def init_cursor(self): """Position the cursor appropriately. The cursor is set to either the beginning of the oplog, or wherever it was last left off. Returns the cursor and the number of documents left in the cursor. """ timestamp = self.read_last_checkpoint() if timestamp is None: if self.collection_dump: # dump collection and update checkpoint timestamp = self.dump_collection() if timestamp is None: return None, 0 else: # Collection dump disabled: # return cursor to beginning of oplog. cursor = self.get_oplog_cursor() self.checkpoint = self.get_last_oplog_timestamp() self.update_checkpoint() return cursor, retry_until_ok(cursor.count) self.checkpoint = timestamp self.update_checkpoint() for i in range(60): cursor = self.get_oplog_cursor(timestamp) cursor_len = retry_until_ok(cursor.count) if cursor_len == 0: # rollback, update checkpoint, and retry LOG.debug("OplogThread: Initiating rollback from " "get_oplog_cursor") self.checkpoint = self.rollback() self.update_checkpoint() return self.init_cursor() # try to get the first oplog entry try: first_oplog_entry = retry_until_ok(next, cursor) except StopIteration: # It's possible for the cursor to become invalid # between the cursor.count() call and now time.sleep(1) continue # first entry should be last oplog entry processed cursor_ts_long = util.bson_ts_to_long( first_oplog_entry.get("ts")) given_ts_long = util.bson_ts_to_long(timestamp) if cursor_ts_long > given_ts_long: # first entry in oplog is beyond timestamp # we've fallen behind return None, 0 # first entry has been consumed return cursor, cursor_len - 1 else: raise errors.MongoConnectorError( "Could not initialize oplog cursor.")
def init_cursor(self): """Position the cursor appropriately. The cursor is set to either the beginning of the oplog, or wherever it was last left off. Returns the cursor and True if the cursor is empty. """ timestamp = self.read_last_checkpoint() if timestamp is None: if self.collection_dump: # dump collection and update checkpoint timestamp = self.dump_collection() if timestamp is None: return None, True else: # Collection dump disabled: # return cursor to beginning of oplog. cursor = self.get_oplog_cursor() self.checkpoint = self.get_last_oplog_timestamp() self.update_checkpoint() return cursor, retry_until_ok(self._cursor_empty, cursor) self.checkpoint = timestamp self.update_checkpoint() for i in range(60): cursor = self.get_oplog_cursor(timestamp) cursor_empty = retry_until_ok(self._cursor_empty, cursor) if cursor_empty: # rollback, update checkpoint, and retry LOG.debug("OplogThread: Initiating rollback from " "get_oplog_cursor") self.checkpoint = self.rollback() self.update_checkpoint() return self.init_cursor() # try to get the first oplog entry try: first_oplog_entry = retry_until_ok(next, cursor) except StopIteration: # It's possible for the cursor to become invalid # between the next(cursor) call and now time.sleep(1) continue oldest_ts_long = util.bson_ts_to_long( self.get_oldest_oplog_timestamp()) checkpoint_ts_long = util.bson_ts_to_long(timestamp) if checkpoint_ts_long < oldest_ts_long: # We've fallen behind, the checkpoint has fallen off the oplog return None, True cursor_ts_long = util.bson_ts_to_long(first_oplog_entry["ts"]) if cursor_ts_long > checkpoint_ts_long: # The checkpoint is not present in this oplog and the oplog # did not rollover. This means that we connected to a new # primary which did not replicate the checkpoint and which has # new changes in its oplog for us to process. # rollback, update checkpoint, and retry LOG.debug("OplogThread: Initiating rollback from " "get_oplog_cursor: new oplog entries found but " "checkpoint is not present") self.checkpoint = self.rollback() self.update_checkpoint() return self.init_cursor() # first entry has been consumed return cursor, cursor_empty else: raise errors.MongoConnectorError( "Could not initialize oplog cursor.")