public void Sync() { using (var store = new DocumentStore()) { #region open_cluster_session_sync using (var session = store.OpenSession(new SessionOptions { TransactionMode = TransactionMode.ClusterWide })) #endregion { #region new_compare_exchange_sync // occupy "Best NoSQL Transactional Database" to be "RavenDB" session.Advanced.ClusterTransaction.CreateCompareExchangeValue(key: "Best NoSQL Transactional Database", value: "RavenDB"); session.SaveChanges(); #endregion #region update_compare_exchange_sync // load the existing dns record of ravendb.net CompareExchangeValue <DNS> result = session.Advanced.ClusterTransaction.GetCompareExchangeValue <DNS>(key: "ravendb.net"); // change the ip result.Value.IpAddress = "52.32.173.150"; session.Advanced.ClusterTransaction.UpdateCompareExchangeValue(result); // save the changes session.SaveChanges(); #endregion var key = "key"; var keys = new[] { "key" }; var index = 0L; var value = default(T); #region methods_1_sync session.Advanced.ClusterTransaction.GetCompareExchangeValue <T>(key); #endregion #region methods_2_sync session.Advanced.ClusterTransaction.GetCompareExchangeValues <T>(keys); #endregion #region methods_3_sync session.Advanced.ClusterTransaction.CreateCompareExchangeValue(key, value); #endregion #region methods_4_sync session.Advanced.ClusterTransaction.DeleteCompareExchangeValue(key, index); #endregion #region methods_5_sync session.Advanced.ClusterTransaction.UpdateCompareExchangeValue(new CompareExchangeValue <T>(key, index, value)); #endregion } } }
public CompareExchangeSessionValue(CompareExchangeValue <BlittableJsonReaderObject> value) : this(value.Key, value.Index, value.Index >= 0 ? CompareExchangeValueState.None : CompareExchangeValueState.Missing) { if (value.Index > 0) { _originalValue = value; } }
public void DeleteCompareExchangeValue <T>(CompareExchangeValue <T> item) { EnsureNotStored(item.Key); if (_deleteCompareExchange == null) { _deleteCompareExchange = new Dictionary <string, long>(); } _deleteCompareExchange[item.Key] = item.Index; }
public void UpdateCompareExchangeValue <T>(CompareExchangeValue <T> item) { EnsureNotDeleted(item.Key); if (_storeCompareExchange == null) { _storeCompareExchange = new Dictionary <string, StoredCompareExchange>(); } _storeCompareExchange[item.Key] = new StoredCompareExchange(item.Index, item.Value); }
internal CompareExchangeValue <T> Create <T>(T item) { AssertState(); if (_value != null) { throw new InvalidOperationException($"The compare exchange value with key '{_key}' is already tracked."); } _index = 0; var value = new CompareExchangeValue <T>(_key, _index, item); _value = value; _state = CompareExchangeValueState.Created; return(value); }
public IActionResult Run(RunParams runParams) { string cmpXchgKey = runParams.CmpXchgKey ?? "*****@*****.**"; string cmpXchgValue = runParams.CmpXchgValue ?? "employee/1-A"; string result = null; #region Demo #region Step_1 var putCmpXchgOperation = new PutCompareExchangeValueOperation <string>(cmpXchgKey, cmpXchgValue, 0); CompareExchangeResult <string> putCmpXchgResult = DocumentStoreHolder.Store.Operations.Send(putCmpXchgOperation); #endregion #region Step_2 var success = putCmpXchgResult.Successful; var putValue = putCmpXchgResult.Value; var putVersion = putCmpXchgResult.Index; if (success == false) { result = "Key already exists"; } #endregion #region Step_3 var getCmpXchgOperation = new GetCompareExchangeValueOperation <string>(cmpXchgKey); CompareExchangeValue <string> getCmpXchgResult = DocumentStoreHolder.Store.Operations.Send(getCmpXchgOperation); #endregion #region Step_4 var key = getCmpXchgResult.Key; var currentValue = getCmpXchgResult.Value; var currentValueVersion = getCmpXchgResult.Index; var currentMetadata = getCmpXchgResult.Metadata; #endregion #endregion result = result ?? $"Created a new Compare-Exchange Key: {key}, Value: {currentValue}, Value Version: {currentValueVersion}"; return(Ok(result)); }
internal void UpdateValue(CompareExchangeValue <BlittableJsonReaderObject> value, InMemoryDocumentSessionOperations session) { _index = value.Index; _state = value.Index >= 0 ? CompareExchangeValueState.None : CompareExchangeValueState.Missing; _originalValue = value; if (_value != null) { _value.Index = _index; if (_value.Value != null) { session.JsonConverter.PopulateEntity(_value.Value, value.Value, session.JsonSerializer); } } }
internal CompareExchangeValue <T> GetValue <T>(DocumentConventions conventions) { switch (_state) { case CompareExchangeValueState.None: case CompareExchangeValueState.Created: { if (_value is CompareExchangeValue <T> v) { return(v); } if (_value != null) { throw new InvalidOperationException("Value cannot be null."); } T entity = default; if (_originalValue != null && _originalValue.Value != null) { var type = typeof(T); if (type.IsPrimitive || type == typeof(string)) { _originalValue.Value.TryGet(Constants.CompareExchange.ObjectFieldName, out entity); } else { entity = conventions.Serialization.DefaultConverter.FromBlittable <T>(_originalValue.Value, _key); } } var value = new CompareExchangeValue <T>(_key, _index, entity); _value = value; return(value); } case CompareExchangeValueState.Missing: case CompareExchangeValueState.Deleted: return(null); default: throw new NotSupportedException($"Not supported state: '{_state}'"); } }
public override async Task <IEnumerable <AggregateEventEnvelope <TAggregate> > > LoadHistory(long maxVersion, CancellationToken ctk = default) { var aggrname = AggregateHelper <TAggregate> .Name; var envelopes = new List <AggregateEventStore>(); _chex = await _session.Advanced.ClusterTransaction.GetCompareExchangeValueAsync <long>(_chexKey, ctk); if (_chex == null) { return(new AggregateEventEnvelope <TAggregate> [0]); } maxVersion = Math.Min(_chex.Value, maxVersion); string lastId = null; while (envelopes.Count != maxVersion) { var results = await _session.Advanced.StreamAsync <AggregateEventStore>( $"{aggrname}/{Identifier}/", startAfter : lastId, pageSize : (int)maxVersion - envelopes.Count, token : ctk); while (envelopes.Count != maxVersion && await results.MoveNextAsync()) { var envelope = results.Current; if (envelope.Document.AggregateVersion != envelopes.Count + 1) { break; } envelopes.Add(envelope.Document); lastId = envelope.Id; } } return(envelopes.Select(x => x.FromStore <TAggregate>())); }
public override async Task SaveChangesAsync(CancellationToken ctk = default) { if (Aggregate.UncommittedAggregateEvents.Any()) { if (_chex == null) { _chex = _session.Advanced.ClusterTransaction.CreateCompareExchangeValue <long>(_chexKey, Aggregate.Version); } else { _chex.Value = Aggregate.Version; } foreach (var e in Aggregate.UncommittedDomainEvents) { var eventType = e.Event.GetType(); var outboxType = typeof(OutboxEvent <>).MakeGenericType(eventType); var evt = (OutboxEvent)Activator.CreateInstance(outboxType); evt.Id = e.Metadata.EventId; evt.Metadata = e.Metadata.Values.ToDictionary(x => x.Key, x => x.Value); evt.SetEvent(e.Event); await _session.StoreAsync(evt, ctk); } foreach (var e in Aggregate.UncommittedAggregateEvents) { await _session.StoreAsync(e.ToStore(), ctk); } await _session.StoreAsync(Aggregate.State, AggregateHelper <TAggregate> .Name + "/" + Aggregate.Identifier, ctk); await _session.SaveChangesAsync(ctk); } Aggregate.Commit(); }
internal bool HasChanged(CompareExchangeValue <BlittableJsonReaderObject> originalValue, CompareExchangeValue <BlittableJsonReaderObject> newValue) { if (ReferenceEquals(originalValue, newValue)) { return(false); } if (string.Equals(originalValue.Key, newValue.Key, StringComparison.OrdinalIgnoreCase) == false) { throw new InvalidOperationException($"Keys do not match. Expected '{originalValue.Key}' but was '{newValue.Key}'."); } if (originalValue.Index != newValue.Index) { return(true); } if (originalValue.Value == null) { return(true); } return(originalValue.Value.Equals(newValue.Value) == false); }
public async Task CreateFullAndIncrementalBackupWithCompareExchangeInTheMiddle() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenSession()) { session.Store(new User { Name = "Toli" }, "users/1"); session.SaveChanges(); } var config = new PeriodicBackupConfiguration { LocalSettings = new LocalSettings { FolderPath = backupPath }, Name = "full", FullBackupFrequency = "* */6 * * *", BackupType = BackupType.Backup }; var result = await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config)); var documentDatabase = (await GetDocumentDatabaseInstanceFor(store)); RunBackup(result.TaskId, documentDatabase, true, store); CompareExchangeResult <string> compareExchangeResult = store.Operations.Send( new PutCompareExchangeValueOperation <string>("users/1", "Mitzi", 0)); config.IncrementalBackupFrequency = "* */2 * * *"; config.TaskId = result.TaskId; result = await store.Maintenance.SendAsync(new UpdatePeriodicBackupOperation(config)); RunBackup(result.TaskId, documentDatabase, false, store); var backupDirectory = Directory.GetDirectories(backupPath).First(); var databaseName = GetDatabaseName() + "restore"; RestoreBackupConfiguration config2 = new RestoreBackupConfiguration() { BackupLocation = backupDirectory, DatabaseName = databaseName, LastFileNameToRestore = Directory.GetFiles(backupDirectory).Last() }; RestoreBackupOperation restoreOperation = new RestoreBackupOperation(config2); store.Maintenance.Server.Send(restoreOperation) .WaitForCompletion(); using (var store2 = GetDocumentStore(new Options() { CreateDatabase = false, ModifyDatabaseName = s => databaseName })) { using (var session = store2.OpenSession()) { var doc = session.Load <User>("users/1"); Assert.NotNull(doc); }; CompareExchangeValue <string> readResult = store2.Operations.Send(new GetCompareExchangeValueOperation <string>("users/1")); Assert.Equal("Mitzi", readResult.Value); }; } }
public CompareExchange() { using (var store = new DocumentStore()) { { #region get_1 CompareExchangeValue <long> readResult = store.Operations.Send(new GetCompareExchangeValueOperation <long>("NextClientId")); long value = readResult.Value; #endregion } { #region get_2 CompareExchangeValue <User> readResult = store.Operations.Send(new GetCompareExchangeValueOperation <User>("AdminUser")); User admin = readResult.Value; #endregion } { #region get_list_2 Dictionary <string, CompareExchangeValue <string> > compareExchangeValues = store.Operations.Send( new GetCompareExchangeValuesOperation <string>(new[] { "Key-1", "Key-2" })); #endregion } { #region get_list_3 // Get values for keys that have the common prefix 'users' // Retrieve maximum 20 entries Dictionary <string, CompareExchangeValue <User> > compareExchangeValues = store.Operations.Send(new GetCompareExchangeValuesOperation <User>("users", 0, 20)); #endregion } { #region put_1 CompareExchangeResult <string> compareExchangeResult = store.Operations.Send( new PutCompareExchangeValueOperation <string>("Emails/[email protected]", "users/123", 0)); bool successful = compareExchangeResult.Successful; // If successfull is true: then Key '*****@*****.**' now has the value of "users/123" #endregion } { #region put_2 // Get existing value CompareExchangeValue <User> readResult = store.Operations.Send( new GetCompareExchangeValueOperation <User>("AdminUser")); readResult.Value.Age++; // Update value CompareExchangeResult <User> saveResult = store.Operations.Send( new PutCompareExchangeValueOperation <User>("AdminUser", readResult.Value, readResult.Index)); // The save result is successful only if 'index' wasn't changed between the read and write operations bool saveResultSuccessful = saveResult.Successful; #endregion } { #region delete_1 // First, get existing value CompareExchangeValue <User> readResult = store.Operations.Send( new GetCompareExchangeValueOperation <User>("AdminUser")); // Delete the key - use the index received from the 'Get' operation CompareExchangeResult <User> deleteResult = store.Operations.Send( new DeleteCompareExchangeValueOperation <User>("AdminUser", readResult.Index)); // The delete result is successful only if the index has not changed between the read and delete operations bool deleteResultSuccessful = deleteResult.Successful; #endregion } } }
public CompareExchange() { using (var store = new DocumentStore()) { { #region get_1 CompareExchangeValue <long> readResult = store.Operations.Send(new GetCompareExchangeValueOperation <long>("NextClientId")); long value = readResult.Value; #endregion } { #region get_2 CompareExchangeValue <User> readResult = store.Operations.Send(new GetCompareExchangeValueOperation <User>("AdminUser")); User admin = readResult.Value; #endregion } /*{ This overload is no longer available #region get_list_2 * Dictionary<string, CompareExchangeValue<string>> compareExchangeValues * = store.Operations.Send( * new GetCompareExchangeValuesOperation<string>(new[] { "Key-1", "Key-2" })); #endregion * }*/ { #region get_list_3 // Get values for keys that have the common prefix 'users' // Retrieve maximum 20 entries Dictionary <string, CompareExchangeValue <User> > compareExchangeValues = store.Operations.Send(new GetCompareExchangeValuesOperation <User>("users", 0, 20)); #endregion } { #region put_1 CompareExchangeResult <string> compareExchangeResult = store.Operations.Send( new PutCompareExchangeValueOperation <string>("Emails/[email protected]", "users/123", 0)); bool successful = compareExchangeResult.Successful; // If successfull is true: then Key '*****@*****.**' now has the value of "users/123" #endregion } { #region put_2 // Get existing value CompareExchangeValue <User> readResult = store.Operations.Send( new GetCompareExchangeValueOperation <User>("AdminUser")); readResult.Value.Age++; // Update value CompareExchangeResult <User> saveResult = store.Operations.Send( new PutCompareExchangeValueOperation <User>("AdminUser", readResult.Value, readResult.Index)); // The save result is successful only if 'index' wasn't changed between the read and write operations bool saveResultSuccessful = saveResult.Successful; #endregion } { #region delete_1 // First, get existing value CompareExchangeValue <User> readResult = store.Operations.Send( new GetCompareExchangeValueOperation <User>("AdminUser")); // Delete the key - use the index received from the 'Get' operation CompareExchangeResult <User> deleteResult = store.Operations.Send( new DeleteCompareExchangeValueOperation <User>("AdminUser", readResult.Index)); // The delete result is successful only if the index has not changed between the read and delete operations bool deleteResultSuccessful = deleteResult.Successful; #endregion } #region expiration_0 using (IAsyncDocumentSession session = store.OpenAsyncSession()) { // Set a time exactly one week from now DateTime expirationTime = DateTime.UtcNow.AddDays(7); // Create a new compare exchange value var cmpxchgValue = session.Advanced.ClusterTransaction.CreateCompareExchangeValue("key", "value"); // Edit Metadata cmpxchgValue.Metadata[Constants.Documents.Metadata.Expires] = expirationTime; // Send to server session.SaveChangesAsync(); } #endregion using (IAsyncDocumentSession session = store.OpenAsyncSession()) { #region expiration_1 // Retrieve an existing key CompareExchangeValue <string> cmpxchgValue = store.Operations.Send( new GetCompareExchangeValueOperation <string>("key")); // Set time DateTime expirationTime = DateTime.UtcNow.AddDays(7); // Edit Metadata cmpxchgValue.Metadata[Constants.Documents.Metadata.Expires] = expirationTime; // Update value. Index must match the index on the server side, // or the operation will fail. CompareExchangeResult <string> result = store.Operations.Send( new PutCompareExchangeValueOperation <string>( cmpxchgValue.Key, cmpxchgValue.Value, cmpxchgValue.Index)); #endregion } #region metadata_0 using (IAsyncDocumentSession session = store.OpenAsyncSession( new SessionOptions { TransactionMode = TransactionMode.ClusterWide })) { // Create a new compare exchange value var cmpxchgValue = session.Advanced.ClusterTransaction.CreateCompareExchangeValue("key", "value"); // Add a field to the metadata // with a value of type string cmpxchgValue.Metadata["Field name"] = "some value"; // Retrieve metadata as a dictionary IDictionary <string, object> cmpxchgMetadata = cmpxchgValue.Metadata; } #endregion } }
public async Task CreateFullAndIncrementalBackupWithCompareExchangeInTheMiddle() { var backupPath = NewDataPath(suffix: "BackupFolder"); using (var store = GetDocumentStore()) { using (var session = store.OpenSession()) { session.Store(new User { Name = "Toli" }, "users/1"); session.SaveChanges(); } var config = Backup.CreateBackupConfiguration(backupPath); var backupTaskId = await Backup.UpdateConfigAndRunBackupAsync(Server, config, store); CompareExchangeResult <string> compareExchangeResult = store.Operations.Send( new PutCompareExchangeValueOperation <string>("users/1", "Mitzi", 0)); WaitForValue(() => compareExchangeResult.Successful, true); await Backup.RunBackupAsync(Server, backupTaskId, store, isFullBackup : false); compareExchangeResult = store.Operations.Send( new PutCompareExchangeValueOperation <string>("users/1", "Mitzi2", compareExchangeResult.Index)); WaitForValue(() => compareExchangeResult.Successful, true); await Backup.RunBackupAsync(Server, backupTaskId, store, isFullBackup : false); var backupDirectory = Directory.GetDirectories(backupPath).First(); var databaseName = GetDatabaseName() + "restore"; var files = Directory.GetFiles(backupDirectory) .Where(BackupUtils.IsBackupFile) .OrderBackups() .ToArray(); RestoreBackupConfiguration config2 = new RestoreBackupConfiguration() { BackupLocation = backupDirectory, DatabaseName = databaseName, LastFileNameToRestore = files.Last() }; RestoreBackupOperation restoreOperation = new RestoreBackupOperation(config2); store.Maintenance.Server.Send(restoreOperation) .WaitForCompletion(); using (var store2 = GetDocumentStore(new Options() { CreateDatabase = false, ModifyDatabaseName = s => databaseName })) { using (var session = store2.OpenSession()) { var doc = session.Load <User>("users/1"); Assert.NotNull(doc); }; CompareExchangeValue <string> readResult = store2.Operations.Send(new GetCompareExchangeValueOperation <string>("users/1")); Assert.Equal("Mitzi2", readResult.Value); }; } }
internal ICommandData GetCommand(DocumentConventions conventions, JsonOperationContext context, IJsonSerializer jsonSerializer) { switch (_state) { case CompareExchangeValueState.None: case CompareExchangeValueState.Created: if (_value == null) { return(null); } var entity = CompareExchangeValueBlittableJsonConverter.ConvertToBlittable(_value.Value, conventions, context, jsonSerializer); var entityJson = entity as BlittableJsonReaderObject; BlittableJsonReaderObject metadata = null; if (_value.HasMetadata && _value.Metadata.Count != 0) { metadata = PrepareMetadataForPut(_key, _value.Metadata, conventions, context); } BlittableJsonReaderObject entityToInsert = null; if (entityJson == null) { entityJson = entityToInsert = ConvertEntity(_key, entity, metadata); } var newValue = new CompareExchangeValue <BlittableJsonReaderObject>(_key, _index, entityJson); var hasChanged = _originalValue == null || HasChanged(_originalValue, newValue); _originalValue = newValue; if (hasChanged == false) { return(null); } if (entityToInsert == null) { entityToInsert = ConvertEntity(_key, entity, metadata); } return(new PutCompareExchangeCommandData(newValue.Key, entityToInsert, newValue.Index)); case CompareExchangeValueState.Deleted: return(new DeleteCompareExchangeCommandData(_key, _index)); case CompareExchangeValueState.Missing: return(null); default: throw new NotSupportedException($"Not supported state: '{_state}'"); } BlittableJsonReaderObject ConvertEntity(string key, object entity, BlittableJsonReaderObject metadata = null) { var djv = new DynamicJsonValue { [Constants.CompareExchange.ObjectFieldName] = entity }; if (metadata == null) { return(context.ReadObject(djv, key)); } djv[Constants.Documents.Metadata.Key] = metadata; return(context.ReadObject(djv, key)); } }