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);
        }