With the development of high transaction distributed applications, distributed caching solutions have become highly desirable to achieve performance scalability. NCache is a good choice as an in-memory distributed data store since it provides linear scalability and high availability.
So far, so good, but how to ensure data integrity in such shared environments is a big deal. Since two or more clients can access and alter the same data simultaneously in your application, the result can be inconsistent data. Once data integrity breaches occur, the data in the cache becomes virtually useless.
In this blog post, I will explain how this problem occurs and how NCache saves you with its distributed locking feature.
Key Takeaways:
Data Integrity Protection: Concurrency controls in NCache mitigate transactional race conditions, such as the Lost Update anomaly, during simultaneous multi-client operations.
Pessimistic Locking Mechanism: The GetWithLock method acquires an exclusive resource lock managed via a LockHandle and a designated TimeSpan timeout to block concurrent modification attempts.
Optimistic Locking Mechanism: Data updates are validated using unique CacheItemVersion properties, enabling non-blocking reads while ensuring atomic changes across independent operations.
Failure Handling Matrix: Lock acquisition failures return a false status, while version mismatches and unauthorized modifications to locked keys throw an explicit OperationFailedException.
Data Integrity Problems Without Locking
To understand the data integrity problem in detail, we consider the example of an online E-Commerce store where sellers upload their products while customers view and place orders for those products to purchase.
Suppose a customer wants to view a certain product and the seller of that product wants to update its price. Now if a customer is viewing a product at a higher price and the seller adds a discount that the user cannot see yet, the user ends up purchasing the product at a higher price.
The scenario is shown in Figure 1.

Figure 1: Data inconsistency resulting from un-managed concurrent updates in NCache.
- Client 1 reads the details of the product in the cache.
- Client 2 also reads the product data. It is correct.
- Client 1 now updates product details in the cache.
- Client 2 also updates the product details in the cache.
- Updates made by client 1 are lost.
Let’s see how NCache resolves this problem.
NCache Distributed Locking
NCache provides a flexible way of securing your data according to your business needs by allowing you to lock your data. One user takes control of a chunk of data and updates it. Meanwhile, no other user can manipulate that data.
Based on your application scenario, you can choose either of these NCache locking mechanisms:
- Pessimistic locking (transactional or exclusive locks): Locks an item exclusively which makes it inaccessible for other users.
- Optimistic locking (lock through item versioning): Uses item versioning which makes an item accessible for other users.
The following table contrasts these two concurrency models to help you select the right locking strategy for your architecture.
| Feature | Pessimistic Locking | Optimistic Locking |
|---|---|---|
| Mechanism | Explicitly locks the item in the cache via LockHandle. | Uses item versioning (CacheItemVersion) to track changes. |
| Best Use Case | High contention, when data integrity is critical. | Low contention, when performance is the priority. |
| Client Behavior | Other clients must wait for the lock to be released or expire. | Clients can update data only if the version matches the cache version. |
| Pros & Cons | High consistency, potential for bottlenecks. | High performance, possible update failures. |
Pessimistic Locking for Sensitive Data
You should use the pessimistic locking strategy when the data that requires updates in your application is sensitive. You can use a LockHandle to acquire an explicit lock on your data. Once you are done, the lock is released.
Now, we see that how NCache pessimistic locking solves the data consistency problem in our example. You can acquire an exclusive lock on the product to update meanwhile, no other user can access that product. This is illustrated in figure 2.

Figure 2: Pessimistic Locking mechanism ensuring exclusive data access by blocking concurrent client requests.
- Client 1 acquires lock over the product and starts adding and updating the product details.
- Client 2 is denied access to read product details and must wait until the lock is released.
- Once the lock is released, Client 2 can carry on its regular operations on the product.
It is important to note that, NCache supports two sets of APIs: with and without locking. If the user wants to use pessimistic locking, then APIs with locking parameters should be used everywhere in applications where strong data consistency is the requirement. Let’s see how you can do it with NCache locking feature. In the following code segment, first, a new LockHandle is created and then the timespan is set to specify the time period for which the lock will be acquired. This LockHandle works as a lock ID to identify the lock. A lock is then acquired using the Get method with a key and LockHandle.
Now you can perform your business operations and manually release the lock or wait for the timespan to end.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// Pre-condition: Cache is already connected // Create a new lock handle to fetch an Item using locking LockHandle lockHandle = new LockHandle(); // Timespan for which lock is to be taken TimeSpan timeSpan = TimeSpan.FromSeconds(5); // Get item from the cache and lock it var result = cache.Get(key, true, timeSpan, ref lockHandle); // Verify if the item is locked successfully if (result != null) { // Item has been successfully locked } else { // Key does not exist // Item is already locked with a different LockHandle } //Unlock item in cache manually cache.Unlock(key, lockHandle); |
Here, Get API with lock parameters immediately returns without waiting for lock acquisition. You need to make explicit reties to acquire a lock on items in case you fail in the first place.
You can also acquire a lock using the Lock method which associates a LockHandle with a key. NCache provides various ways to acquire/release an explicit lock which enables flexible locking. If you intend to implement NCache locking, using the NCache sample application for item locking on GitHub will be helpful.
NCache Details Pessimistic Locking Optimistic locking
Optimistic Locking for Data Availability
Pessimistic locking is great but it may not be an optimal approach when response time is critical for your application. This is where optimistic locking comes in handy.
NCache optimistic locking uses cache item versioning to overcome the thread starvation caused in the case of explicit lock. Hence, you can work on a version of the cached item which is incremented with every update to that item. NCache keeps track of the item version and you don’t need to worry about data consistency.
Figure 3 shows how it’s done:

Figure 3: Optimistic Locking in NCache utilizing version-based validation to prevent stale data updates.
- Client 1 adds details about the product and the CacheItemVersion is set to v1.
- Client 2 reads updated product details with CacheItemVersion v1.
- Client 1 again alters the details due to which CacheItemVersion is incremented and it becomes v2.
- Now when Client 2 tries to update details using old CacheItemVersion v1, the operation fails with CacheItemVersion
- Client 2 gets the latest CacheItemVersion
- Client 2 updates the product details using CacheItemVersion. Now the operation is performed successfully and increments the CacheItemVersion by 1 automatically.
This ensures all users have updated CacheItemVersion at all times and no user is refused access to any product in the store.
The following code shows how to do it:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// Specify the key of the cacheItem string key = "Product:1001"; // Initialize the cacheItemVersion CacheItemVersion version = null; // Get the cacheItem previously added in the cache with the version CacheItem cacheItem = cache.GetCacheItem(key, ref version); // If result is not null if (cacheItem != null) { // CacheItem is retrieved successfully with the version var prod = cacheItem.GetValue(); prod.Discount = 0.5; // Create a new cacheItem with updated value var updateItem = new CacheItem(prod); //Set the itemversion. This version is used to compare the // item version of the cached item updateItem.Version = version; //Insert call will fail with LockingException, if cache contains a newer version of the cache item. //In case of LockingException, we can fetch the latest cache item from cache and update it cache.Insert(key, updateItem); // If it matches, the insert is successful, otherwise it fails } |
Managing Concurrency Failures and Cache Exceptions
When implementing concurrency strategies, tracking return behaviors and handling system failures ensures execution continuity. The following reference details runtime exceptions and operations feedback for explicit and version-based locking configurations.
| Exception / Return Behavior | Trigger Condition | Recommended Mitigation Strategy |
|---|---|---|
| GetWithLock returns false | Occurs when a client tries to acquire a lock on an item that is already locked by another LockHandle. | Implement a retry loop with a short backoff delay to re-attempt lock acquisition. |
| OperationFailedException | Thrown if a client attempts to update or remove an exclusively locked item without passing the valid LockHandle. | Handle the exception, wait for the lock to release, or acquire the correct LockHandle before modifying. |
| OperationFailedException | Thrown during Optimistic Locking if the CacheItemVersion in the cache has changed since it was fetched. | Re-fetch the latest CacheItem along with its new version number and retry the update operation. |
Why Use NCache Locking
Secure and consistent data is crucial for today’s businesses and it would be a shame if something as simple as multi-user transactions damages your data integrity.
NCache ensures the integrity and consistency of your data in highly distributed environments with utmost flexibility. Based on your application scenario, you can adopt different locking mechanisms in various ways provided by NCache. Eventually, you will have concurrency without any data inconsistency!
NCache Details Download NCache Edition Comparison
Frequently Asked Questions (FAQ)
Q: What happens if an application fails to release an exclusive lock in NCache?
A: NCache avoids permanent deadlocks by using an explicit TimeSpan parameter during lock acquisition. The cache automatically frees the locked item once this lease period expires, making the resource available to other client applications.
Q: Can a client modify an item that is locked by another instance without a handle?
A: No. Any attempt to update or delete a locked cache item without supplying the matching LockHandle results in an OperationFailedException. The item remains protected until it is explicitly unlocked or the timeout passes.
Q: How does NCache determine if a version is outdated during Optimistic Locking?
A: Every cache item contains a numeric CacheItemVersion. When a client calls an update operation, NCache performs an atomic comparison between the application’s current item version and the server-side version to verify no intervening updates occurred.
Q: Does NCache block read operations on items under a Pessimistic Lock?
A: Standard read requests that do not attempt to acquire a lock can still access the data. The item is only blocked for requests that explicitly attempt to write to the item or call methods requiring a concurrent lock lease.







Such amazing information you have, to give others. Thanks for letting us know about it. Please keep sharing such information, that ensures the security of our properties.