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