docs: def _RunInTransaction(self, function, readonly=False):
      """Runs function within a transaction.
  
      Allocates a connection, begins a transaction on it and passes the connection
      to function.
  
      If function finishes without raising, the transaction is committed.
  
      If function raises, the transaction will be rolled back, if a retryable
      database error is raised, the operation may be repeated.
  
      Args:
        function: A function to be run, must accept a single MySQLdb.connection
          parameter.
        readonly: Indicates that only a readonly (snapshot) transaction is
          required.
  
      Returns:
        The value returned by the last call to function.
  
      Raises: Any exception raised by function.
      """
      start_query = "START TRANSACTION;"
      if readonly:
        start_query = "START TRANSACTION WITH CONSISTENT SNAPSHOT, READ ONLY;"
  
      for retry_count in range(_MAX_RETRY_COUNT):
        with contextlib.closing(self.pool.get()) as connection:
          try:
            with contextlib.closing(connection.cursor()) as cursor:
              cursor.execute(start_query)
  
            ret = function(connection)
  
            if not readonly:
              connection.commit()
            return ret
          except MySQLdb.OperationalError as e:
            connection.rollback()
            # Re-raise if this was the last attempt.
            if retry_count >= _MAX_RETRY_COUNT or not _IsRetryable(e):
              raise
        # Simple delay, with jitter.
        #
        # TODO(user): Move to something more elegant, e.g. integrate a
        # general retry or backoff library.
        time.sleep(random.uniform(1.0, 2.0) * math.pow(1.5, retry_count))
      # Shouldn't happen, because we should have re-raised whatever caused the
      # last try to fail.
      raise Exception("Looped ended early - last exception swallowed.")