public void AddConflict(TransactionOperationContext context, Transaction tx, string name, IndexEntryType type, ChangeVectorEntry[] changeVector, BlittableJsonReaderObject definition) { if (!TrySetConflictedByName(context, tx, name)) { throw new InvalidOperationException($"When trying to add a conflict on {type} {name}, we couldn't find {name} in the index metadata. Shouldn't happen and likely a bug."); } var conflictsTable = tx.OpenTable(ConflictsTableSchema, SchemaNameConstants.ConflictMetadataTable); var metadataTable = tx.OpenTable(IndexesTableSchema, SchemaNameConstants.IndexMetadataTable); Slice indexNameAsSlice; var newEtag = GetNewEtag(metadataTable); var bitSwappedEtag = Bits.SwapBytes(newEtag); using (DocumentKeyWorker.GetSliceFromKey(context, name, out indexNameAsSlice)) { fixed(ChangeVectorEntry *pChangeVector = changeVector) { byte byteAsType = (byte)type; conflictsTable.Set(new TableValueBuilder { indexNameAsSlice, {&bitSwappedEtag, sizeof(long) }, {&byteAsType, sizeof(byte) }, { (byte *)pChangeVector, sizeof(ChangeVectorEntry) * changeVector.Length }, { definition.BasePointer, definition.Size } }); } } }
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 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); }