private void ThrowIfAlreadyExistsAndOverwriting( string indexName, IndexEntryType type, int indexIndexId, Table table, Slice indexNameAsSlice, IndexEntryMetadata existing) { if (!table.VerifyKeyExists(indexNameAsSlice) || indexIndexId == -1 || existing == null || existing.Id == -1) { if (Logger.IsInfoEnabled && indexIndexId != -1 && existing != null && existing.Id == -1 && existing.Type != type) { Logger.Info($"Writing {type}, and there is a tombstone of {existing.Type} under the same name. The created {type} will have take the change vector from the tombstone."); } return; } string msg; switch (type) { case IndexEntryType.Index: msg = $"Tried to create an index with a name of {indexName}, but an index or a transformer under the same name exist"; break; case IndexEntryType.Transformer: msg = $"Tried to create an transformer with a name of {indexName}, but an index or a transformer under the same name exist"; break; default: throw new ArgumentOutOfRangeException(nameof(type), $"Unknown index/transformer type. For the record, I've got {(int)type}.."); } throw new IndexOrTransformerAlreadyExistException(msg); }
private IndexEntryMetadata TableValueToMetadata(TableValueReader tvr, JsonOperationContext context, bool returnNullIfTombstone) { var metadata = new IndexEntryMetadata(); int size; metadata.Id = Bits.SwapBytes(*(int *)tvr.Read((int)MetadataFields.Id, out size)); if (returnNullIfTombstone && metadata.Id == -1) { return(null); } metadata.Name = new LazyStringValue(null, tvr.Read((int)MetadataFields.Name, out size), size, context).ToString(); metadata.ChangeVector = ReplicationUtils.GetChangeVectorEntriesFromTableValueReader(tvr, (int)MetadataFields.ChangeVector); metadata.Type = (IndexEntryType)(*tvr.Read((int)MetadataFields.Type, out size)); metadata.Etag = Bits.SwapBytes(*(long *)tvr.Read((int)MetadataFields.Etag, out size)); metadata.IsConflicted = *(bool *)tvr.Read((int)MetadataFields.IsConflicted, out size); return(metadata); }
private long WriteEntry(Transaction tx, string indexName, IndexEntryType type, int indexIndexId, TransactionOperationContext context, bool isConflicted = false, bool allowOverwrite = false, ChangeVectorEntry[] changeVector = null) { var table = tx.OpenTable(IndexesTableSchema, SchemaNameConstants.IndexMetadataTable); Debug.Assert(table != null); var newEtag = GetNewEtag(table); Slice nameAsSlice; IndexEntryMetadata existing = null; ChangeVectorEntry[] changeVectorForWrite; using (DocumentKeyWorker.GetSliceFromKey(context, indexName, out nameAsSlice)) { var tvr = table.ReadByKey(nameAsSlice); //SetIndexTransformerChangeVectorForLocalChange also merges vectors if conflicts exist changeVectorForWrite = SetIndexTransformerChangeVectorForLocalChange(tx, context, nameAsSlice, tvr, newEtag, changeVector); if (tvr != null) { existing = TableValueToMetadata(tvr, context, false); } } //precautions if (changeVectorForWrite == null) { throw new ArgumentException("changeVector == null, should not be so"); } Slice indexNameAsSlice; using (DocumentKeyWorker.GetSliceFromKey(context, indexName, out indexNameAsSlice)) { if (!allowOverwrite) { ThrowIfAlreadyExistsAndOverwriting(indexName, type, indexIndexId, table, indexNameAsSlice, existing); } fixed(ChangeVectorEntry *pChangeVector = changeVectorForWrite) { var bitSwappedEtag = Bits.SwapBytes(newEtag); var bitSwappedId = Bits.SwapBytes(indexIndexId); table.Set(new TableValueBuilder { { (byte *)&bitSwappedId, sizeof(int) }, { (byte *)&bitSwappedEtag, sizeof(long) }, indexNameAsSlice, { (byte *)&type, sizeof(byte) }, { (byte *)pChangeVector, sizeof(ChangeVectorEntry) * changeVectorForWrite.Length }, { (byte *)&isConflicted, sizeof(bool) } }); } } MergeEntryVectorWithGlobal(tx, context.Allocator, changeVectorForWrite); return(newEtag); }