Skip to content

Instantly share code, notes, and snippets.

@jbrestan
Last active August 29, 2015 14:04
Show Gist options
  • Save jbrestan/3ff7477121ea9635222b to your computer and use it in GitHub Desktop.
Save jbrestan/3ff7477121ea9635222b to your computer and use it in GitHub Desktop.
public static IGetOperationResult<T> ExecuteGetOrCreateWithLock<T>(this ICouchbaseClient client,
string key, Func<T> defaultNewValue, TimeSpan keyExpiration, TimeSpan lockExpiration)
{
var initialGetResult = client.ExecuteGetWithLock<T>(key, lockExpiration);
if (initialGetResult.StatusCode == (int) StatusCodeEnums.NotFound ||
(initialGetResult.InnerResult != null &&
initialGetResult.InnerResult.StatusCode == (int) StatusCodeEnums.NotFound))
{
// Key not found. We'll have to create it with the default value and make sure we get the lock.
// There may be other threads racing at this moment, we have to make sure we create the record
// and acquire lock over this newly created key. AFAIK CB API does not allow this to happen
// atomically, so we have to perform two operations, each with its own race conditions.
var storeResult = client.ExecuteStore(StoreMode.Add, key, defaultNewValue(), keyExpiration);
if (!storeResult.Success)
{
// "Add" operation failed; either it was a generic error, or a racing thread beat us to it.
return new GetOperationResult<T>
{
Cas = storeResult.Cas,
Exception = storeResult.Exception,
InnerResult = storeResult,
Message = storeResult.Message,
StatusCode = storeResult.StatusCode,
Success = false,
Value = default (T)
};
}
// Finally try to get the created record with a lock. There may be yet another thread racing between
// adding a record and acquiring a lock.
return client.ExecuteGetWithLock<T>(key, lockExpiration);
}
// If the key was found or there was any other kind of error except missing key, just return the original result.
return initialGetResult;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment