예제 #1
0
def _save_coverage_information(context, result):
    """Saves coverage information in datastore using an atomic transaction."""

    # Use ndb.transaction with retries below to mitigate risk of a race condition.
    def _try_save_coverage_information():
        """Implements save_coverage_information function."""
        coverage_info = data_handler.get_coverage_information(
            context.fuzz_target.project_qualified_name(),
            result.coverage_info.date,
            create_if_needed=True)

        # Intentionally skip edge and function coverage values as those would come
        # from fuzzer coverage cron task (see src/go/server/cron/coverage.go).
        coverage_info.corpus_size_units = result.coverage_info.corpus_size_units
        coverage_info.corpus_size_bytes = result.coverage_info.corpus_size_bytes
        coverage_info.corpus_location = result.coverage_info.corpus_location
        coverage_info.corpus_backup_location = (
            result.coverage_info.corpus_backup_location)
        coverage_info.quarantine_size_units = (
            result.coverage_info.quarantine_size_units)
        coverage_info.quarantine_size_bytes = (
            result.coverage_info.quarantine_size_bytes)
        coverage_info.quarantine_location = result.coverage_info.quarantine_location
        coverage_info.put()

    try:
        ndb.transaction(_try_save_coverage_information,
                        retries=data_handler.DEFAULT_FAIL_RETRIES)
    except Exception as e:
        raise CorpusPruningException(
            'Failed to save corpus pruning result: %s.' % repr(e))
예제 #2
0
async def set_email(content: APIKeyEmail, response: Response):
    def update_email(api_key: str, email: str, response: Response):
        email_obj = ndb.Key("UserEmail", api_key).get()
        if email_obj is None:
            email_obj = UserEmail(id=api_key, email=email)
            response.status_code = status.HTTP_201_CREATED
        else:
            email_obj.email = email
            response.status_code = status.HTTP_200_OK

        email_obj.put()

    client = ndb.Client()
    with client.context():
        ndb.transaction(lambda: update_email(
            content.api_key, content.email, response))
예제 #3
0
def test_delete_entity_in_transaction(ds_entity):
    entity_id = test_utils.system.unique_resource_id()
    ds_entity(KIND, entity_id, foo=42)

    class SomeKind(ndb.Model):
        foo = ndb.IntegerProperty()

    key = ndb.Key(KIND, entity_id)
    assert key.get().foo == 42

    def delete_entity():
        assert key.delete() is None
        assert key.get().foo == 42  # not deleted until commit

    ndb.transaction(delete_entity)
    assert key.get() is None
예제 #4
0
def test_delete_entity_in_transaction_then_rollback(ds_entity):
    entity_id = test_utils.system.unique_resource_id()
    ds_entity(KIND, entity_id, foo=42)

    class SomeKind(ndb.Model):
        foo = ndb.IntegerProperty()

    key = ndb.Key(KIND, entity_id)
    assert key.get().foo == 42

    def delete_entity():
        assert key.delete() is None
        raise Exception("Spurious error")

    with pytest.raises(Exception):
        ndb.transaction(delete_entity)

    assert key.get().foo == 42
예제 #5
0
def test_delete_entity_in_transaction_with_global_cache(
        client_context, ds_entity):
    """Regression test for #426

    https://github.com/googleapis/python-ndb/issues/426
    """
    class SomeKind(ndb.Model):
        foo = ndb.IntegerProperty()

    entity_id = test_utils.system.unique_resource_id()
    ds_entity(KIND, entity_id, foo=42)

    global_cache = global_cache_module._InProcessGlobalCache()
    with client_context.new(global_cache=global_cache).use():
        key = ndb.Key(KIND, entity_id)
        assert key.get().foo == 42

        ndb.transaction(key.delete)
        assert key.get() is None
예제 #6
0
def test_insert_entity_in_transaction_without_preallocating_id(dispose_of):
    class SomeKind(ndb.Model):
        foo = ndb.IntegerProperty()
        bar = ndb.StringProperty()

    def save_entity():
        # By not waiting on the Future, we don't force a call to AllocateIds
        # before the transaction is committed.
        SomeKind(foo=42, bar="none").put_async()

    ndb.transaction(save_entity)

    query = SomeKind.query()
    eventually(query.fetch, length_equals(1))
    retrieved = query.fetch()[0]
    dispose_of(retrieved._key._key)

    assert retrieved.foo == 42
    assert retrieved.bar == "none"
예제 #7
0
def acquire_lock(key_name,
                 max_hold_seconds=DEFAULT_MAX_HOLD_SECONDS,
                 retries=None,
                 by_zone=True):
    """Acquire a lock for the given key name. Returns the expiration time if
  succeeded, otherwise None. The lock holder is responsible for making sure it
  doesn't assume the lock is still held after the expiration time."""
    logs.log('Acquiring lock for %s.' % key_name)
    failed_acquires = 0
    total_wait = 0
    wait_exponent = 1

    if by_zone:
        key_name_with_zone = _get_key_name_with_lock_zone(key_name)
        if key_name_with_zone is None:
            logs.log_error('Failed to get zone while trying to lock %s.' %
                           key_name)
            return None

        key_name = key_name_with_zone

    bot_name = environment.get_value('BOT_NAME')
    expiration_delta = datetime.timedelta(seconds=max_hold_seconds)
    while total_wait < LOCK_CHECK_TIMEOUT:
        try:
            lock_entity = ndb.transaction(lambda: _try_acquire_lock(
                key_name,
                expiration_time=datetime.datetime.utcnow() + expiration_delta,
                holder=bot_name),
                                          retries=TRANSACTION_RETRIES)

            if lock_entity.holder == bot_name:
                logs.log('Got the lock.')
                return lock_entity.expiration_time
        except exceptions.Error:
            pass

        failed_acquires += 1
        if retries and retries >= failed_acquires:
            logs.log('Failed to acquire lock, exceeded max retries.')
            return None

        logs.log('Failed to acquire lock, waiting...')

        # Exponential backoff.
        max_sleep = (1 << wait_exponent) * LOCK_CHECK_SLEEP_MULTIPLIER
        sleep_time = random.uniform(1.0, max_sleep)
        time.sleep(sleep_time)

        total_wait += sleep_time
        wait_exponent = min(wait_exponent + 1, MAX_WAIT_EXPONENT)

    logs.log('Timeout exceeded while trying to acquire lock, bailing.')
    return None
예제 #8
0
def test_get_or_insert_get_in_transaction(ds_entity):
    class SomeKind(ndb.Model):
        foo = ndb.IntegerProperty()

    name = "Inigo Montoya"
    assert SomeKind.get_by_id(name) is None

    def do_the_thing():
        ds_entity(KIND, name, foo=42)
        return SomeKind.get_or_insert(name, foo=21)

    entity = ndb.transaction(do_the_thing)
    assert entity.foo == 42
예제 #9
0
def test_insert_entity_in_transaction(dispose_of):
    class SomeKind(ndb.Model):
        foo = ndb.IntegerProperty()
        bar = ndb.StringProperty()

    def save_entity():
        entity = SomeKind(foo=42, bar="none")
        key = entity.put()
        dispose_of(key._key)
        return key

    key = ndb.transaction(save_entity)
    retrieved = key.get()
    assert retrieved.foo == 42
    assert retrieved.bar == "none"
예제 #10
0
def test_insert_entity_in_transaction(dispose_of):
    commit_callback = mock.Mock()

    class SomeKind(ndb.Model):
        foo = ndb.IntegerProperty()
        bar = ndb.StringProperty()

    def save_entity():
        ndb.get_context().call_on_commit(commit_callback)
        entity = SomeKind(foo=42, bar="none")
        key = entity.put()
        dispose_of(key._key)
        return key

    key = ndb.transaction(save_entity)
    retrieved = key.get()
    assert retrieved.foo == 42
    assert retrieved.bar == "none"
    commit_callback.assert_called_once_with()
예제 #11
0
def test_update_entity_in_transaction(ds_entity):
    entity_id = test_utils.system.unique_resource_id()
    ds_entity(KIND, entity_id, foo=42, bar="none")

    class SomeKind(ndb.Model):
        foo = ndb.IntegerProperty()
        bar = ndb.StringProperty()

    def update_entity():
        key = ndb.Key(KIND, entity_id)
        entity = key.get()
        entity.foo = 56
        entity.bar = "high"
        assert entity.put() == key
        return key

    key = ndb.transaction(update_entity)
    retrieved = key.get()
    assert retrieved.foo == 56
    assert retrieved.bar == "high"
예제 #12
0
def claim_token_with_tx():
    """Claim a token and record the action, using a transaction.

    Because this function uses a datastore transaction, it can handle many
    concurrent requests claiming the same token, but ensure the token is
    issued to no more than 1 request.
    """
    client = ndb.Client()
    path = '/token-with-tx'
    request_id = new_request_id()
    token_id = next_token_id()

    with client.context():
        # This uses an inner function so that we can capture the function call
        # arguments from the calling scope.
        def _inner():
            return get_or_insert(token_id, request_id, path)

        token_obj, new_claim = ndb.transaction(_inner)
        token = token_obj.to_dict()

    return {'token': token, 'new_claim': new_claim}