public void DeleteRevisionsFor(DocumentsOperationContext context, string id)
        {
            using (DocumentIdWorker.GetSliceFromId(context, id, out Slice lowerId))
                using (GetKeyPrefix(context, lowerId, out Slice prefixSlice))
                {
                    var collectionName = GetCollectionFor(context, prefixSlice);
                    if (collectionName == null)
                    {
                        if (_logger.IsInfoEnabled)
                        {
                            _logger.Info($"Tried to delete all revisions for '{id}' but no revisions found.");
                        }
                        return;
                    }

                    var table        = EnsureRevisionTableCreated(context.Transaction.InnerTransaction, collectionName);
                    var newEtag      = _documentsStorage.GenerateNextEtag();
                    var changeVector = _documentsStorage.GetNewChangeVector(context, newEtag);
                    context.LastDatabaseChangeVector = changeVector;
                    var lastModifiedTicks = _database.Time.GetUtcNow().Ticks;
                    DeleteRevisions(context, table, prefixSlice, collectionName, long.MaxValue, null, changeVector, lastModifiedTicks);
                    DeleteCountOfRevisions(context, prefixSlice);
                }
        }
 public override void HandleDelete(Tombstone tombstone, string collection, Lazy <IndexWriteOperation> writer, TransactionOperationContext indexContext, IndexingStatsScope stats)
 {
     using (DocumentIdWorker.GetSliceFromId(indexContext, tombstone.LowerId, out Slice documentIdPrefixWithTsKeySeparator, SpecialChars.RecordSeparator))
         _referencesStorage.RemoveReferencesByPrefix(documentIdPrefixWithTsKeySeparator, collection, null, indexContext.Transaction);
 }
Esempio n. 3
0
            public override int Execute(DocumentsOperationContext context)
            {
                if (Database.ServerStore.Configuration.Core.FeaturesAvailability == FeaturesAvailability.Stable)
                {
                    FeaturesAvailabilityException.Throw("Cluster Transactions");
                }
                var global = context.LastDatabaseChangeVector ??
                             (context.LastDatabaseChangeVector = DocumentsStorage.GetDatabaseChangeVector(context));
                var dbGrpId = Database.DatabaseGroupId;
                var current = ChangeVectorUtils.GetEtagById(global, dbGrpId);

                foreach (var command in _batch)
                {
                    Replies.Add(command.Index, new DynamicJsonArray());
                    Reply = Replies[command.Index];

                    var commands = command.Commands;
                    var count    = command.PreviousCount;
                    var options  = Options[command.Index] = command.Options;

                    if (options.WaitForIndexesTimeout != null)
                    {
                        ModifiedCollections = new HashSet <string>();
                    }

                    if (commands != null)
                    {
                        foreach (BlittableJsonReaderObject blittableCommand in commands)
                        {
                            count++;
                            var changeVector = $"RAFT:{count}-{dbGrpId}";

                            var cmd = JsonDeserializationServer.ClusterTransactionDataCommand(blittableCommand);

                            switch (cmd.Type)
                            {
                            case CommandType.PUT:
                                if (current < count)
                                {
                                    // delete the document to avoid exception if we put new document in a different collection.
                                    // TODO: document this behavior
                                    using (DocumentIdWorker.GetSliceFromId(context, cmd.Id, out Slice lowerId))
                                    {
                                        Database.DocumentsStorage.Delete(context, lowerId, cmd.Id, expectedChangeVector: null,
                                                                         nonPersistentFlags: NonPersistentDocumentFlags.SkipRevisionCreation);
                                    }

                                    var putResult = Database.DocumentsStorage.Put(context, cmd.Id, null, cmd.Document.Clone(context), changeVector: changeVector,
                                                                                  flags: DocumentFlags.FromClusterTransaction);
                                    context.DocumentDatabase.HugeDocuments.AddIfDocIsHuge(cmd.Id, cmd.Document.Size);
                                    AddPutResult(putResult);
                                }
                                else
                                {
                                    try
                                    {
                                        var item = Database.DocumentsStorage.GetDocumentOrTombstone(context, cmd.Id);
                                        if (item.Missing)
                                        {
                                            AddPutResult(new DocumentsStorage.PutOperationResults
                                            {
                                                ChangeVector = changeVector,
                                                Id           = cmd.Id,
                                                LastModified = DateTime.UtcNow,
                                                Collection   = Database.DocumentsStorage.ExtractCollectionName(context, cmd.Document)
                                            });
                                            continue;
                                        }
                                        var collection = GetCollection(context, item);
                                        AddPutResult(new DocumentsStorage.PutOperationResults
                                        {
                                            ChangeVector = changeVector,
                                            Id           = cmd.Id,
                                            Flags        = item.Document?.Flags ?? item.Tombstone.Flags,
                                            LastModified = item.Document?.LastModified ?? item.Tombstone.LastModified,
                                            Collection   = collection
                                        });
                                    }
                                    catch (DocumentConflictException)
                                    {
                                        AddPutResult(new DocumentsStorage.PutOperationResults
                                        {
                                            ChangeVector = changeVector,
                                            Id           = cmd.Id,
                                            Collection   = GetFirstConflictCollection(context, cmd)
                                        });
                                    }
                                }

                                break;

                            case CommandType.DELETE:
                                if (current < count)
                                {
                                    using (DocumentIdWorker.GetSliceFromId(context, cmd.Id, out Slice lowerId))
                                    {
                                        var deleteResult = Database.DocumentsStorage.Delete(context, lowerId, cmd.Id, null, changeVector: changeVector,
                                                                                            documentFlags: DocumentFlags.FromClusterTransaction);
                                        AddDeleteResult(deleteResult, cmd.Id);
                                    }
                                }
                                else
                                {
                                    try
                                    {
                                        var item = Database.DocumentsStorage.GetDocumentOrTombstone(context, cmd.Id);
                                        if (item.Missing)
                                        {
                                            AddDeleteResult(new DocumentsStorage.DeleteOperationResult
                                            {
                                                ChangeVector = changeVector,
                                                Collection   = null
                                            }, cmd.Id);
                                            continue;
                                        }
                                        var collection = GetCollection(context, item);
                                        AddDeleteResult(new DocumentsStorage.DeleteOperationResult
                                        {
                                            ChangeVector = changeVector,
                                            Collection   = collection
                                        }, cmd.Id);
                                    }
                                    catch (DocumentConflictException)
                                    {
                                        AddDeleteResult(new DocumentsStorage.DeleteOperationResult
                                        {
                                            ChangeVector = changeVector,
                                            Collection   = GetFirstConflictCollection(context, cmd)
                                        }, cmd.Id);
                                    }
                                }
                                break;

                            default:
                                throw new NotSupportedException($"{cmd.Type} is not supported in {nameof(ClusterTransactionMergedCommand)}.");
                            }
                        }
                    }

                    if (context.LastDatabaseChangeVector == null)
                    {
                        context.LastDatabaseChangeVector = global;
                    }

                    var result = ChangeVectorUtils.TryUpdateChangeVector("RAFT", dbGrpId, count, context.LastDatabaseChangeVector);
                    if (result.IsValid)
                    {
                        context.LastDatabaseChangeVector = result.ChangeVector;
                    }
                }

                return(Reply.Count);
            }
Esempio n. 4
0
        private CollectionName PutCounters(UpdateStep step, DocumentsOperationContext context, HashSet <string> dbIds, Dictionary <string, List <CounterDetail> > allCountersBatch, string docId)
        {
            string collection = null;

            using (DocumentIdWorker.GetSliceFromId(context, docId, out Slice lowerId))
            {
                var docsTable = new Table(DocsSchema, step.ReadTx);
                if (docsTable.ReadByKey(lowerId, out var tvr))
                {
                    using (var doc = new BlittableJsonReaderObject(tvr.Read((int)DocumentsTable.Data, out int size), size, context))
                    {
                        collection = CollectionName.GetCollectionName(doc);
                    }
                }
                else
                {
                    // document does not exist
                    return(null);
                }
            }

            var collectionName = new CollectionName(collection);

            using (DocumentIdWorker.GetSliceFromId(context, docId, out Slice documentKeyPrefix, separator: SpecialChars.RecordSeparator))
            {
                var maxNumberOfCountersPerGroup = Math.Max(32, 2048 / (dbIds.Count * 32 + 1)); // rough estimate
                var orderedKeys = allCountersBatch.OrderBy(x => x.Key).ToList();
                var listOfDbIds = dbIds.ToList();

                for (int i = 0; i < orderedKeys.Count / maxNumberOfCountersPerGroup + (orderedKeys.Count % maxNumberOfCountersPerGroup == 0 ? 0 : 1); i++)
                {
                    var currentBatch = allCountersBatch.Skip(maxNumberOfCountersPerGroup * i).Take(maxNumberOfCountersPerGroup);
                    using (var data = WriteNewCountersDocument(context, listOfDbIds, currentBatch))
                    {
                        var etag         = step.DocumentsStorage.GenerateNextEtag();
                        var changeVector = ChangeVectorUtils.NewChangeVector(
                            step.DocumentsStorage.DocumentDatabase.ServerStore.NodeTag, etag, _dbId);

                        var table = step.DocumentsStorage.CountersStorage.GetCountersTable(step.WriteTx, collectionName);
                        data.TryGet(CountersStorage.Values, out BlittableJsonReaderObject values);
                        BlittableJsonReaderObject.PropertyDetails prop = default;
                        values.GetPropertyByIndex(0, ref prop);
                        using (table.Allocate(out TableValueBuilder tvb))
                        {
                            using (Slice.From(context.Allocator, changeVector, out var cv))
                                using (DocumentIdWorker.GetStringPreserveCase(context, collectionName.Name, out Slice collectionSlice))
                                    using (context.Allocator.Allocate(documentKeyPrefix.Size + prop.Name.Size, out var counterKeyBuffer))
                                        using (Slice.From(context.Allocator, prop.Name, out var nameSlice))
                                            using (CreateCounterKeySlice(context, counterKeyBuffer, documentKeyPrefix, nameSlice, out var counterKeySlice))
                                            {
                                                if (i == 0)
                                                {
                                                    tvb.Add(documentKeyPrefix);
                                                }
                                                else
                                                {
                                                    tvb.Add(counterKeySlice);
                                                }

                                                tvb.Add(Bits.SwapBytes(etag));
                                                tvb.Add(cv);
                                                tvb.Add(data.BasePointer, data.Size);
                                                tvb.Add(collectionSlice);
                                                tvb.Add(context.GetTransactionMarker());

                                                table.Set(tvb);
                                            }
                        }
                    }
                }
            }

            return(collectionName);
        }
        public unsafe dynamic LoadDocument(LazyStringValue keyLazy, string keyString, string collectionName)
        {
            using (_loadDocumentStats?.Start() ?? (_loadDocumentStats = _stats?.For(IndexingOperation.LoadDocument)))
            {
                if (keyLazy == null && keyString == null)
                {
                    return(DynamicNullObject.Null);
                }

                var source = Source;
                if (source == null)
                {
                    throw new ArgumentException("Cannot execute LoadDocument. Source is not set.");
                }

                var id = source.GetId() as LazyStringValue;
                if (id == null)
                {
                    throw new ArgumentException("Cannot execute LoadDocument. Source does not have a key.");
                }

                if (keyLazy != null && id.Equals(keyLazy))
                {
                    return(source);
                }

                if (keyString != null && id.Equals(keyString))
                {
                    return(source);
                }

                // we intentionally don't dispose of the scope here, this is being tracked by the references
                // and will be disposed there.

                // making sure that we normalize the case of the key so we'll be able to find
                // it in case insensitive manner
                // In addition, special characters need to be escaped
                Slice keySlice;
                if (keyLazy != null)
                {
                    if (keyLazy.Length == 0)
                    {
                        return(DynamicNullObject.Null);
                    }

                    DocumentIdWorker.GetSliceFromId(_documentsContext, keyLazy, out keySlice);
                }
                else
                {
                    if (keyString.Length == 0)
                    {
                        return(DynamicNullObject.Null);
                    }

                    DocumentIdWorker.GetSliceFromId(_documentsContext, keyString, out keySlice);
                }

                var references = GetReferencesForDocument(id);

                references.Add(keySlice);

                // when there is conflict, we need to apply same behavior as if the document would not exist
                var document = _documentsStorage.Get(_documentsContext, keySlice, throwOnConflict: false);

                if (document == null)
                {
                    return(DynamicNullObject.Null);
                }

                // we can't share one DynamicBlittableJson instance among all documents because we can have multiple LoadDocuments in a single scope
                return(new DynamicBlittableJson(document));
            }
        }