public IEnumerable <IndexConflictEntry> GetConflictsFor(Transaction tx, TransactionOperationContext context, string name, int start, int take)
        {
            int taken   = 0;
            int skipped = 0;
            var table   = tx.OpenTable(ConflictsTableSchema, SchemaNameConstants.ConflictMetadataTable);

            Debug.Assert(table != null);

            Slice nameSlice;

            using (DocumentKeyWorker.GetSliceFromKey(context, name, out nameSlice))
            {
                foreach (var seekResult in table.SeekForwardFrom(ConflictsTableSchema.Indexes[NameAndEtagIndexName], nameSlice, true))
                {
                    foreach (var tvr in seekResult.Results)
                    {
                        if (start > skipped)
                        {
                            skipped++;
                            continue;
                        }

                        if (taken++ >= take)
                        {
                            yield break;
                        }

                        yield return(TableValueToConflict(tvr, context));
                    }
                }
            }
        }
        public IReadOnlyList <ChangeVectorEntry[]> DeleteConflictsFor(Transaction tx, TransactionOperationContext context, string name)
        {
            Slice nameSlice;

            using (DocumentKeyWorker.GetSliceFromKey(context, name, out nameSlice))
                return(DeleteConflictsFor(tx, nameSlice));
        }
        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 }
                    });
                }
            }
        }
        public IndexEntryMetadata GetIndexMetadataByName <TTransaction>(Transaction tx, TransactionOperationContext <TTransaction> context, string name, bool returnNullIfTombstone = true)
            where TTransaction : RavenTransaction
        {
            var table = tx.OpenTable(IndexesTableSchema, SchemaNameConstants.IndexMetadataTable);

            Debug.Assert(table != null);

            Slice            nameAsSlice;
            TableValueReader tvr;

            using (DocumentKeyWorker.GetSliceFromKey(context, name, out nameAsSlice))
                tvr = table.ReadByKey(nameAsSlice);

            return(tvr == null ? null : TableValueToMetadata(tvr, context, returnNullIfTombstone));
        }
        public bool TrySetConflictedByName(TransactionOperationContext context, Transaction tx, string name)
        {
            var table = tx.OpenTable(IndexesTableSchema, SchemaNameConstants.IndexMetadataTable);

            Debug.Assert(table != null);

            TableValueReader tvr;
            Slice            nameAsSlice;

            using (DocumentKeyWorker.GetSliceFromKey(context, name, out nameAsSlice))
                tvr = table.ReadByKey(nameAsSlice);

            if (tvr == null)
            {
                return(false);
            }

            var metadata = TableValueToMetadata(tvr, context, false);

            WriteEntry(tx, name, metadata.Type, metadata.Id, context, isConflicted: true, allowOverwrite: true);

            return(true);
        }
        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);
        }