public void ReleaseResource(IDocumentStore store, string resourceName, long index) { CompareExchangeResult <SharedResource> deleteResult = store.Operations.Send(new DeleteCompareExchangeValueOperation <SharedResource>(resourceName, index)); // We have 2 options here: // deleteResult.Successful is true - we managed to release resource // deleteResult.Successful is false - someone else took the look due to timeout }
public async Task Sample() { using (var store = new DocumentStore()) { #region email string email = "*****@*****.**"; User user = new User { Email = email }; using (IDocumentSession session = store.OpenSession()) { session.Store(user); // At this point, the user document has an Id assigned // Try to reserve a new user email // Note: This operation takes place outside of the session transaction, // It is a cluster-wide reservation CompareExchangeResult <string> cmpXchgResult = store.Operations.Send( new PutCompareExchangeValueOperation <string>("emails/" + email, user.Id, 0)); if (cmpXchgResult.Successful == false) { throw new Exception("Email is already in use"); } // At this point we managed to reserve/save the user email - // The document can be saved in SaveChanges session.SaveChanges(); } #endregion #region query_cmpxchg using (IDocumentSession session = store.OpenSession()) { var query = from u in session.Query <User>() where u.Email == RavenQuery.CmpXchg <string>("emails/[email protected]") select u; var q = session.Advanced .DocumentQuery <User>() .WhereEquals("Email", CmpXchg.Value("emails/[email protected]")); } #endregion } }
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)); }
public async Task SubscriptionsWorksWithCompareExchange() { using (var store = GetDocumentStore()) { string userId; string cmpxValueOriginal; using (var session = store.OpenSession()) { User user = new User { Name = "foobar" }; session.Store(user); userId = session.Advanced.GetDocumentId(user); // Try to reserve a new user email // Note: This operation takes place outside of the session transaction, // It is a cluster-wide reservation cmpxValueOriginal = "His name is " + user.Name; CompareExchangeResult <string> cmpXchgResult = store.Operations.Send( new PutCompareExchangeValueOperation <string>(user.Id, cmpxValueOriginal, 0)); session.SaveChanges(); } var subsId = store.Subscriptions.Create <User>(new Raven.Client.Documents.Subscriptions.SubscriptionCreationOptions <User>() { Projection = x => new { Foo = RavenQuery.CmpXchg <string>(userId), x.AddressId } }); string cmpxValue = string.Empty; var subsWorker = store.Subscriptions.GetSubscriptionWorker(new Raven.Client.Documents.Subscriptions.SubscriptionWorkerOptions(subsId) { CloseWhenNoDocsLeft = true }); await Assert.ThrowsAsync <SubscriptionClosedException>(async() => await subsWorker.Run(x => { cmpxValue = x.Items[0].RawResult["Foo"].ToString(); })); Assert.Equal(cmpxValue, cmpxValueOriginal); } }
public long LockResource(IDocumentStore store, string resourceName, TimeSpan duration) { while (true) { DateTime now = DateTime.UtcNow; SharedResource resource = new SharedResource { ReservedUntil = now.Add(duration) }; CompareExchangeResult <SharedResource> saveResult = store.Operations.Send( new PutCompareExchangeValueOperation <SharedResource>(resourceName, resource, 0)); if (saveResult.Successful) { // resourceName wasn't present - we managed to reserve return(saveResult.Index); } // At this point, Put operation failed - someone else owns the lock or lock time expired if (saveResult.Value.ReservedUntil < now) { // Time expired - Update the existing key with the new value CompareExchangeResult <SharedResource> takeLockWithTimeoutResult = store.Operations.Send( new PutCompareExchangeValueOperation <SharedResource>(resourceName, resource, saveResult.Index)); if (takeLockWithTimeoutResult.Successful) { return(takeLockWithTimeoutResult.Index); } } // Wait a little bit and retry Thread.Sleep(20); } }
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); }; } }