Counter Behavior and Usage in Cache
Note
This feature is only available in NCache Enterprise Edition.
A counter in NCache is a single long value stored in cache which can be accessed by all applications connected to the cache. This value can be incremented and decremented, can be locked and can have events registered against it.
For example, a counter can be used to store the views every time a video is viewed on a social media site. It can also be used to store subscriptions against a website, where people can subscribe or unsubscribe from the website.
NCache further enhances this counter by providing NCache specific features such as expiration, dependency, groups and more to the counter. For example, you can specify a counter against the group "SubscriptionDetails" which can contain customer objects as well the subscription counter.
Behavior
- Null is not a supported value.
- Counters are named; you need to provide a unique cache key for each counter.
Pre-requisites
- Install the following NuGet packages:
- Include the following namespaces in your application:
Alachisoft.NCache.Client
Alachisoft.NCache.Client.DataTypes
Alachisoft.NCache.Runtime.Exceptions
Alachisoft.NCache.Client.DataTypes.Counter
- The application must be connected to cache before performing the operation.
- Cache must be running.
- For API details, refer to: ICache, CreateCounter, Decrement, DecrementBy, GetCounter, Increment, Lock, SetValue, Unlock.
- Make sure that the data being added is serializable.
- To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
- To handle any unseen exceptions, refer to the Troubleshooting section.
Create Counter
The following code sample shows how a counter can be created in cache using CreateCounter
against the cache key SubscriptionCounter without any additional parameters. The key must be unique.
Tip
You can also configure searchable attributes such as groups/tags/named tags and invalidation attributes such as expiration/eviction/dependency while creating a data type.
try
{
// Pre-condition: Cache must be connected
// Specify unique cache key for counter
string key = "SubscriptionCounter";
// Set initial value of counter
long initialValue = 15;
// Create counter
ICounter counter = cache.DataTypeManager.CreateCounter(key, initialValue);
}
catch (OperationFailedException ex)
{
// NCache specific exception
if(ex.ErrorCode == NCacheErrorCodes.KEY_ALREADY_EXISTS)
{
// The specified key already exists in cache,
// Either remove the existing object from cache
// Or specify another key
}
else
{
// NCache specific exception
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
Recommendation: To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
Fetch Counter from Cache
You can fetch a counter from cache using GetCounter
, which takes a cache key as parameter. This key is the name of the counter which is specified during counter creation. You can use this value to Increment
or Decrement
the value.
try
{
// Pre-condition: Cache is already connected
// Unique key for counter
string key = "SubscriptionCounter";
// Get counter against key
ICounter retrievedCounter = cache.DataTypeManager.GetCounter(key);
// Increment value of retrievedCounter on new subscription
retrievedCounter.Increment();
}
catch (OperationFailedException ex)
{
// NCache specific exception
if(ex.ErrorCode == NCacheErrorCodes.NOT_A_COUNTER)
{
// Item being fetched is not of counter type;
// Cache key corresponds to an item of different data type
}
else
{
// NCache specific exception
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
Recommendation: To ensure the operation is fail safe, it is recommended to handle any potential exceptions within your application, as explained in Handling Failures.
Update Value of Counter
NCache provides option to update the value of a counter after it is created. The following code sample fetches a counter from cache and sets its value to another value, overwriting the existing value using SetValue
. It then gets the number of users which have unsubscribed, and decrements the value by that value using DecrementBy
.
try
{
// Pre-condition: Cache is already connected
// Unique key for counter
string key = "SubscriptionCounter";
// Get counter against key
ICounter retrievedCounter = cache.DataTypeManager.GetCounter(key);
// Set Value of counter to 100
retrievedCounter.SetValue(100);
// Decrement value by number of users which unsubscribed
// CountUnsubscribedUsers gets the count of the unsubscribed users
long unsubscribedUsers = CountUnsubscribedUsers();
retrievedCounter.DecrementBy(unsubscribedUsers);
}
catch (OperationFailedException ex)
{
// NCache specific exception
if (ex.ErrorCode == NCacheErrorCodes.NOT_A_COUNTER)
{
// Item being fetched is not of counter type;
// Cache key corresponds to an item of different data type
}
else
{
// NCache specific exception
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
Event Notifications on Counters
You can register cache events as well as data type events on a data type such as counter. For behavior, refer to the Feature Wise behavior topic.
The following code sample registers a cache event of ItemAdded
and ItemUpdated
as well as registers an event for ItemAdded
and ItemUpdated
on the counter in cache.
Once a counter is created in cache, an ItemAdded
cache level event is fired. However, once an item is added to counter, an ItemAdded
data type event is fired, and an ItemUpdated
cache level event is fired.
Register Event on Counter Created
try
{
// Pre-condition: Cache is already connected
// Unique cache key for counter
string key = "SubscriptionCounter";
// Set initial value of counter
long initialValue = 15;
// Create counter
ICounter counter = cache.DataTypeManager.CreateCounter(key, initialValue);
// Register ItemAdded, ItemUpdated, ItemRemoved events on counter created
// DataTypeNotificationCallback is callback method specified
counter.RegisterNotification(DataTypeDataNotificationCallback, EventType.ItemAdded |
EventType.ItemUpdated | EventType.ItemRemoved,
DataTypeEventDataFilter.Data);
// Perform operations
}
catch (OperationFailedException ex)
{
// NCache specific exception
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
catch (Exception ex)
{
// Any generic exception like ArgumentNullException or ArgumentException
}
Specify Callback for Event Notification
private void DataTypeDataNotificationCallback(string collectionName, DataTypeEventArg collectionEventArgs)
{
switch (collectionEventArgs.EventType)
{
case EventType.ItemAdded:
// Item has been added to the collection
break;
case EventType.ItemUpdated:
if (collectionEventArgs.CollectionItem != null)
{
// Item has been updated in the collection
// Perform operations
}
break;
case EventType.ItemRemoved:
// Item has been removed from the collection
break;
}
}
Locking Counter
Counters can be explicitly locked and unlocked to ensure data consistency. The following code sample creates a counter and locks it for a period of 10 seconds using Lock(), and unlocks it using Unlock().
try
{
// Pre-conditions: Cache is already connected
// Counter exists with key "SubscriptionCounter"
// Cache Key
string key = "SubscriptionCounter";
// Get counter against key
ICounter counter = cache.DataTypeManager.GetCounter(key);
bool isLocked = counter.Lock(TimeSpan.FromSeconds(10));
if (isLocked)
{
// Counter is successfully locked for 10 seconds
// Unless explicitly unlocked
}
else
{
// Counter is not locked because either:
// Counter is not present in the cache
// Counter is already locked
}
counter.Unlock();
}
catch (OperationFailedException ex)
{
// NCache specific exception
// Exception can occur due to:
// Connection Failures
// Operation Timeout
// Operation performed during state transfer
}
catch (Exception ex)
{
// Any other generic exception like ArgumentNullException or ArgumentException
}
Additional Resources
NCache provides sample application for Counter datatypes on GitHub.
See Also
Sets Behavior and Usage in Cache
Dictionary Behavior and Usage in Cache
Configure Searchable Attributes
Configure Invalidation Attributes