Пример #1
0
        public string IncrementCounter(DocumentsOperationContext context, string documentId, string collection, string name, long value)
        {
            if (context.Transaction == null)
            {
                DocumentPutAction.ThrowRequiresTransaction();
                Debug.Assert(false);// never hit
            }

            var collectionName = _documentsStorage.ExtractCollectionName(context, collection);
            var table          = GetCountersTable(context.Transaction.InnerTransaction, collectionName);

            using (GetCounterKey(context, documentId, name, context.Environment.Base64Id, out var counterKey))
            {
                long prev = 0;
                if (table.ReadByKey(counterKey, out var existing))
                {
                    prev = *(long *)existing.Read((int)CountersTable.Value, out var size);
                    Debug.Assert(size == sizeof(long));
                }

                RemoveTombstoneIfExists(context, documentId, name);

                var etag   = _documentsStorage.GenerateNextEtag();
                var result = ChangeVectorUtils.TryUpdateChangeVector(_documentDatabase.ServerStore.NodeTag, _documentsStorage.Environment.Base64Id, etag, string.Empty);

                using (Slice.From(context.Allocator, result.ChangeVector, out var cv))

                    using (DocumentIdWorker.GetStringPreserveCase(context, name, out Slice nameSlice))
                        using (DocumentIdWorker.GetStringPreserveCase(context, collectionName.Name, out Slice collectionSlice))
                            using (table.Allocate(out TableValueBuilder tvb))
                            {
                                tvb.Add(counterKey);
                                tvb.Add(nameSlice);
                                tvb.Add(Bits.SwapBytes(etag));
                                tvb.Add(prev + value); //inc
                                tvb.Add(cv);
                                tvb.Add(collectionSlice);
                                tvb.Add(context.TransactionMarkerOffset);

                                table.Set(tvb);
                            }

                context.Transaction.AddAfterCommitNotification(new DocumentChange
                {
                    ChangeVector = result.ChangeVector,
                    Id           = documentId,
                    CounterName  = name,
                    Type         = DocumentChangeTypes.Counter
                });

                return(result.ChangeVector);
            }
        }
Пример #2
0
        private void PutCounterImpl(DocumentsOperationContext context, string documentId, string collection, string name, string changeVector, long value)
        {
            if (context.Transaction == null)
            {
                DocumentPutAction.ThrowRequiresTransaction();
                Debug.Assert(false);// never hit
            }

            var collectionName = _documentsStorage.ExtractCollectionName(context, collection);
            var table          = GetCountersTable(context.Transaction.InnerTransaction, collectionName);

            using (GetCounterKey(context, documentId, name, changeVector ?? context.Environment.Base64Id, out var counterKey))
            {
                using (DocumentIdWorker.GetStringPreserveCase(context, name, out Slice nameSlice))
                    using (table.Allocate(out TableValueBuilder tvb))
                    {
                        if (changeVector != null)
                        {
                            if (table.ReadByKey(counterKey, out var existing))
                            {
                                var existingChangeVector = TableValueToChangeVector(context, (int)CountersTable.ChangeVector, ref existing);

                                if (ChangeVectorUtils.GetConflictStatus(changeVector, existingChangeVector) == ConflictStatus.AlreadyMerged)
                                {
                                    return;
                                }
                            }
                        }

                        RemoveTombstoneIfExists(context, documentId, name);

                        var etag = _documentsStorage.GenerateNextEtag();

                        if (changeVector == null)
                        {
                            changeVector = ChangeVectorUtils
                                           .TryUpdateChangeVector(_documentDatabase.ServerStore.NodeTag, _documentsStorage.Environment.Base64Id, etag, string.Empty)
                                           .ChangeVector;
                        }

                        using (Slice.From(context.Allocator, changeVector, out var cv))
                            using (DocumentIdWorker.GetStringPreserveCase(context, collectionName.Name, out Slice collectionSlice))
                            {
                                tvb.Add(counterKey);
                                tvb.Add(nameSlice);
                                tvb.Add(Bits.SwapBytes(etag));
                                tvb.Add(value);
                                tvb.Add(cv);
                                tvb.Add(collectionSlice);
                                tvb.Add(context.TransactionMarkerOffset);

                                table.Set(tvb);
                            }

                        UpdateMetrics(counterKey, name, changeVector, collection);

                        context.Transaction.AddAfterCommitNotification(new CounterChange
                        {
                            ChangeVector = changeVector,
                            DocumentId   = documentId,
                            Name         = name,
                            Value        = value,
                            Type         = CounterChangeTypes.Put
                        });
                    }
            }
        }
Пример #3
0
        public string IncrementCounter(DocumentsOperationContext context, string documentId, string collection, string name, long delta, out bool exists)
        {
            if (context.Transaction == null)
            {
                DocumentPutAction.ThrowRequiresTransaction();
                Debug.Assert(false);// never hit
            }

            var collectionName = _documentsStorage.ExtractCollectionName(context, collection);
            var table          = GetCountersTable(context.Transaction.InnerTransaction, collectionName);

            using (GetCounterKey(context, documentId, name, context.Environment.Base64Id, out var counterKey))
            {
                var value = delta;
                exists = table.ReadByKey(counterKey, out var existing);
                if (exists)
                {
                    var prev = *(long *)existing.Read((int)CountersTable.Value, out var size);
                    Debug.Assert(size == sizeof(long));
                    try
                    {
                        value = checked (prev + delta); //inc
                    }
                    catch (OverflowException e)
                    {
                        CounterOverflowException.ThrowFor(documentId, name, prev, delta, e);
                    }
                }

                RemoveTombstoneIfExists(context, documentId, name);

                var etag         = _documentsStorage.GenerateNextEtag();
                var changeVector = ChangeVectorUtils.NewChangeVector(_documentDatabase.ServerStore.NodeTag, etag, _documentsStorage.Environment.Base64Id);

                using (Slice.From(context.Allocator, changeVector, out var cv))
                    using (DocumentIdWorker.GetStringPreserveCase(context, name, out Slice nameSlice))
                        using (DocumentIdWorker.GetStringPreserveCase(context, collectionName.Name, out Slice collectionSlice))
                            using (table.Allocate(out TableValueBuilder tvb))
                            {
                                tvb.Add(counterKey);
                                tvb.Add(nameSlice);
                                tvb.Add(Bits.SwapBytes(etag));
                                tvb.Add(value);
                                tvb.Add(cv);
                                tvb.Add(collectionSlice);
                                tvb.Add(context.TransactionMarkerOffset);

                                table.Set(tvb);
                            }

                UpdateMetrics(counterKey, name, changeVector, collection);

                context.Transaction.AddAfterCommitNotification(new CounterChange
                {
                    ChangeVector = changeVector,
                    DocumentId   = documentId,
                    Name         = name,
                    Type         = exists ? CounterChangeTypes.Increment : CounterChangeTypes.Put,
                    Value        = value
                });

                return(changeVector);
            }
        }