private async Task <MongoDbRecord> LockRecord(byte[] lockToken, Record r) { var key = r.Key.ToByteArray(); var version = r.Version.ToByteArray(); if (version.Length != 0) { var res = await RecordCollection.FindOneAndUpdateAsync( x => x.Key.Equals(key) && x.Version.Equals(version) && (x.TransactionLock == null || x.TransactionLock.Equals(lockToken)), Builders <MongoDbRecord> .Update .Set(x => x.TransactionLock, lockToken) ); if (res == null) { var e = new ConcurrentMutationException(r); e.Data["ExceptionType"] = "LockRecord"; throw e; } #if DEBUG Logger.LogDebug($"Locked token {new ByteString(lockToken)} {r.Key.ToString()}"); #endif return(res); } return(null); }
private async Task RollbackTransaction(byte[] hash) { // Rollback is idempotent && reentrant : may be call twice even at the same time try { #if DEBUG Logger.LogDebug($"Rollbacking transaction {new ByteString(hash)}"); #endif // get affected records var trn = await PendingTransactionCollection.Find(x => x.TransactionHash.Equals(hash)).SingleOrDefaultAsync(); if (trn != null) { // revert records values & version foreach (var r in trn.InitialRecords) { await RecordCollection.FindOneAndUpdateAsync( x => x.Key.Equals(r.Key) && x.TransactionLock.Equals(trn.LockToken), Builders <MongoDbRecord> .Update.Set(x => x.Value, r.Value).Set(x => x.Version, r.Version).Unset(x => x.TransactionLock) ); } foreach (var r in trn.AddedRecords) { await RecordCollection.FindOneAndDeleteAsync( x => x.Key.Equals(r) && x.TransactionLock.Equals(trn.LockToken) ); } // remove transaction await TransactionCollection.DeleteOneAsync(x => x.TransactionHash.Equals(hash)); await RecordCollection.UpdateOneAsync( x => x.TransactionLock == trn.LockToken, Builders <MongoDbRecord> .Update .Unset(x => x.TransactionLock) ); // remove pending transaction await PendingTransactionCollection.DeleteOneAsync(x => x.TransactionHash.Equals(hash)); Logger.LogInformation($"Transaction {new ByteString(hash)} rollbacked"); } } catch (Exception ex) { var msg = "Error rollbacking transaction : " + new ByteString(hash).ToString(); Logger.LogCritical(msg, ex); throw new Exception(msg, ex); } }
private async Task <MongoDbRecord> LockRecord(byte[] lockToken, Record r) { var key = r.Key.ToByteArray(); var version = r.Version.ToByteArray(); if (version.Length != 0) { var res = await RecordCollection.FindOneAndUpdateAsync( x => x.Key.Equals(key) && x.Version.Equals(version) && (x.TransactionLock == null || x.TransactionLock.Equals(lockToken)), Builders <MongoDbRecord> .Update .Set(x => x.TransactionLock, lockToken) ); if (res == null) { throw new ConcurrentMutationException(r); } return(res); } return(null); }