@gen.engine
  def CheckViewpoint(self, viewpoint, callback):
    # Don't check viewpoints that were modified within last hour, as operation might still be in progress.
    if _TEST_MODE or viewpoint.last_updated <= time.time() - _CHECK_THRESHOLD_TIMESPAN:
      logging.info('Processing viewpoint "%s"...' % viewpoint.viewpoint_id)
      self._current_viewpoint = viewpoint.viewpoint_id
      self._num_visited_viewpoints += 1

      # Gather followers.
      query_func = partial(Viewpoint.QueryFollowerIds, self._client, viewpoint.viewpoint_id)
      follower_ids = yield gen.Task(self._CacheQuery, query_func)
      followers = yield [gen.Task(Follower.Query, self._client, f_id, viewpoint.viewpoint_id, None)
                         for f_id in follower_ids]

      # Gather activities.
      # _RepairBadCoverPhoto() depends on the order of activities produced by this query.  If it
      #   changes, _RepairBadCoverPhoto() needs to be modified to compensate.
      query_func = partial(Activity.RangeQuery, self._client, viewpoint.viewpoint_id,
                           range_desc=None, col_names=None)
      activities = yield gen.Task(self._CacheQuery, query_func)

      # Gather episodes and photos.
      query_func = partial(Viewpoint.QueryEpisodes, self._client, viewpoint.viewpoint_id)
      episodes = yield gen.Task(self._CacheQuery, query_func)
      ep_photos_list = []
      for episode in episodes:
        query_func = partial(Post.RangeQuery, self._client, episode.episode_id,
                             range_desc=None, col_names=None)
        posts = yield gen.Task(self._CacheQuery, query_func)
        photos = yield [gen.Task(Photo.Query, self._client, post.photo_id, col_names=None) for post in posts]

        user_posts = None
        if viewpoint.IsDefault():
          # Only query user_post entries if this is a default viewpoint.
          user_posts = yield [gen.Task(UserPost.Query, self._client, episode.user_id,
                                       Post.ConstructPostId(post.episode_id, post.photo_id),
                                       None, must_exist=False) for post in posts]

        ep_photos_list.append((episode, photos, posts, user_posts))
        if (len(ep_photos_list) % 100) == 0:
          logging.info('  caching photos from %d+ episode records...' % len(ep_photos_list))

      # Gather comments.
      query_func = partial(Comment.RangeQuery, self._client, viewpoint.viewpoint_id,
                           range_desc=None, col_names=None)
      comments = yield gen.Task(self._CacheQuery, query_func)

      # Gather accounting entries for this viewpoint.
      query_func = partial(Accounting.RangeQuery, self._client,
                           '%s:%s' % (Accounting.VIEWPOINT_SIZE, viewpoint.viewpoint_id),
                           range_desc=None, col_names=None)
      accounting = yield gen.Task(self._CacheQuery, query_func)

      if viewpoint.IsDefault():
        # Default viewpoint has a viewpoint-level OWNED_BY accounting entry matching exactly
        # the user-level OWNED_BY entry for the viewpoint owner. Look it up now.
        user_accounting = yield gen.Task(Accounting.Query, self._client,
                                         '%s:%d' % (Accounting.USER_SIZE, viewpoint.user_id),
                                         Accounting.OWNED_BY, None, must_exist=False)
        if user_accounting is not None:
          # Add it to the accounting list. It will be automatically checked in CheckBadViewpointAccounting.
          accounting.append(user_accounting)
      else:
        # Set each follower id in visited_users. We only do this for shared viewpoint as the per-user
        # actions do not process default viewpoint accounting.
        for f_id in follower_ids:
          self._visited_users[f_id] = viewpoint.viewpoint_id

      refreshed_viewpoint = yield gen.Task(Viewpoint.Query, self._client, viewpoint.viewpoint_id, None)
      # TODO(marc): check if other fields have changed?

      # Now that assets have been gathered, check to see if viewpoint was modified during the gathering phase.
      if _TEST_MODE or refreshed_viewpoint.last_updated <= time.time() - _CHECK_THRESHOLD_TIMESPAN:
        # Check for invalid viewpoint metadata.
        yield gen.Task(self._CheckInvalidViewpointMetadata, viewpoint, activities)

        # Check for multiple share_new activities.
        yield gen.Task(self._CheckMultipleShareNew, viewpoint, activities)

        # Check for missing activities.
        yield gen.Task(self._CheckMissingActivities, viewpoint, activities, followers, ep_photos_list, comments)

        # Check for missing posts referenced by activities.
        yield gen.Task(self._CheckMissingPosts, viewpoint, activities, ep_photos_list)

        # Check for any missing Followed records.
        yield gen.Task(self._CheckMissingFollowed, viewpoint, followers)

        # Check for empty viewpoint.
        yield gen.Task(self._CheckEmptyViewpoint, viewpoint, activities, followers, ep_photos_list, comments)

        # Check for missing/bad accounting entries.
        yield gen.Task(self._CheckBadViewpointAccounting, viewpoint, ep_photos_list, accounting)

        if not viewpoint.IsDefault():
          # Check for valid cover_photo.
          yield gen.Task(self._CheckBadCoverPhoto, viewpoint, ep_photos_list, activities)
      else:
        logging.info('Aborting viewpoint "%s" check because it was modified while gathering its assets...',
                     viewpoint.viewpoint_id)
    else:
      logging.info('Skipping viewpoint "%s" because it was modified in the last hour...', viewpoint.viewpoint_id)

    # Check users in visited_users if it has grown big enough.
    self._current_viewpoint = ''
    yield gen.Task(self._MaybeCheckVisitedUsers)
    callback()
Returns the SQL for committing the given savepoint.
dataset/ETHPy150Open viewfinderco/viewfinder/backend/db/tools/dbchk.py/DatabaseChecker.CheckViewpoint--crossover with--dataset/ETHPy150Open AppScale/appscale/AppServer/lib/django-1.2/django/db/backends/__init__.py/BaseDatabaseOperations.savepoint_commit_sql