def validate_commit_req(self, req): """Validates a normalized CommitRequest. Args: req: a googledatastore.CommitRequest Raises: ValidationError: if the request is invalid """ _assert_initialized(req) if (req.mode == googledatastore.CommitRequest.MODE_UNSPECIFIED or req.mode == googledatastore.CommitRequest.TRANSACTIONAL): _assert_condition(req.WhichOneof('transaction_selector'), 'Transactional commit requires a transaction.') if req.WhichOneof('transaction_selector') == 'transaction': _assert_condition( req.transaction, 'a transaction cannot be the empty ' 'string.') seen_base_versions = {} for mutation in req.mutations: v1_key, _ = datastore_pbs.get_v1_mutation_key_and_entity( mutation) if datastore_pbs.is_complete_v1_key(v1_key): mutation_base_version = None if mutation.HasField('base_version'): mutation_base_version = mutation.base_version key = datastore_types.ReferenceToKeyValue( v1_key, self.__id_resolver) if key in seen_base_versions: _assert_condition( seen_base_versions[key] == mutation_base_version, 'Mutations for the same entity must have the ' 'same base version.') seen_base_versions[key] = mutation_base_version elif req.mode == googledatastore.CommitRequest.NON_TRANSACTIONAL: _assert_condition( not req.WhichOneof('transaction_selector'), 'Non-transactional commit cannot specify a ' 'transaction.') seen_complete_keys = set() for mutation in req.mutations: v1_key, _ = datastore_pbs.get_v1_mutation_key_and_entity( mutation) if datastore_pbs.is_complete_v1_key(v1_key): key = datastore_types.ReferenceToKeyValue( v1_key, self.__id_resolver) _assert_condition( key not in seen_complete_keys, 'A non-transactional commit may not contain ' 'multiple mutations affecting the same entity.') seen_complete_keys.add(key) for mutation in req.mutations: self.__validate_mutation(mutation)
def _GetEntitiesInEntityGroup(self, entity_group): query = datastore_pb.Query() query.set_app(entity_group.app()) if entity_group.name_space(): query.set_name_space(entity_group.name_space()) query.mutable_ancestor().CopyFrom(entity_group) filter_info = self.__GenerateFilterInfo(query.filter_list(), query) order_info = self.__GenerateOrderInfo(query.order_list()) sql_stmt, params = self.__KindQuery(query, filter_info, order_info) conn = self._GetConnection() try: db_cursor = conn.execute(sql_stmt, params) entities = {} for row in db_cursor.fetchall(): entity = entity_pb.EntityProto(row[1]) key = datastore_types.ReferenceToKeyValue(entity.key()) entities[key] = datastore_stub_util._FromStorageEntity(entity) return entities finally: self._ReleaseConnection(conn)
def _GetEntitiesInEntityGroup(self, entity_group): connection = self._GetConnection() if isinstance(entity_group, entity_pb.Reference): req = googledatastore.LookupRequest() v1_key = req.key.add() converter.v3_entity_ref_to_v1_key(entity_group, v1_key) v1_key.partition_id.Clear() resp = connection.lookup(req) if resp.found: v3_entities = [] for v1_entity_result in resp.found: v3_entity = entity_pb.EntityProto() converter.v1_to_v3_entity(v1_entity_result.entity, v3_entity) v3_entity.mutable_key().set_app(entity_group.app()) v3_entity.mutable_key().set_name_space(entity_group.name_space()) v3_entities.append(v3_entity) return dict((datastore_types.ReferenceToKeyValue(entity.key()), entity) for entity in v3_entities) return {}
def __apply_v1_mutation(self, v1_mutation, base_version, v1_txn, version_cache): """Applies a v1 Mutation in a transaction. Args: v1_mutation: a googledatastore.Mutation, must be for a complete key. base_version: optional, the version the entity is expected to be at. If the entity has a different version number, the mutation does not apply. If None, then this check is skipped. v1_txn: a v1 transaction handle version_cache: a cache of entity keys to version, for entities that have been mutated previously in this transaction. """ v1_key, v1_entity = datastore_pbs.get_v1_mutation_key_and_entity( v1_mutation) key = datastore_types.ReferenceToKeyValue(v1_key, self._id_resolver) if (v1_mutation.HasField('insert') or v1_mutation.HasField('update') or base_version is not None) and key not in version_cache: version_cache[key] = self.__get_v1_entity_version(v1_key, v1_txn) if v1_mutation.HasField('insert'): if base_version is not None and base_version != _NO_VERSION: raise apiproxy_errors.ApplicationError(datastore_pb.Error.BAD_REQUEST, 'Cannot insert an entity with a ' 'base version greater than zero') elif version_cache[key] != _NO_VERSION: raise apiproxy_errors.ApplicationError(datastore_pb.Error.BAD_REQUEST, 'Entity already exists.') elif v1_mutation.HasField('update'): if base_version is not None and base_version == _NO_VERSION: raise apiproxy_errors.ApplicationError(datastore_pb.Error.BAD_REQUEST, 'Cannot update an entity with a ' 'base version set to zero') elif version_cache[key] == _NO_VERSION: raise apiproxy_errors.ApplicationError(datastore_pb.Error.BAD_REQUEST, 'Entity does not exist.') if base_version is not None: persisted_version = version_cache[key] if persisted_version != _NO_VERSION and persisted_version < base_version: raise apiproxy_errors.ApplicationError(datastore_pb.Error.BAD_REQUEST, 'Invalid base version, it is ' 'greater than the stored ' 'version') if persisted_version != base_version: return persisted_version if v1_mutation.HasField('delete'): self.__delete_v1_key(v1_key, v1_txn) version_cache[key] = _NO_VERSION else: self.__put_v1_entity(v1_entity, v1_txn) version_cache[key] = _MINIMUM_VERSION
def _GetEntityLocation(self, key): """Get keys to self.__entities_by_* from the given key. Example usage: app_kind, eg_k, k = self._GetEntityLocation(key) self.__entities_by_kind[app_kind][k] self.__entities_by_entity_group[eg_k][k] Args: key: entity_pb.Reference Returns: Tuple (by_kind key, by_entity_group key, entity key) """ app_ns = datastore_types.EncodeAppIdNamespace(key.app(), key.name_space()) kind = key.path().element_list()[-1].type() entity_group = datastore_stub_util._GetEntityGroup(key) eg_k = datastore_types.ReferenceToKeyValue(entity_group) k = datastore_types.ReferenceToKeyValue(key) return ((app_ns, kind), eg_k, k)
def _GetEntitiesInEntityGroup(self, entity_group): eg_k = datastore_types.ReferenceToKeyValue(entity_group) return self.__entities_by_group[eg_k].copy()
def _GetEntitiesInEntityGroup(self, entity_group): eg_k = datastore_types.ReferenceToKeyValue(entity_group) return dict((k, e.record) for (k, e) in self.__entities_by_group[eg_k].iteritems())
def __commit(self, v1_mutations, v1_txn, resp): """Commits a list of v1 mutations. Args: v1_mutations: the list of mutations to apply and commit v1_txn: required v1 transaction handle in which to apply the mutations resp: a v1 CommitResponse to update with the result of this commit """ mutation_keys = [] seen_keys = set() allocated_keys = {} conflict_cache = {} version_cache = {} for i, mutation in enumerate(v1_mutations): v1_key, v1_entity = datastore_pbs.get_v1_mutation_key_and_entity(mutation) key = datastore_types.ReferenceToKeyValue(v1_key, self._id_resolver) if not datastore_pbs.is_complete_v1_key(v1_key): v1_key = self.__put_v1_entity(v1_entity, v1_txn) key = datastore_types.ReferenceToKeyValue(v1_key, self._id_resolver) allocated_keys[key] = v1_key elif key not in conflict_cache: base_version = None if mutation.HasField('base_version') and key not in seen_keys: base_version = mutation.base_version conflict_version = self.__apply_v1_mutation(mutation, base_version, v1_txn, version_cache) if conflict_version is not None: conflict_cache[key] = conflict_version mutation_keys.append(key) seen_keys.add(key) v3_txn = datastore_pb.Transaction() self.__service_converter.v1_to_v3_txn(v1_txn, v3_txn) v3_resp = datastore_pb.CommitResponse() self.__make_v3_call('Commit', v3_txn, v3_resp) resp.index_updates = v3_resp.cost().index_writes() mutation_versions = {} for version in v3_resp.version_list(): key = datastore_types.ReferenceToKeyValue(version.root_entity_key()) mutation_versions[key] = version.version() for key in mutation_keys: mutation_result = resp.mutation_results.add() if key in allocated_keys: mutation_result.key.CopyFrom(allocated_keys[key]) if key in conflict_cache: mutation_result.conflict_detected = True mutation_result.version = conflict_cache[key] else: mutation_result.version = mutation_versions[key]