public DatabaseBulkOperations(DocumentDatabase database, TransactionInformation transactionInformation, CancellationTokenSource tokenSource, CancellationTimeout timeout) { this.database = database; this.transactionInformation = transactionInformation; this.tokenSource = tokenSource; this.timeout = timeout; }
public override void OnPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { VersioningConfiguration versioningConfiguration; if (metadata.ContainsKey(Constants.RavenCreateVersion)) { metadata.__ExternalState[Constants.RavenCreateVersion] = metadata[Constants.RavenCreateVersion]; metadata.Remove(Constants.RavenCreateVersion); } if (TryGetVersioningConfiguration(key, metadata, out versioningConfiguration) == false) return; var revision = GetNextRevisionNumber(key); using (Database.DisableAllTriggersForCurrentThread()) { RemoveOldRevisions(key, revision, versioningConfiguration, transactionInformation); } metadata.__ExternalState["Next-Revision"] = revision; metadata.__ExternalState["Parent-Revision"] = metadata.Value<string>(VersioningUtil.RavenDocumentRevision); metadata[VersioningUtil.RavenDocumentRevisionStatus] = RavenJToken.FromObject("Current"); metadata[VersioningUtil.RavenDocumentRevision] = RavenJToken.FromObject(revision); }
public static void AssertNotModifiedByAnotherTransaction(TableStorage storage, ITransactionStorageActions transactionStorageActions, string key, Table.ReadResult readResult, TransactionInformation transactionInformation) { if (readResult == null) return; var txIdAsBytes = readResult.Key.Value<byte[]>("txId"); if (txIdAsBytes == null) return; var txId = new Guid(txIdAsBytes); if (transactionInformation != null && transactionInformation.Id == txId) { return; } var existingTx = storage.Transactions.Read(new RavenJObject { { "txId", txId.ToByteArray() } }); if (existingTx == null)//probably a bug, ignoring this as not a real tx return; var timeout = existingTx.Key.Value<DateTime>("timeout"); if (SystemTime.UtcNow > timeout) { transactionStorageActions.RollbackTransaction(txId); return; } throw new ConcurrencyException("Document '" + key + "' is locked by transacton: " + txId); }
public void AfterCommittingCanSeeChangesWithoutTx() { var transactionInformation = new TransactionInformation { Id = Guid.NewGuid(), Timeout = TimeSpan.FromDays(7) }; using (var tx = NewTransactionalStorage()) { tx.Batch(mutator => mutator.Transactions.AddDocumentInTransaction("Ayende", null, RavenJObject.FromObject(new { Name = "Rahien" }), new RavenJObject(), transactionInformation)); tx.Batch(mutator => mutator.Transactions.CompleteTransaction(transactionInformation.Id, data => { if (data.Delete) { RavenJObject metadata; mutator.Documents.DeleteDocument(data.Key, null, out metadata); } else mutator.Documents.AddDocument(data.Key, null, data.Data, data.Metadata); })); tx.Batch(viewer => Assert.NotNull(viewer.Documents.DocumentByKey("Ayende", null))); } }
public override ReadVetoResult AllowRead(string key, RavenJObject metadata, ReadOperation operation, TransactionInformation transactionInformation) { // This trigger is only for simple query operations if (key == null || operation != ReadOperation.Query) return ReadVetoResult.Allowed; // Don't do anything if temporal versioning is inactive for this document type if (!Database.IsTemporalVersioningEnabled(key, metadata)) return ReadVetoResult.Allowed; // If an effective date was passed in, then use it. DateTimeOffset effective; var headerValue = CurrentOperationContext.Headers.Value[TemporalMetadata.RavenTemporalEffective]; if (headerValue == null || !DateTimeOffset.TryParse(headerValue, null, DateTimeStyles.RoundtripKind, out effective)) { // If no effective data passed, return as stored. return ReadVetoResult.Allowed; } // Return the requested effective date in the metadata. var temporal = metadata.GetTemporalMetadata(); temporal.Effective = effective; // Return the result if it's the active revision, or skip it otherwise. return temporal.Status == TemporalStatus.Revision && temporal.EffectiveStart <= effective && effective < temporal.EffectiveUntil && !temporal.Deleted ? ReadVetoResult.Allowed : ReadVetoResult.Ignore; }
public override void OnPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { if (!metadata.ContainsKey("IsRoutable") || !metadata.Value<bool>("IsRoutable")) { return; } RavenJToken parentIdToken; RavenJToken slugToken; if (document.TryGetValue("ParentId", out parentIdToken) && document.TryGetValue("Slug", out slugToken)) { var parentId = parentIdToken.Value<string>(); var slug = slugToken.Value<string>(); string parentPath = null; if (!String.IsNullOrEmpty(parentId)) { var parent = Database.Get(parentId, transactionInformation); parentPath = parent.DataAsJson["Path"].Value<string>(); } if (String.IsNullOrEmpty(parentPath)) { document["Path"] = slug; } else { document["Path"] = parentPath + "/" + slug; } } base.OnPut(key, document, metadata, transactionInformation); }
public override void OnPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { if (key.StartsWith("Raven/", StringComparison.InvariantCultureIgnoreCase)) return; if (metadata.Value<string>(VersioningUtil.RavenDocumentRevisionStatus) == "Historical") return; var versioningConfiguration = Database.GetDocumentVersioningConfiguration(metadata); if (versioningConfiguration == null || versioningConfiguration.Exclude) return; using (Database.DisableAllTriggersForCurrentThread()) { var copyMetadata = new RavenJObject(metadata); copyMetadata[VersioningUtil.RavenDocumentRevisionStatus] = RavenJToken.FromObject("Historical"); copyMetadata[Constants.RavenReadOnly] = true; copyMetadata.Remove(VersioningUtil.RavenDocumentRevision); var parentRevision = metadata.Value<string>(VersioningUtil.RavenDocumentRevision); if (parentRevision != null) { copyMetadata[VersioningUtil.RavenDocumentParentRevision] = key + "/revisions/" + parentRevision; metadata[VersioningUtil.RavenDocumentParentRevision] = key + "/revisions/" + parentRevision; } PutResult newDoc = Database.Put(key + "/revisions/", null, document, copyMetadata, transactionInformation); int revision = int.Parse(newDoc.Key.Split('/').Last()); RemoveOldRevisions(key, revision, versioningConfiguration, transactionInformation); metadata[VersioningUtil.RavenDocumentRevisionStatus] = RavenJToken.FromObject("Current"); metadata[VersioningUtil.RavenDocumentRevision] = RavenJToken.FromObject(revision); } }
public override VetoResult AllowDelete(string key, TransactionInformation transactionInformation) { if (key == Constants.InResourceKeyVerificationDocumentName) return VetoResult.Deny("Cannot delete the encryption verification document."); return base.AllowDelete(key, transactionInformation); }
public override void AfterPut(string key, RavenJObject document, RavenJObject metadata, Etag etag, TransactionInformation transactionInformation) { if (key.StartsWith("Raven/", StringComparison.InvariantCultureIgnoreCase)) return; var status = document.Value<string>("Status"); if (string.IsNullOrWhiteSpace(status) || !status.Equals("Published", StringComparison.InvariantCultureIgnoreCase)) return; if (metadata.Value<string>(PublishedVersioningConstants.AtisDocumentRevisionStatus) == "Historical") return; using (Database.DisableAllTriggersForCurrentThread()) { var copyMetadata = new RavenJObject(metadata); copyMetadata[PublishedVersioningConstants.AtisDocumentRevisionStatus] = RavenJToken.FromObject("Historical"); copyMetadata[Constants.RavenReadOnly] = true; copyMetadata.Remove(PublishedVersioningConstants.AtisDocumentRevision); object value; metadata.__ExternalState.TryGetValue("Next-Revision", out value); var revisionKey = string.Format("{0}/PublishedRevisions/{1}", key, value); Database.Put(revisionKey, null, (RavenJObject)document.CreateSnapshot(), copyMetadata, transactionInformation); log.Debug(() => string.Format("Created published revision with key [{0}]", revisionKey)); } }
/// <summary> /// Called when [put]. /// </summary> /// <param name="key">The key.</param> /// <param name="document">The document.</param> /// <param name="metadata">The metadata.</param> /// <param name="transactionInformation">The transaction information.</param> public override void OnPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { if (key.StartsWith("Raven/",true,CultureInfo.InvariantCulture)) // we don't deal with system documents return; if (TriggerContext.IsInTriggerContext) return; using (TriggerContext.Enter()) { var meta = document["MetaData"] as RavenJObject; if(meta != null) { var slug = meta.Value<string>("Slug"); RavenJToken parent; if (document.TryGetValue("Parent", out parent) && parent.Type != JTokenType.Null) { var parentId = parent.Value<string>("Id"); var parentDocument = Database.Get(parentId, transactionInformation); var parentUrl = parentDocument.DataAsJson.Value<JObject>("Metadata").Value<string>("Url"); if (parentUrl != null) { meta["Url"] = string.Format("{0}/{1}", parentUrl, slug); base.OnPut(key, document, metadata, transactionInformation); return; } } meta["Url"] = slug; } } base.OnPut(key, document, metadata, transactionInformation); }
public override void OnPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { if (key.StartsWith("Raven/")) // we don't deal with system documents return; var doc = Database.Get(key, null); if (doc != null) { var history = doc.Metadata.Value<RavenJArray>(ReplicationConstants.RavenReplicationHistory) ?? new RavenJArray(); metadata[ReplicationConstants.RavenReplicationHistory] = history; history.Add(new RavenJObject { {ReplicationConstants.RavenReplicationVersion, doc.Metadata[ReplicationConstants.RavenReplicationVersion]}, {ReplicationConstants.RavenReplicationSource, doc.Metadata[ReplicationConstants.RavenReplicationSource]} }); if (history.Length > ReplicationConstants.ChangeHistoryLength) { history.RemoveAt(0); } } metadata[ReplicationConstants.RavenReplicationVersion] = RavenJToken.FromObject(hiLo.NextId()); metadata[ReplicationConstants.RavenReplicationSource] = RavenJToken.FromObject(Database.TransactionalStorage.Id); }
private void RecursiveDelete(string key, TransactionInformation transactionInformation) { var document = Database.Documents.Get(key, transactionInformation); if (document == null) return; var documentsToDelete = document.Metadata.Value<RavenJArray>(MetadataKeys.DocumentsToCascadeDelete); if (documentsToDelete != null) { foreach (var documentToDelete in documentsToDelete) { var documentId = documentToDelete.Value<string>(); if (!CascadeDeleteContext.HasAlreadyDeletedDocument(documentId)) { CascadeDeleteContext.AddDeletedDocument(documentId); RecursiveDelete(documentId, transactionInformation); Database.Documents.Delete(documentId, null, transactionInformation); } } } var attachmentsToDelete = document.Metadata.Value<RavenJArray>(MetadataKeys.AttachmentsToCascadeDelete); if (attachmentsToDelete != null) foreach (var attachmentToDelete in attachmentsToDelete) Database.Attachments.DeleteStatic(attachmentToDelete.Value<string>(), null); return; }
public long GetNextIdentityValueWithoutOverwritingOnExistingDocuments(string key, IStorageActionsAccessor actions, TransactionInformation transactionInformation) { int tries; return GetNextIdentityValueWithoutOverwritingOnExistingDocuments(key, actions, transactionInformation, out tries); }
public override VetoResult AllowPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { // always reset these _clearCurrent.Value = false; _originalDocument.Value = null; _now.Value = SystemTime.UtcNow; if (key == null) return VetoResult.Allowed; // Don't do anything if temporal versioning is inactive for this document type if (!Database.IsTemporalVersioningEnabled(key, metadata)) return VetoResult.Allowed; // Don't allow modifications to revision documents if (key.Contains(TemporalConstants.TemporalKeySeparator)) return VetoResult.Deny("Modifying an existing temporal revision directly is not allowed."); // If no effective date was passed in, use now. var temporal = metadata.GetTemporalMetadata(); if (!temporal.Effective.HasValue) temporal.Effective = _now.Value; return VetoResult.Allowed; }
public override void OnDelete(string key, TransactionInformation transactionInformation) { if (CascadeDeleteContext.IsInCascadeDeleteContext) return; var document = Database.Get(key, transactionInformation); if (document == null) return; using (CascadeDeleteContext.Enter()) { var documentsToDelete = document.Metadata.Value<RavenJArray>(MetadataKeys.DocumentsToCascadeDelete); if (documentsToDelete != null) { foreach (var documentToDelete in documentsToDelete) { var documentId = documentToDelete.Value<string>(); if (!CascadeDeleteContext.HasAlreadyDeletedDocument(documentId)) { CascadeDeleteContext.AddDeletedDocument(documentId); Database.Delete(documentId, null, transactionInformation); } } } var attachmentsToDelete = document.Metadata.Value<RavenJArray>(MetadataKeys.AttachmentsToCascadeDelete); if (attachmentsToDelete != null) foreach (var attachmentToDelete in attachmentsToDelete) Database.DeleteStatic(attachmentToDelete.Value<string>(), null); } }
public override void OnPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { if (key.StartsWith("Raven/", StringComparison.OrdinalIgnoreCase) && // we don't deal with system documents key.StartsWith("Raven/Hilo/", StringComparison.OrdinalIgnoreCase) == false) // except for hilos return; using (Database.DisableAllTriggersForCurrentThread()) { var documentMetadata = GetDocumentMetadata(key); if (documentMetadata != null) { RavenJArray history = new RavenJArray(ReplicationData.GetHistory(documentMetadata)); metadata[Constants.RavenReplicationHistory] = history; if (documentMetadata.ContainsKey(Constants.RavenReplicationVersion) && documentMetadata.ContainsKey(Constants.RavenReplicationSource)) { history.Add(new RavenJObject { {Constants.RavenReplicationVersion, documentMetadata[Constants.RavenReplicationVersion]}, {Constants.RavenReplicationSource, documentMetadata[Constants.RavenReplicationSource]} }); } while (history.Length > Constants.ChangeHistoryLength) { history.RemoveAt(0); } } metadata[Constants.RavenReplicationVersion] = RavenJToken.FromObject(HiLo.NextId()); metadata[Constants.RavenReplicationSource] = RavenJToken.FromObject(Database.TransactionalStorage.Id); } }
public override void AfterDelete(string key, TransactionInformation transactionInformation) { var versioningConfig = Database.GetDocumentVersioningConfiguration(versionInformer.Value[key]); using (Database.DisableAllTriggersForCurrentThread()) { Database.TransactionalStorage.Batch(accessor => { using (DocumentCacher.SkipSetDocumentsInDocumentCache()) { foreach (var jsonDocument in accessor.Documents.GetDocumentsWithIdStartingWith(key + "/revisions/", 0, int.MaxValue, null)) { if (jsonDocument == null) continue; if (versioningConfig != null && versioningConfig.PurgeOnDelete) { Database.Documents.Delete(jsonDocument.Key, null, transactionInformation); } else { jsonDocument.Metadata.Remove(Constants.RavenReadOnly); accessor.Documents.AddDocument(jsonDocument.Key, jsonDocument.Etag, jsonDocument.DataAsJson, jsonDocument.Metadata); } } } }); } }
public void CanModifyTxId() { var transactionInformation = new TransactionInformation { Id = Guid.NewGuid(), Timeout = TimeSpan.FromDays(7) }; using (var tx = NewTransactionalStorage()) { tx.Batch(mutator => mutator.Transactions.AddDocumentInTransaction("Ayende", null, RavenJObject.FromObject(new { Name = "Rahien" }), new RavenJObject(), transactionInformation)); var txInfo2 = new TransactionInformation { Id = Guid.NewGuid(), Timeout = TimeSpan.FromDays(1) }; tx.Batch(mutator => mutator.Transactions.ModifyTransactionId(transactionInformation.Id, txInfo2.Id, txInfo2.Timeout)); tx.Batch(viewer => Assert.NotNull(viewer.Documents.DocumentByKey("Ayende", txInfo2))); } }
public void Delete(string key, Guid?etag, TransactionInformation transactionInformation) { log.DebugFormat("Delete a document with key: {0} and etag {1}", key, etag); TransactionalStorage.Batch(actions => { if (transactionInformation == null) { AssertDeleteOperationNotVetoed(key, transactionInformation); DeleteTriggers.Apply(trigger => trigger.OnDelete(key, transactionInformation)); RavenJObject metadata; if (actions.Documents.DeleteDocument(key, etag, out metadata)) { AddIndexingTask(actions, metadata, () => new RemoveFromIndexTask { Keys = new[] { key } }); DeleteTriggers.Apply(trigger => trigger.AfterDelete(key, transactionInformation)); } } else { actions.Transactions.DeleteDocumentInTransaction(transactionInformation, key, etag); } workContext.ShouldNotifyAboutWork(); }); TransactionalStorage .ExecuteImmediatelyOrRegisterForSyncronization(() => DeleteTriggers.Apply(trigger => trigger.AfterCommit(key))); }
public override VetoResult AllowPut(string key, Raven.Json.Linq.RavenJObject document, Raven.Json.Linq.RavenJObject metadata, TransactionInformation transactionInformation) { if (key == "Raven/Authorization/WindowsSettings" && Authentication.IsEnabled == false) return VetoResult.Deny("Cannot setup Windows Authentication without a valid commercial license."); return VetoResult.Allowed; }
public bool RecoverTransaction(string id, IEnumerable <DocumentInTransactionData> changes) { var txInfo = new TransactionInformation { Id = id, Timeout = TimeSpan.FromMinutes(5) }; if (changes == null) { log.Warn("Failed to prepare transaction " + id + " because changes were null, maybe this is a partially committed transaction? Transaction will be rolled back"); return(false); } foreach (var changedDoc in changes) { if (changedDoc == null) { log.Warn("Failed preparing a document change in transaction " + id + " with a null change, maybe this is partiall committed transaction? Transaction will be rolled back"); return(false); } changedDoc.Metadata.EnsureCannotBeChangeAndEnableSnapshotting(); changedDoc.Data.EnsureCannotBeChangeAndEnableSnapshotting(); //we explicitly pass a null for the etag here, because we might have calls for TouchDocument() //that happened during the transaction, which changed the committed etag. That is fine when we are just running //the transaction, since we can just report the error and abort. But it isn't fine when we recover //var etag = changedDoc.CommittedEtag; Etag etag = null; AddToTransactionState(changedDoc.Key, null, txInfo, etag, changedDoc); } return(true); }
private void HandleConflictedDocument(JsonDocument document, TransactionInformation transactionInformation) { var conflicts = document.DataAsJson.Value<RavenJArray>("Conflicts"); var currentSource = Database.TransactionalStorage.Id.ToString(); foreach (var c in conflicts) { var conflict = Database.Get(c.Value<string>(), transactionInformation); var conflictSource = conflict.Metadata.Value<RavenJValue>(Constants.RavenReplicationSource).Value<string>(); if (conflictSource != currentSource) continue; this.deletedHistory.Value = new RavenJArray { new RavenJObject { { Constants.RavenReplicationVersion, conflict.Metadata[Constants.RavenReplicationVersion] }, { Constants.RavenReplicationSource, conflict.Metadata[Constants.RavenReplicationSource] } } }; return; } }
private bool TryGetInternal <T>(string key, TransactionInformation transactionInformation, Func <string, DocumentInTransactionData, T> createDoc, out T document) where T : class { TransactionState state; if (transactionStates.TryGetValue(transactionInformation.Id, out state) == false) { document = null; return(false); } var change = state.changes.LastOrDefault(x => string.Equals(x.Key, key, StringComparison.InvariantCultureIgnoreCase)); if (change == null) { document = null; return(false); } if (change.Delete) { document = null; return(true); } document = createDoc(key, change); return(true); }
public override VetoResult AllowDelete(string key, TransactionInformation transactionInformation) { var document = Database.Documents.Get(key, transactionInformation); if (document == null) return VetoResult.Allowed; versionInformer.Value[key] = document.Metadata; if (document.Metadata.Value<string>(VersioningUtil.RavenDocumentRevisionStatus) != "Historical") return VetoResult.Allowed; if (Database.ChangesToRevisionsAllowed() == false && Database.IsVersioningActive(document.Metadata)) { var revisionPos = key.LastIndexOf("/revisions/", StringComparison.OrdinalIgnoreCase); if (revisionPos != -1) { var parentKey = key.Remove(revisionPos); var parentDoc = Database.Documents.Get(parentKey, transactionInformation); if (parentDoc == null) return VetoResult.Allowed; } return VetoResult.Deny("Deleting a historical revision is not allowed"); } return VetoResult.Allowed; }
private void HandleConflictedDocument(JsonDocument document, TransactionInformation transactionInformation) { var conflicts = document.DataAsJson.Value<RavenJArray>("Conflicts"); var currentSource = Database.TransactionalStorage.Id.ToString(); var historySet = false; foreach (var c in conflicts) { RavenJObject conflict; if (Database.Documents.Delete(c.Value<string>(), null, transactionInformation, out conflict) == false) continue; if (historySet) continue; var conflictSource = conflict.Value<RavenJValue>(Constants.RavenReplicationSource).Value<string>(); if (conflictSource != currentSource) continue; deletedHistory.Value = new RavenJArray { new RavenJObject { { Constants.RavenReplicationVersion, conflict[Constants.RavenReplicationVersion] }, { Constants.RavenReplicationSource, conflict[Constants.RavenReplicationSource] } } }; historySet = true; } }
public override void OnPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { if (key.StartsWith("Raven/", StringComparison.InvariantCultureIgnoreCase) && // we don't deal with system documents key.StartsWith("Raven/Hilo/", StringComparison.InvariantCultureIgnoreCase) == false) // except for hilos return; using (Database.DisableAllTriggersForCurrentThread()) { var doc = Database.Get(key, null); if (doc != null) { var history = doc.Metadata.Value<RavenJArray>(ReplicationConstants.RavenReplicationHistory) ?? new RavenJArray(); metadata[ReplicationConstants.RavenReplicationHistory] = history; if (doc.Metadata.ContainsKey(ReplicationConstants.RavenReplicationVersion) && doc.Metadata.ContainsKey(ReplicationConstants.RavenReplicationSource)) { history.Add(new RavenJObject { {ReplicationConstants.RavenReplicationVersion, doc.Metadata[ReplicationConstants.RavenReplicationVersion]}, {ReplicationConstants.RavenReplicationSource, doc.Metadata[ReplicationConstants.RavenReplicationSource]} }); } if (history.Length > ReplicationConstants.ChangeHistoryLength) { history.RemoveAt(0); } } metadata[ReplicationConstants.RavenReplicationVersion] = RavenJToken.FromObject(HiLo.NextId()); metadata[ReplicationConstants.RavenReplicationSource] = RavenJToken.FromObject(Database.TransactionalStorage.Id); } }
/// <summary> /// Called when [delete]. /// </summary> /// <param name="key">The key.</param> /// <param name="transactionInformation">The transaction information.</param> public override void OnDelete(string key, TransactionInformation transactionInformation) { if (key.StartsWith("Raven/")) // we don't deal with system documents return; var childrenQuery = new IndexQuery { Query = "Id:" + key }; var queryResult = Database.Query("Documents/ByParent", childrenQuery); if (queryResult.Results.Count > 0) { foreach (var result in queryResult.Results) { var metadataJObject = result.Value<RavenJObject>("@metadata"); if (metadataJObject != null) { var childId = metadataJObject.Value<string>("@id"); var childEtag = metadataJObject.Value<string>("@etag"); Database.Delete(childId, Guid.Parse(childEtag), transactionInformation); } } } base.OnDelete(key, transactionInformation); }
public override void OnPut(string key, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { if (metadata["Document-Owner"] == null) // user didn't explicitly set it { // modify the metadata to the current user metadata["Document-Owner"] = RavenJObject.FromObject(Thread.CurrentPrincipal.Identity.Name); } }
public override ReadVetoResult AllowRead(string key, RavenJObject metadata, ReadOperation operation, TransactionInformation transactionInformation) { if (operation != ReadOperation.Index) return ReadVetoResult.Allowed; if (metadata.ContainsKey("Deleted") == false) return ReadVetoResult.Allowed; return ReadVetoResult.Ignore; }
public override void OnRead(string key, RavenJObject document, RavenJObject metadata, ReadOperation operation, TransactionInformation transactionInformation) { var name = document["name"]; if (name != null) { document["name"] = new RavenJValue(name.Value<string>().ToUpper()); } }
private void RemoveOldRevisions(string key, int revision, VersioningConfiguration versioningConfiguration, TransactionInformation transactionInformation) { int latestValidRevision = revision - versioningConfiguration.MaxRevisions; if (latestValidRevision <= 0) return; Database.Delete(string.Format("{0}/revisions/{1}", key, latestValidRevision), null, transactionInformation); }
private void RemoveOldRevisions(string key, int revision, VersioningConfiguration versioningConfiguration, TransactionInformation transactionInformation) { int latestValidRevision = revision - versioningConfiguration.MaxRevisions; if (latestValidRevision <= 1) return; Database.Delete(key + "/revisions/" + (latestValidRevision - 1), null, transactionInformation); }
private Etag AddToTransactionState(string key, Etag etag, TransactionInformation transactionInformation, Etag committedEtag, DocumentInTransactionData item) { try { var state = transactionStates.GetOrAdd(transactionInformation.Id, id => new TransactionState()); lock (state) { state.LastSeen = new Reference <DateTime> { Value = SystemTime.UtcNow }; state.Timeout = transactionInformation.Timeout; var currentTxVal = state.Changes.LastOrDefault(x => string.Equals(x.Key, key, StringComparison.InvariantCultureIgnoreCase)); if (currentTxVal != null) { EnsureValidEtag(key, etag, committedEtag, currentTxVal); state.Changes.Remove(currentTxVal); } var result = changedInTransaction.AddOrUpdate(key, s => { EnsureValidEtag(key, etag, committedEtag, currentTxVal); return(new ChangedDoc { transactionId = transactionInformation.Id, committedEtag = committedEtag, currentEtag = item.Etag }); }, (_, existing) => { if (existing.transactionId == transactionInformation.Id) { EnsureValidEtag(key, etag, committedEtag, currentTxVal); existing.currentEtag = item.Etag; return(existing); } throw new ConcurrencyException("Document " + key + " is being modified by another transaction: " + existing); }); state.Changes.Add(item); return(result.currentEtag); } } catch (Exception) { Rollback(transactionInformation.Id); throw; } }
private void AssertDeleteOperationNotVetoed(string key, TransactionInformation transactionInformation) { var vetoResult = DeleteTriggers .Select(trigger => new { Trigger = trigger, VetoResult = trigger.AllowDelete(key, transactionInformation) }) .FirstOrDefault(x => x.VetoResult.IsAllowed == false); if (vetoResult != null) { throw new OperationVetoedException("DELETE vetoed by " + vetoResult.Trigger + " because: " + vetoResult.VetoResult.Reason); } }
public bool TryGet(string key, TransactionInformation transactionInformation, out JsonDocumentMetadata document) { return(TryGetInternal(key, transactionInformation, (theKey, change) => new JsonDocumentMetadata { Metadata = (RavenJObject)change.Metadata.CreateSnapshot(), Key = theKey, Etag = change.Etag, NonAuthoritativeInformation = false, LastModified = change.LastModified }, out document)); }
public JsonDocumentMetadata GetDocumentMetadata(string key, TransactionInformation transactionInformation) { JsonDocumentMetadata document = null; TransactionalStorage.Batch(actions => { document = actions.Documents.DocumentMetadataByKey(key, transactionInformation); }); DocumentRetriever.EnsureIdInMetadata(document); return(new DocumentRetriever(null, ReadTriggers) .ProcessReadVetoes(document, transactionInformation, ReadOperation.Load)); }
public void DeleteDocumentInTransaction( TransactionInformation transactionInformation, string key, Etag etag, Etag committedEtag, SequentialUuidGenerator uuidGenerator) { AddToTransactionState(key, etag, transactionInformation, committedEtag, new DocumentInTransactionData { Delete = true, Key = key, LastModified = SystemTime.UtcNow }); }
public void CanGetErrorOnOptimisticDeleteInTransaction() { using (var store = NewDocumentStore()) { using (var session = store.OpenSession()) { session.Store(new Item()); session.SaveChanges(); } var tx = new TransactionInformation { Id = Guid.NewGuid().ToString() }; Assert.Throws <ConcurrencyException>(() => store.DocumentDatabase.Delete("items/1", Etag.InvalidEtag, tx)); } }
public void CanGetErrorOnOptimisticDeleteInTransactionWhenModifiedInTransaction() { using (var store = NewDocumentStore()) { using (var session = store.OpenSession()) { session.Store(new Item()); session.SaveChanges(); } var tx = new TransactionInformation { Id = Guid.NewGuid() }; store.DocumentDatabase.Put("items/1", null, new RavenJObject(), new RavenJObject(), tx); Assert.Throws <ConcurrencyException>(() => store.DocumentDatabase.Delete("items/1", Guid.NewGuid(), tx)); } }
public void CanGetErrorOnOptimisticDeleteInTransactionWhenDeletedInTransaction() { using (var store = NewDocumentStore(requestedStorage: "esent")) { EnsureDtcIsSupported(store); using (var session = store.OpenSession()) { session.Store(new Item()); session.SaveChanges(); } var tx = new TransactionInformation { Id = Guid.NewGuid().ToString() }; store.SystemDatabase.Documents.Delete("items/1", null, tx); Assert.Throws <ConcurrencyException>(() => store.SystemDatabase.Documents.Delete("items/1", Etag.InvalidEtag, tx)); } }
public void RecoverTransaction(string id, IEnumerable <DocumentInTransactionData> changes) { var txInfo = new TransactionInformation { Id = id, Timeout = TimeSpan.FromMinutes(5) }; foreach (var changedDoc in changes) { changedDoc.Metadata.EnsureCannotBeChangeAndEnableSnapshotting(); changedDoc.Data.EnsureCannotBeChangeAndEnableSnapshotting(); //we explicitly pass a null for the etag here, because we might have calls for TouchDocument() //that happened during the transaction, which changed the committed etag. That is fine when we are just running //the transaction, since we can just report the error and abort. But it isn't fine when we recover //var etag = changedDoc.CommittedEtag; Etag etag = null; AddToTransactionState(changedDoc.Key, null, txInfo, etag, changedDoc); } }
public void ConcurrentDtcTransactions() { using (var store = NewDocumentStore(requestedStorage: "esent")) { var documentDatabase = store.SystemDatabase; var tx1 = new TransactionInformation { Id = "tx1", Timeout = TimeSpan.FromHours(1) }; var tx2 = new TransactionInformation { Id = "tx2", Timeout = TimeSpan.FromHours(1) }; documentDatabase.Documents.Put("test/1", null, new RavenJObject(), new RavenJObject(), tx1); documentDatabase.Documents.Put("test/2", null, new RavenJObject(), new RavenJObject(), tx1); documentDatabase.Documents.Put("test/3", null, new RavenJObject(), new RavenJObject(), tx2); documentDatabase.Documents.Put("test/4", null, new RavenJObject(), new RavenJObject(), tx2); documentDatabase.PrepareTransaction("tx1"); documentDatabase.PrepareTransaction("tx2"); documentDatabase.Commit("tx2"); WaitForIndexing(documentDatabase); documentDatabase.Commit("tx1"); WaitForIndexing(documentDatabase); var queryResult = store.DatabaseCommands.Query("Raven/DocumentsByEntityName", new IndexQuery(), null); Assert.Equal(4, queryResult.TotalResults); } }
public Etag AddDocumentInTransaction( string key, Etag etag, RavenJObject data, RavenJObject metadata, TransactionInformation transactionInformation, Etag committedEtag, SequentialUuidGenerator uuidGenerator) { metadata.EnsureCannotBeChangeAndEnableSnapshotting(); data.EnsureCannotBeChangeAndEnableSnapshotting(); return(AddToTransactionState(key, etag, transactionInformation, committedEtag, new DocumentInTransactionData { Metadata = metadata, Data = data, Delete = false, Key = key, LastModified = SystemTime.UtcNow, Etag = uuidGenerator.CreateSequentialUuid(UuidType.DocumentTransactions) })); }
public Func <TDocument, TDocument> GetNonAuthoritativeInformationBehavior <TDocument>(TransactionInformation tx, string key) where TDocument : class, IJsonDocumentMetadata, new() { ChangedDoc existing; if (changedInTransaction.TryGetValue(key, out existing) == false || (tx != null && tx.Id == existing.transactionId)) { return(null); } return(document => { if (document == null) { return new TDocument { Key = key, Metadata = new RavenJObject { { Constants.RavenDocumentDoesNotExists, true } }, LastModified = DateTime.MinValue, NonAuthoritativeInformation = true, Etag = Etag.Empty }; } document.NonAuthoritativeInformation = true; return document; }); }
public override void AfterPut(string key, Raven.Json.Linq.RavenJObject document, Raven.Json.Linq.RavenJObject metadata, Etag etag, Raven.Abstractions.Data.TransactionInformation transactionInformation) { if (key == "Raven/Authorization/WindowsSettings") { WindowsRequestAuthorizer.InvokeWindowsSettingsChanged(); } base.AfterPut(key, document, metadata, etag, transactionInformation); }
private Etag AddToTransactionState(string key, Etag etag, TransactionInformation transactionInformation, Etag committedEtag, DocumentInTransactionData item) { try { TransactionState state; if (transactionStates.TryGetValue(transactionInformation.Id, out state) == false) { lock (modifyTransactionStates) { if (transactionStates.TryGetValue(transactionInformation.Id, out state) == false) // check it once again, after we retrieved the lock - could be added while we waited for the lock { state = new TransactionState(); transactionStates = transactionStates.Add(transactionInformation.Id, state); } } } lock (state) { state.LastSeen = new Reference <DateTime> { Value = SystemTime.UtcNow }; state.Timeout = transactionInformation.Timeout; var currentTxVal = state.Changes.LastOrDefault(x => string.Equals(x.Key, key, StringComparison.InvariantCultureIgnoreCase)); if (currentTxVal != null) { EnsureValidEtag(key, etag, committedEtag, currentTxVal); state.Changes.Remove(currentTxVal); } ChangedDoc result; lock (modifyChangedInTransaction) { if (changedInTransaction.TryGetValue(key, out result)) { if (result.transactionId != transactionInformation.Id) { throw new ConcurrencyException("Document " + key + " is being modified by another transaction: " + result); } EnsureValidEtag(key, etag, committedEtag, currentTxVal); result.currentEtag = item.Etag; } else { EnsureValidEtag(key, etag, committedEtag, currentTxVal); result = new ChangedDoc { transactionId = transactionInformation.Id, committedEtag = committedEtag, currentEtag = item.Etag }; changedInTransaction = changedInTransaction.Add(key, result); } } state.Changes.Add(item); return(result.currentEtag); } } catch (Exception) { Rollback(transactionInformation.Id); throw; } }
public PatchResult ApplyPatch(string docId, Guid?etag, PatchRequest[] patchDoc, TransactionInformation transactionInformation) { var result = PatchResult.Patched; TransactionalStorage.Batch(actions => { var doc = actions.Documents.DocumentByKey(docId, transactionInformation); if (doc == null) { result = PatchResult.DocumentDoesNotExists; } else if (etag != null && doc.Etag != etag.Value) { Debug.Assert(doc.Etag != null); throw new ConcurrencyException("Could not patch document '" + docId + "' because non current etag was used") { ActualETag = doc.Etag.Value, ExpectedETag = etag.Value, }; } else { var jsonDoc = doc.ToJson(); new JsonPatcher(jsonDoc).Apply(patchDoc); Put(doc.Key, doc.Etag, jsonDoc, jsonDoc.Value <RavenJObject>("@metadata"), transactionInformation); result = PatchResult.Patched; } workContext.ShouldNotifyAboutWork(); }); return(result); }
private void AssertPutOperationNotVetoed(string key, RavenJObject metadata, RavenJObject document, TransactionInformation transactionInformation) { var vetoResult = PutTriggers .Select(trigger => new { Trigger = trigger, VetoResult = trigger.AllowPut(key, document, metadata, transactionInformation) }) .FirstOrDefault(x => x.VetoResult.IsAllowed == false); if (vetoResult != null) { throw new OperationVetoedException("PUT vetoed by " + vetoResult.Trigger + " because: " + vetoResult.VetoResult.Reason); } }
public PutResult Put(string key, Guid?etag, RavenJObject document, RavenJObject metadata, TransactionInformation transactionInformation) { if (key != null && Encoding.Unicode.GetByteCount(key) >= 255) { throw new ArgumentException("The key must be a maximum of 255 bytes in unicode, 127 characters", "key"); } log.DebugFormat("Putting a document with key: {0} and etag {1}", key, etag); if (string.IsNullOrEmpty(key)) { // we no longer sort by the key, so it doesn't matter // that the key is no longer sequential key = Guid.NewGuid().ToString(); } RemoveReservedProperties(document); RemoveReservedProperties(metadata); Guid newEtag = Guid.Empty; lock (this) { TransactionalStorage.Batch(actions => { if (key.EndsWith("/")) { key += actions.General.GetNextIdentityValue(key); } if (transactionInformation == null) { AssertPutOperationNotVetoed(key, metadata, document, transactionInformation); PutTriggers.Apply(trigger => trigger.OnPut(key, document, metadata, transactionInformation)); newEtag = actions.Documents.AddDocument(key, etag, document, metadata); // We detect this by using the etags // AddIndexingTask(actions, metadata, () => new IndexDocumentsTask { Keys = new[] { key } }); PutTriggers.Apply(trigger => trigger.AfterPut(key, document, metadata, newEtag, transactionInformation)); } else { newEtag = actions.Transactions.AddDocumentInTransaction(key, etag, document, metadata, transactionInformation); } workContext.ShouldNotifyAboutWork(); }); } TransactionalStorage .ExecuteImmediatelyOrRegisterForSyncronization(() => PutTriggers.Apply(trigger => trigger.AfterCommit(key, document, metadata, newEtag))); return(new PutResult { Key = key, ETag = newEtag }); }
public override void AfterPut(string key, RavenJObject document, RavenJObject metadata, Etag etag, TransactionInformation transactionInformation) { VersioningConfiguration versioningConfiguration; if (TryGetVersioningConfiguration(key, metadata, out versioningConfiguration) == false) return; using (Database.DisableAllTriggersForCurrentThread()) { var copyMetadata = new RavenJObject(metadata); copyMetadata[VersioningUtil.RavenDocumentRevisionStatus] = RavenJToken.FromObject("Historical"); copyMetadata[Constants.RavenReadOnly] = true; copyMetadata.Remove(VersioningUtil.RavenDocumentRevision); object parentRevision; metadata.__ExternalState.TryGetValue("Parent-Revision", out parentRevision); if (parentRevision != null) { copyMetadata[VersioningUtil.RavenDocumentParentRevision] = key + "/revisions/" + parentRevision; copyMetadata[VersioningUtil.RavenDocumentParentRevision] = key + "/revisions/" + parentRevision; } object value; metadata.__ExternalState.TryGetValue("Next-Revision", out value); Database.Put(key + "/revisions/" + value, null, (RavenJObject)document.CreateSnapshot(), copyMetadata, transactionInformation); } }