Пример #1
0
        public static dynamic IfEntityIs(this object self, string collection)
        {
            var document = self as DynamicBlittableJson;

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

            var collectionName = CollectionName.GetCollectionName(document);

            if (string.Equals(collection, collectionName, StringComparison.OrdinalIgnoreCase) == false)
            {
                return(DynamicNullObject.Null);
            }

            return(document);
        }
Пример #2
0
        public static IEnumerable <dynamic> WhereEntityIs(this IEnumerable <dynamic> self, params string[] collections)
        {
            foreach (var document in self)
            {
                var dynamicBlittableJson = document as DynamicBlittableJson;
                if (dynamicBlittableJson == null)
                {
                    continue;
                }

                var collectionName = CollectionName.GetCollectionName(dynamicBlittableJson);
                if (collections.Contains(collectionName, StringComparer.OrdinalIgnoreCase) == false)
                {
                    continue;
                }

                yield return(document);
            }
        }
Пример #3
0
        private bool TryResolveUsingDefaultResolver(
            DocumentsOperationContext context,
            string id,
            string collection,
            string incomingChangeVector,
            BlittableJsonReaderObject doc)
        {
            if (_conflictResolver.ConflictSolver?.DatabaseResolverId == null)
            {
                return(false);
            }

            var conflicts          = new List <DocumentConflict>(_database.DocumentsStorage.ConflictsStorage.GetConflictsFor(context, id));
            var localDocumentTuple = _database.DocumentsStorage.GetDocumentOrTombstone(context, id, false);
            var localDoc           = DocumentConflict.From(context, localDocumentTuple.Document) ??
                                     DocumentConflict.From(localDocumentTuple.Tombstone);

            if (localDoc != null)
            {
                conflicts.Add(localDoc);
            }
            conflicts.Add(new DocumentConflict
            {
                ChangeVector = incomingChangeVector,
                Collection   = context.GetLazyStringForFieldWithCaching(
                    collection ??
                    CollectionName.GetCollectionName(id, doc)),
                Doc     = doc,
                LowerId = context.GetLazyString(id)
            });

            if (_conflictResolver.TryResolveUsingDefaultResolverInternal(
                    context,
                    _conflictResolver.ConflictSolver.DatabaseResolverId,
                    conflicts, out var resolved))
            {
                _conflictResolver.PutResolvedDocument(context, resolved);
                return(true);
            }

            return(false);
        }
Пример #4
0
            public static string GetDocumentCollection(string docId, DocumentDatabase documentDatabase, DocumentsOperationContext context, bool fromEtl, out Document doc)
            {
                try
                {
                    doc = documentDatabase.DocumentsStorage.Get(context, docId, throwOnConflict: true);
                    if (doc == null)
                    {
                        if (fromEtl)
                        {
                            return(null);
                        }

                        ThrowMissingDocument(docId);
                        return(null); // never hit
                    }

                    if (doc.Flags.HasFlag(DocumentFlags.Artificial))
                    {
                        ThrowArtificialDocument(doc);
                    }

                    return(CollectionName.GetCollectionName(doc.Data));
                }
                catch (DocumentConflictException)
                {
                    doc = null;

                    if (fromEtl)
                    {
                        return(null);
                    }

                    // this is fine, we explicitly support
                    // setting the flag if we are in conflicted state is
                    // done by the conflict resolver

                    // avoid loading same document again, we validate write using the metadata instance
                    doc = new Document();
                    return(documentDatabase.DocumentsStorage.ConflictsStorage.GetCollection(context, docId));
                }
            }
Пример #5
0
        public void HandleConflictForDocument(
            DocumentsOperationContext documentsContext,
            string id,
            string collection,
            long lastModifiedTicks,
            BlittableJsonReaderObject doc,
            string changeVector,
            string conflictedChangeVector,
            DocumentFlags flags)
        {
            if (id.StartsWith("Raven/Hilo/", StringComparison.OrdinalIgnoreCase))
            {
                HandleHiloConflict(documentsContext, id, doc, changeVector);
                return;
            }
            if (TryResolveIdenticalDocument(
                    documentsContext,
                    id,
                    doc,
                    lastModifiedTicks,
                    changeVector))
            {
                return;
            }

            var conflictedDoc = new DocumentConflict
            {
                Doc        = doc,
                Collection = documentsContext.GetLazyStringForFieldWithCaching(
                    collection ??
                    CollectionName.GetCollectionName(doc)
                    ),
                LastModified = new DateTime(lastModifiedTicks),
                LowerId      = documentsContext.GetLazyString(id),
                Id           = documentsContext.GetLazyString(id),
                ChangeVector = changeVector
            };

            if (TryResolveConflictByScript(
                    documentsContext,
                    conflictedDoc))
            {
                return;
            }

            if (_conflictResolver.ConflictSolver?.ResolveToLatest == true)
            {
                if (conflictedChangeVector == null) //precaution
                {
                    throw new InvalidOperationException(
                              "Detected conflict on replication, but could not figure out conflicted vector. This is not supposed to happen and is likely a bug.");
                }

                var conflicts = new List <DocumentConflict>
                {
                    conflictedDoc.Clone()
                };
                conflicts.AddRange(documentsContext.DocumentDatabase.DocumentsStorage.ConflictsStorage.GetConflictsFor(
                                       documentsContext, id));
                var localDocumentTuple =
                    documentsContext.DocumentDatabase.DocumentsStorage.GetDocumentOrTombstone(documentsContext,
                                                                                              id, false);
                var local = DocumentConflict.From(documentsContext, localDocumentTuple.Document) ?? DocumentConflict.From(localDocumentTuple.Tombstone);
                if (local != null)
                {
                    conflicts.Add(local);
                }

                var resolved = _conflictResolver.ResolveToLatest(documentsContext, conflicts);
                _conflictResolver.PutResolvedDocument(documentsContext, resolved, conflictedDoc);

                return;
            }
            _database.DocumentsStorage.ConflictsStorage.AddConflict(documentsContext, id, lastModifiedTicks, doc, changeVector, collection, flags);
        }
Пример #6
0
        private bool TryResolveConflictByScript(
            DocumentsOperationContext documentsContext,
            string id,
            string incomingChangeVector,
            BlittableJsonReaderObject doc)
        {
            var collection = CollectionName.GetCollectionName(id, doc);

            var hasScript = _conflictResolver.ScriptConflictResolversCache.TryGetValue(collection, out ScriptResolver scriptResolver);

            if (!hasScript || scriptResolver == null)
            {
                if (_log.IsInfoEnabled)
                {
                    _log.Info($"Script not found to resolve the {collection} collection");
                }
                return(false);
            }

            var conflictedDocs = new List <DocumentConflict>(documentsContext.DocumentDatabase.DocumentsStorage.ConflictsStorage.GetConflictsFor(documentsContext, id));

            if (conflictedDocs.Count == 0)
            {
                var relevantLocalDoc = documentsContext.DocumentDatabase.DocumentsStorage
                                       .GetDocumentOrTombstone(
                    documentsContext,
                    id);
                if (relevantLocalDoc.Document != null)
                {
                    conflictedDocs.Add(DocumentConflict.From(documentsContext, relevantLocalDoc.Document));
                }
                else if (relevantLocalDoc.Tombstone != null)
                {
                    conflictedDocs.Add(DocumentConflict.From(relevantLocalDoc.Tombstone));
                }
            }

            if (conflictedDocs.Count == 0)
            {
                InvalidConflictWhenThereIsNone(id);
            }

            conflictedDocs.Add(new DocumentConflict
            {
                LowerId      = conflictedDocs[0].LowerId,
                Id           = conflictedDocs[0].Id,
                Collection   = documentsContext.GetLazyStringForFieldWithCaching(collection),
                ChangeVector = incomingChangeVector,
                Doc          = doc
            });

            if (_conflictResolver.TryResolveConflictByScriptInternal(
                    documentsContext,
                    scriptResolver,
                    conflictedDocs,
                    documentsContext.GetLazyString(collection), out var resolved))
            {
                _conflictResolver.PutResolvedDocument(documentsContext, resolved);
                return(true);
            }

            return(false);
        }
Пример #7
0
        public unsafe void HandleConflictForDocument(
            DocumentsOperationContext documentsContext,
            string id,
            string collection,
            long lastModifiedTicks,
            BlittableJsonReaderObject doc,
            string changeVector,
            DocumentFlags flags)
        {
            if (id.StartsWith(HiLoHandler.RavenHiloIdPrefix, StringComparison.OrdinalIgnoreCase))
            {
                HandleHiloConflict(documentsContext, id, doc, changeVector);
                return;
            }

            if (TryResolveIdenticalDocument(
                    documentsContext,
                    id,
                    doc,
                    lastModifiedTicks,
                    changeVector))
            {
                return;
            }

            var lazyId = documentsContext.GetLazyString(id);

            using (DocumentIdWorker.GetLower(documentsContext.Allocator, lazyId, out var loweredKey))
            {
                var conflictedDoc = new DocumentConflict
                {
                    Doc        = doc,
                    Collection = documentsContext.GetLazyStringForFieldWithCaching(
                        collection ??
                        CollectionName.GetCollectionName(doc)
                        ),
                    LastModified = new DateTime(lastModifiedTicks),
                    LowerId      = documentsContext.AllocateStringValue(null, loweredKey.Content.Ptr, loweredKey.Content.Length),
                    Id           = lazyId,
                    ChangeVector = changeVector,
                    Flags        = flags
                };

                if (TryResolveConflictByScript(
                        documentsContext,
                        conflictedDoc))
                {
                    return;
                }

                if (_conflictResolver.ConflictSolver?.ResolveToLatest ?? true)
                {
                    var conflicts = new List <DocumentConflict>
                    {
                        conflictedDoc.Clone()
                    };
                    conflicts.AddRange(_database.DocumentsStorage.ConflictsStorage.GetConflictsFor(documentsContext, id));

                    var localDocumentTuple = _database.DocumentsStorage.GetDocumentOrTombstone(documentsContext, id, false);
                    var local = DocumentConflict.From(documentsContext, localDocumentTuple.Document) ?? DocumentConflict.From(localDocumentTuple.Tombstone);
                    if (local != null)
                    {
                        conflicts.Add(local);
                    }

                    var resolved = _conflictResolver.ResolveToLatest(conflicts);
                    _conflictResolver.PutResolvedDocument(documentsContext, resolved, resolvedToLatest: true, conflictedDoc);

                    return;
                }

                _database.DocumentsStorage.ConflictsStorage.AddConflict(documentsContext, id, lastModifiedTicks, doc, changeVector, collection, flags);
            }
        }
Пример #8
0
            protected override int ExecuteCmd(DocumentsOperationContext context)
            {
                if (_database.ServerStore.Server.Configuration.Core.FeaturesAvailability == FeaturesAvailability.Stable)
                    FeaturesAvailabilityException.Throw("Counters");

                var ops = 0;
                var countersToAdd = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
                var countersToRemove = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

                foreach (var kvp in _dictionary)
                {
                    Document doc = null;
                    var docId = kvp.Key;
                    string docCollection = null;
                    ops += kvp.Value.Count;
                    foreach (var operation in kvp.Value)
                    {
                        switch (operation.Type)
                        {
                            case CounterOperationType.Increment:
                            case CounterOperationType.Delete:
                            case CounterOperationType.Put:
                                LoadDocument();
                                break;
                        }

                        switch (operation.Type)
                        {
                            case CounterOperationType.Increment:
                                LastChangeVector =
                                    _database.DocumentsStorage.CountersStorage.IncrementCounter(context, docId, docCollection, operation.CounterName, operation.Delta, out var exists);
                                GetCounterValue(context, _database, docId, operation.CounterName, _replyWithAllNodesValues, CountersDetail);

                                if (exists == false)
                                {
                                    // if exists it is already on the document's metadata
                                    countersToAdd.Add(operation.CounterName);
                                    countersToRemove.Remove(operation.CounterName);
                                }

                                break;
                            case CounterOperationType.Delete:
                                if (_fromEtl && doc == null)
                                    break;

                                LastChangeVector = _database.DocumentsStorage.CountersStorage.DeleteCounter(context, docId, docCollection, operation.CounterName);

                                countersToAdd.Remove(operation.CounterName);
                                countersToRemove.Add(operation.CounterName);
                                break;
                            case CounterOperationType.Put:
                                if (_fromEtl && doc == null)
                                    break;

                                // intentionally not setting LastChangeVector, we never use it for
                                // etl / import and it isn't meaningful in those scenarios

                                if (_fromEtl)
                                {
                                    _database.DocumentsStorage.CountersStorage.PutCounter(context, docId, docCollection,
                                        operation.CounterName,  operation.Delta);
                                }
                                else
                                {
                                    _database.DocumentsStorage.CountersStorage.PutCounter(context, docId, docCollection,
                                        operation.CounterName, operation.ChangeVector, operation.Delta);
                                }

                                countersToAdd.Add(operation.CounterName);
                                countersToRemove.Remove(operation.CounterName);
                                break;
                            case CounterOperationType.None:
                                break;
                            case CounterOperationType.Get:
                                GetCounterValue(context, _database, docId, operation.CounterName, _replyWithAllNodesValues, CountersDetail);
                                break;
                            default:
                                ThrowInvalidBatchOperationType(operation);
                                break;
                        }
                    }

                    if (doc?.Data != null)
                    {
                        var nonPersistentFlags = NonPersistentDocumentFlags.ByCountersUpdate;
                        if (_fromSmuggler)
                            nonPersistentFlags |= NonPersistentDocumentFlags.FromSmuggler;

                        _database.DocumentsStorage.CountersStorage.UpdateDocumentCounters(context, doc, docId, countersToAdd, countersToRemove, nonPersistentFlags);
                        doc.Data.Dispose(); // we cloned the data, so we can dispose it.
                    }

                    countersToAdd.Clear();
                    countersToRemove.Clear();

                    void LoadDocument()
                    {
                        if (doc != null)
                            return;
                        try
                        {
                            doc = _database.DocumentsStorage.Get(context, docId,
                                throwOnConflict: true);
                            if (doc == null)
                            {
                                if (_fromEtl)
                                    return;

                                ThrowMissingDocument(docId);
                                return; // never hit
                            }

                            if (doc.Flags.HasFlag(DocumentFlags.Artificial))
                                ThrowArtificialDocument(doc);

                            docCollection = CollectionName.GetCollectionName(doc.Data);
                        }
                        catch (DocumentConflictException)
                        {
                            if (_fromEtl)
                                return;

                            // this is fine, we explicitly support
                            // setting the flag if we are in conflicted state is 
                            // done by the conflict resolver

                            // avoid loading same document again, we validate write using the metadata instance
                            doc = new Document();
                            docCollection = _database.DocumentsStorage.ConflictsStorage.GetCollection(context, docId);
                        }
                    }
                }

                return ops;
            }
Пример #9
0
            protected override int ExecuteCmd(DocumentsOperationContext context)
            {
                var countersToAdd    = new SortedSet <string>(StringComparer.OrdinalIgnoreCase);
                var countersToRemove = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

                Document doc           = null;
                string   docId         = null;
                string   docCollection = null;

                foreach (var operation in _list)
                {
                    switch (operation.Type)
                    {
                    case CounterOperationType.Increment:
                    case CounterOperationType.Delete:
                    case CounterOperationType.Put:
                        LoadDocument(operation);
                        break;
                    }

                    docId = operation.DocumentId;

                    switch (operation.Type)
                    {
                    case CounterOperationType.Increment:
                        LastChangeVector =
                            _database.DocumentsStorage.CountersStorage.IncrementCounter(context, docId, docCollection, operation.CounterName, operation.Delta, out var exists);
                        GetCounterValue(context, _database, docId, operation.CounterName, _replyWithAllNodesValues, CountersDetail);

                        if (exists == false)
                        {
                            // if exists it is already on the document's metadata
                            countersToAdd.Add(operation.CounterName);
                            countersToRemove.Remove(operation.CounterName);
                        }
                        break;

                    case CounterOperationType.Delete:
                        if (_fromEtl && doc == null)
                        {
                            break;
                        }

                        LastChangeVector = _database.DocumentsStorage.CountersStorage.DeleteCounter(context, docId, docCollection, operation.CounterName);

                        countersToAdd.Remove(operation.CounterName);
                        countersToRemove.Add(operation.CounterName);
                        break;

                    case CounterOperationType.Put:
                        if (_fromEtl == false || doc == null)
                        {
                            break;
                        }

                        _database.DocumentsStorage.CountersStorage.PutCounter(context, docId, docCollection, operation.CounterName, operation.Delta);

                        countersToAdd.Add(operation.CounterName);
                        countersToRemove.Remove(operation.CounterName);
                        break;

                    case CounterOperationType.None:
                        break;

                    case CounterOperationType.Get:
                        GetCounterValue(context, _database, docId, operation.CounterName, _replyWithAllNodesValues, CountersDetail);
                        break;

                    default:
                        ThrowInvalidBatchOperationType(operation);
                        break;
                    }
                }

                if (doc?.Data != null)
                {
                    var changeVector = _database
                                       .DocumentsStorage
                                       .CountersStorage
                                       .UpdateDocumentCounters(context, doc, docId, countersToAdd, countersToRemove, NonPersistentDocumentFlags.ByCountersUpdate);

                    if (changeVector != null)
                    {
                        LastDocumentChangeVector = LastChangeVector = changeVector;
                    }

                    doc.Data.Dispose(); // we cloned the data, so we can dispose it.
                }

                countersToAdd.Clear();
                countersToRemove.Clear();

                void LoadDocument(CounterOperation counterOperation)
                {
                    if (string.IsNullOrEmpty(counterOperation.DocumentId))
                    {
                        throw new ArgumentException("Document ID can't be null");
                    }

                    if (docId == counterOperation.DocumentId && doc != null)
                    {
                        return;
                    }

                    ApplyChangesForPreviousDocument(context, doc, docId, countersToAdd, countersToRemove);

                    docId = counterOperation.DocumentId;

                    try
                    {
                        doc = _database.DocumentsStorage.Get(context, docId, throwOnConflict: true);
                        if (doc == null)
                        {
                            if (_fromEtl)
                            {
                                return;
                            }
                            ThrowMissingDocument(docId);
                            return; // never hit
                        }

                        if (doc.Flags.HasFlag(DocumentFlags.Artificial))
                        {
                            ThrowArtificialDocument(doc);
                        }

                        docCollection = CollectionName.GetCollectionName(doc.Data);
                    }
                    catch (DocumentConflictException)
                    {
                        if (_fromEtl)
                        {
                            return;
                        }

                        // this is fine, we explicitly support
                        // setting the flag if we are in conflicted state is
                        // done by the conflict resolver

                        // avoid loading same document again, we validate write using the metadata instance
                        doc           = new Document();
                        docCollection = _database.DocumentsStorage.ConflictsStorage.GetCollection(context, docId);
                    }
                }

                ApplyChangesForPreviousDocument(context, doc, docId, countersToAdd, countersToRemove);

                return(_list.Count);
            }
Пример #10
0
            public override int Execute(DocumentsOperationContext context)
            {
                if (_database.ServerStore.Server.Configuration.Core.FeaturesAvailability == FeaturesAvailability.Stable)
                {
                    FeaturesAvailabilityException.Throw("Counters");
                }

                foreach (var kvp in _dictionary)
                {
                    Document doc = null;
                    BlittableJsonReaderObject metadata = null;
                    var    docId         = kvp.Key;
                    string docCollection = null;

                    foreach (var operation in kvp.Value)
                    {
                        switch (operation.Type)
                        {
                        case CounterOperationType.Increment:
                        case CounterOperationType.Delete:
                        case CounterOperationType.Put:
                            LoadDocument();

                            if (doc != null)
                            {
                                docCollection = CollectionName.GetCollectionName(doc.Data);
                            }

                            break;
                        }

                        switch (operation.Type)
                        {
                        case CounterOperationType.Increment:
                            LastChangeVector =
                                _database.DocumentsStorage.CountersStorage.IncrementCounter(context, docId, docCollection, operation.CounterName, operation.Delta);
                            GetCounterValue(context, _database, docId, operation.CounterName, _replyWithAllNodesValues, CountersDetail);
                            break;

                        case CounterOperationType.Delete:
                            if (_fromEtl && doc == null)
                            {
                                break;
                            }

                            LastChangeVector = _database.DocumentsStorage.CountersStorage.DeleteCounter(context, docId, docCollection, operation.CounterName);
                            break;

                        case CounterOperationType.Put:
                            if (_fromEtl && doc == null)
                            {
                                break;
                            }

                            // intentionally not setting LastChangeVector, we never use it for
                            // etl / import and it isn't meaningful in those scenarios

                            if (_fromEtl)
                            {
                                _database.DocumentsStorage.CountersStorage.PutCounter(context, docId, docCollection,
                                                                                      operation.CounterName, operation.Delta);
                            }
                            else
                            {
                                _database.DocumentsStorage.CountersStorage.PutCounter(context, docId, docCollection,
                                                                                      operation.CounterName, operation.ChangeVector, operation.Delta);
                            }

                            break;

                        case CounterOperationType.None:
                            break;

                        case CounterOperationType.Get:
                            GetCounterValue(context, _database, docId, operation.CounterName, _replyWithAllNodesValues, CountersDetail);
                            break;

                        default:
                            ThrowInvalidBatchOperationType(operation);
                            break;
                        }
                    }

                    if (metadata != null)
                    {
                        _database.DocumentsStorage.CountersStorage.UpdateDocumentCounters(context, doc.Data, docId, metadata, kvp.Value);
                    }

                    void LoadDocument()
                    {
                        if (doc != null)
                        {
                            return;
                        }
                        try
                        {
                            doc = _database.DocumentsStorage.Get(context, docId,
                                                                 throwOnConflict: true);
                            if (doc == null)
                            {
                                if (_fromEtl)
                                {
                                    return;
                                }

                                ThrowMissingDocument(docId);
                                return; // never hit
                            }

                            if (doc.TryGetMetadata(out metadata) == false)
                            {
                                ThrowInvalidDocumentWithNoMetadata(doc);
                            }
                            if (doc.Flags.HasFlag(DocumentFlags.Artificial))
                            {
                                ThrowArtificialDocument(doc);
                            }
                        }
                        catch (DocumentConflictException)
                        {
                            if (_fromEtl)
                            {
                                return;
                            }

                            // this is fine, we explicitly support
                            // setting the flag if we are in conflicted state is
                            // done by the conflict resolver

                            // avoid loading same document again, we validate write using the metadata instance
                            doc = new Document();
                        }
                    }
                }

                return(CountersDetail.Counters.Count);
            }
Пример #11
0
            protected override int ExecuteCmd(DocumentsOperationContext context)
            {
                if (_database.ServerStore.Server.Configuration.Core.FeaturesAvailability == FeaturesAvailability.Stable)
                {
                    FeaturesAvailabilityException.Throw("Counters");
                }

                var countersToAdd    = new SortedSet <string>(StringComparer.OrdinalIgnoreCase);
                var countersToRemove = new HashSet <string>(StringComparer.OrdinalIgnoreCase);

                string   docId         = null;
                Document doc           = null;
                string   docCollection = null;

                foreach (var operation in _list)
                {
                    switch (operation.Type)
                    {
                    case CounterOperationType.Increment:
                    case CounterOperationType.Delete:
                    case CounterOperationType.Put:
                        try
                        {
                            LoadDocument(operation);
                        }
                        catch (DocumentDoesNotExistException)
                        {
                            if (_fromSmuggler)
                            {
                                ErrorCount++;
                                continue;
                            }

                            throw;
                        }

                        break;
                    }

                    docId = operation.DocumentId;

                    switch (operation.Type)
                    {
                    case CounterOperationType.Increment:
                        LastChangeVector =
                            _database.DocumentsStorage.CountersStorage.IncrementCounter(context, docId, docCollection, operation.CounterName, operation.Delta,
                                                                                        out var exists);
                        GetCounterValue(context, _database, docId, operation.CounterName, _replyWithAllNodesValues, CountersDetail);

                        if (exists == false)
                        {
                            // if exists it is already on the document's metadata
                            countersToAdd.Add(operation.CounterName);
                            countersToRemove.Remove(operation.CounterName);
                        }

                        break;

                    case CounterOperationType.Delete:
                        if (_fromEtl && doc == null)
                        {
                            break;
                        }

                        LastChangeVector = _database.DocumentsStorage.CountersStorage.DeleteCounter(context, docId, docCollection, operation.CounterName);

                        countersToAdd.Remove(operation.CounterName);
                        countersToRemove.Add(operation.CounterName);
                        break;

                    case CounterOperationType.Put:
                        if (_fromEtl && doc == null)
                        {
                            break;
                        }

                        // intentionally not setting LastChangeVector, we never use it for
                        // etl / import and it isn't meaningful in those scenarios

                        if (_fromEtl)
                        {
                            _database.DocumentsStorage.CountersStorage.PutCounter(context, docId, docCollection,
                                                                                  operation.CounterName, operation.Delta);
                        }
                        else
                        {
                            _database.DocumentsStorage.CountersStorage.PutCounter(context, docId, docCollection,
                                                                                  operation.CounterName, operation.ChangeVector, operation.Delta);
                        }

                        countersToAdd.Add(operation.CounterName);
                        countersToRemove.Remove(operation.CounterName);
                        break;

                    case CounterOperationType.None:
                        break;

                    case CounterOperationType.Get:
                        GetCounterValue(context, _database, docId, operation.CounterName, _replyWithAllNodesValues, CountersDetail);
                        break;

                    default:
                        ThrowInvalidBatchOperationType(operation);
                        break;
                    }

                    void LoadDocument(CounterOperation counterOperation)
                    {
                        if (string.IsNullOrEmpty(counterOperation.DocumentId))
                        {
                            throw new ArgumentException("Document ID can't be null");
                        }

                        if (docId == counterOperation.DocumentId && doc != null)
                        {
                            return;
                        }

                        ApplyChangesForPreviousDocument(context, doc, docId, countersToAdd, countersToRemove);

                        docId = counterOperation.DocumentId;

                        try
                        {
                            doc = _database.DocumentsStorage.Get(context, docId,
                                                                 throwOnConflict: true);
                            if (doc == null)
                            {
                                if (_fromEtl)
                                {
                                    return;
                                }
                                ThrowMissingDocument(docId);
                                return; // never hit
                            }

                            if (doc.Flags.HasFlag(DocumentFlags.Artificial))
                            {
                                ThrowArtificialDocument(doc);
                            }

                            docCollection = CollectionName.GetCollectionName(doc.Data);
                        }
                        catch (DocumentConflictException)
                        {
                            if (_fromEtl)
                            {
                                return;
                            }

                            // this is fine, we explicitly support
                            // setting the flag if we are in conflicted state is
                            // done by the conflict resolver

                            // avoid loading same document again, we validate write using the metadata instance
                            doc           = new Document();
                            docCollection = _database.DocumentsStorage.ConflictsStorage.GetCollection(context, docId);
                        }
                    }
                }
                ApplyChangesForPreviousDocument(context, doc, docId, countersToAdd, countersToRemove);

                return(_list.Count);
            }
Пример #12
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);
        }
Пример #13
0
        private void DeleteCounter(UpdateStep step, LazyStringValue tombstoneKey, DocumentsOperationContext context)
        {
            var(docId, counterName) = ExtractDocIdAndNameFromCounterTombstone(context, tombstoneKey);

            using (docId)
                using (counterName)
                    using (DocumentIdWorker.GetLowerIdSliceAndStorageKey(context, docId, out Slice lowerId, out _))
                    {
                        string collection = null;

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

                        var collectionName = new CollectionName(collection);
                        var table          = step.DocumentsStorage.CountersStorage.GetCountersTable(step.WriteTx, collectionName);

                        if (table.ReadByKey(lowerId, out var existing) == false)
                        {
                            return;
                        }

                        // (int)CountersTable.Data = 3
                        var data = new BlittableJsonReaderObject(existing.Read(3, out int oldSize), oldSize, context);

                        if (data.TryGet(CountersStorage.Values, out BlittableJsonReaderObject counters) == false ||
                            counters.TryGetMember(counterName, out object counterToDelete) == false ||
                            counterToDelete is LazyStringValue) // already deleted
                        {
                            return;
                        }

                        var deleteCv = step.DocumentsStorage.CountersStorage.GenerateDeleteChangeVectorFromRawBlob(data, counterToDelete as BlittableJsonReaderObject.RawBlob);
                        counters.Modifications = new DynamicJsonValue(counters)
                        {
                            [counterName] = deleteCv
                        };

                        using (var old = data)
                        {
                            data = context.ReadObject(data, null, BlittableJsonDocumentBuilder.UsageMode.ToDisk);
                        }

                        var newEtag         = step.DocumentsStorage.GenerateNextEtag();
                        var newChangeVector = ChangeVectorUtils.NewChangeVector(step.DocumentsStorage.DocumentDatabase.ServerStore.NodeTag, newEtag, _dbId);
                        using (data)
                            using (Slice.From(context.Allocator, newChangeVector, out var cv))
                                using (DocumentIdWorker.GetStringPreserveCase(context, collectionName.Name, out Slice collectionSlice))
                                    using (table.Allocate(out TableValueBuilder tvb))
                                    {
                                        tvb.Add(lowerId);
                                        tvb.Add(Bits.SwapBytes(newEtag));
                                        tvb.Add(cv);
                                        tvb.Add(data.BasePointer, data.Size);
                                        tvb.Add(collectionSlice);
                                        tvb.Add(context.GetTransactionMarker());

                                        table.Set(tvb);
                                    }
                    }
        }