private PatchResultData ApplyPatchInternal(string docId, Etag etag, TransactionInformation transactionInformation, Func<JsonDocument, RavenJObject> patcher, Func<RavenJObject> patcherIfMissing, Func<IList<JsonDocument>> getDocsCreatedInPatch, bool debugMode) { if (docId == null) throw new ArgumentNullException("docId"); docId = docId.Trim(); var result = new PatchResultData { PatchResult = PatchResult.Patched }; bool shouldRetry = false; int retries = 128; Random rand = null; do { var doc = Database.Documents.Get(docId, transactionInformation); Log.Debug(() => string.Format("Preparing to apply patch on ({0}). Document found?: {1}.", docId, doc != null)); if (etag != null && doc != null && doc.Etag != etag) { Debug.Assert(doc.Etag != null); Log.Debug(() => string.Format("Got concurrent exception while tried to patch the following document ID: {0}", docId)); throw new ConcurrencyException("Could not patch document '" + docId + "' because non current etag was used") { ActualETag = doc.Etag, ExpectedETag = etag, }; } var jsonDoc = (doc != null ? patcher(doc) : patcherIfMissing()); if (jsonDoc == null) { Log.Debug(() => string.Format("Preparing to apply patch on ({0}). DocumentDoesNotExists.", docId)); result.PatchResult = PatchResult.DocumentDoesNotExists; } else { if (debugMode) { result.Document = jsonDoc; result.PatchResult = PatchResult.Tested; } else { try { Database.Documents.Put(doc == null ? docId : doc.Key, (doc == null ? null : doc.Etag), jsonDoc, jsonDoc.Value<RavenJObject>(Constants.Metadata), transactionInformation); var docsCreatedInPatch = getDocsCreatedInPatch(); if (docsCreatedInPatch != null && docsCreatedInPatch.Count > 0) { foreach (var docFromPatch in docsCreatedInPatch) { Database.Documents.Put(docFromPatch.Key, docFromPatch.Etag, docFromPatch.DataAsJson, docFromPatch.Metadata, transactionInformation); } } shouldRetry = false; result.PatchResult = PatchResult.Patched; } catch (ConcurrencyException) { if (TransactionalStorage.IsAlreadyInBatch) throw; if (retries-- > 0) { shouldRetry = true; if (rand == null) rand = new Random(); Thread.Sleep(rand.Next(5, Math.Max(retries * 2, 10))); continue; } throw; } } } if (shouldRetry == false) WorkContext.ShouldNotifyAboutWork(() => "PATCH " + docId); } while (shouldRetry); return result; }
private PatchResultData ApplyPatchInternal(string docId, Etag etag, TransactionInformation transactionInformation, Func<RavenJObject, int, RavenJObject> patcher, bool debugMode) { if (docId == null) throw new ArgumentNullException("docId"); docId = docId.Trim(); var result = new PatchResultData { PatchResult = PatchResult.Patched }; bool shouldRetry = false; int[] retries = { 128 }; do { TransactionalStorage.Batch(actions => { var doc = actions.Documents.DocumentByKey(docId, transactionInformation); if (doc == null) { result.PatchResult = PatchResult.DocumentDoesNotExists; } else if (etag != null && doc.Etag != etag) { Debug.Assert(doc.Etag != null); throw new ConcurrencyException("Could not patch document '" + docId + "' because non current etag was used") { ActualETag = doc.Etag, ExpectedETag = etag, }; } else { var jsonDoc = patcher(doc.ToJson(), doc.SerializedSizeOnDisk); if (debugMode) { result.Document = jsonDoc; result.PatchResult = PatchResult.Tested; } else { try { Put(doc.Key, doc.Etag, jsonDoc, jsonDoc.Value<RavenJObject>("@metadata"), transactionInformation); } catch (ConcurrencyException) { if (retries[0]-- > 0) { shouldRetry = true; return; } throw; } result.PatchResult = PatchResult.Patched; } } if (shouldRetry == false) workContext.ShouldNotifyAboutWork(() => "PATCH " + docId); }); } while (shouldRetry); return result; }
private PatchResultData ApplyPatchInternal(string docId, Etag etag, TransactionInformation transactionInformation, Func<RavenJObject, int, RavenJObject> patcher, Func<RavenJObject> patcherIfMissing, Func<IList<JsonDocument>> getDocsCreatedInPatch, bool debugMode) { if (docId == null) throw new ArgumentNullException("docId"); docId = docId.Trim(); var result = new PatchResultData { PatchResult = PatchResult.Patched }; bool shouldRetry = false; int[] retries = { 128 }; Random rand = null; do { TransactionalStorage.Batch(actions => { var doc = actions.Documents.DocumentByKey(docId, transactionInformation); if (etag != null && doc != null && doc.Etag != etag) { Debug.Assert(doc.Etag != null); throw new ConcurrencyException("Could not patch document '" + docId + "' because non current etag was used") { ActualETag = doc.Etag, ExpectedETag = etag, }; } var jsonDoc = (doc != null ? patcher(doc.ToJson(), doc.SerializedSizeOnDisk) : patcherIfMissing()); if (jsonDoc == null) { result.PatchResult = PatchResult.DocumentDoesNotExists; } else { if (debugMode) { result.Document = jsonDoc; result.PatchResult = PatchResult.Tested; } else { try { Put(doc == null ? docId : doc.Key, (doc == null ? null : doc.Etag), jsonDoc, jsonDoc.Value<RavenJObject>(Constants.Metadata), transactionInformation); var docsCreatedInPatch = getDocsCreatedInPatch(); if (docsCreatedInPatch != null && docsCreatedInPatch.Count > 0) { foreach (var docFromPatch in docsCreatedInPatch) { Put(docFromPatch.Key, docFromPatch.Etag, docFromPatch.DataAsJson, docFromPatch.Metadata, transactionInformation); } } } catch (ConcurrencyException) { if (actions.IsNested) throw; if (retries[0]-- > 0) { shouldRetry = true; if (rand == null) rand = new Random(); Thread.Sleep(rand.Next(5, Math.Max(retries[0] * 2, 10))); return; } throw; } result.PatchResult = PatchResult.Patched; } } if (shouldRetry == false) workContext.ShouldNotifyAboutWork(() => "PATCH " + docId); }); } while (shouldRetry); return result; }