The sosscli::NamedCache class and its specialized subclasses are the primary interfaces used interact with your objects in the distributed object store. A NamedCache represents a named collection of objects in the distributed data store.
The base sosscli::NamedCache class offers limited functionality since it does not have knowledge of the data types being operated on or the serialization mechanism being used, so client applications will typically use one of the NamedCache’s derived class templates to interact with the ScaleOut StateServer service. Different subclasses provide support for different serialization techniques, and the template parameter provided to these specialized classes indicates the type of the objects that application will be storing in each named cache.
ScaleOut’s C++ Native Client API provides two specialized classes to support different serialization techniques.
#include "soss_client/named_protobuf_cache.h"
sosscli::NamedProtobufCache<T> is a named cache that expects Google Protocol Buffers message instances as the objects stored in the StateServer service.
Objects of type T must be generated by the protoc compiler using .proto
files that you define.
The NamedProtobufCache is currently the most feature rich type of named cache—it supports indexing of protobuf fields in the StateServer service and the ability to filter on those fields when performing queries. This guide will focus on the NamedProtobufCache in its examples to illustrate the most typical usage of the C++ Native Client API.
#include "soss_client/named_primitive_cache.h"
sosscli::NamedPrimitiveCache<T> is a named cache that expects primitive C++ types—this type of named cache simply sends the memory occupied by objects of type T to the StateServer service.
Simple structs can also use the NamedPrimitiveCache, but care must be taken to make sure that a cached struct does not contain pointers or references to other objects (only the memory address in a pointer field would be stored in the StateServer service, which would cause serious problems when the object is accessed by other processes). Consider using the NamedProtobufCache if complex object graphs must be stored.
A custom serialization engine can be supported by implementing your own specialized named cache subclass. Inherit from sosscli::TypedNamedCache<T> and override the virtual serialize
and deserialize
methods to support your custom serializer.
Note | |
---|---|
The full implementation of the NamedPrimitiveCache class is available in the named_primitive_cache.h header, which can serve as a useful starting point for creating your own custom named cache subclasses. |
A named cache in the ScaleOut StateServer service can be accessed through the C++ Native Client API by instantiating one of the NamedCache subtypes (typically a NamedProtobufCache or a NamedPrimitiveCache) and providing the cache’s name as a constructor parameter. For example:
//#include "soss_client/named_protobuf_cache.h" //#include "StockQuote.pb.h" // A cache named "Stock Quotes", containing protobuf objects // of type StockQuote: sosscli::NamedProtobufCache<StockQuote> cache("Stock Quotes");
Multiple client application instances on different machines could instantiate a "Stock Quotes" cache in the manner above and gain access to the same, shared collection of stock quote objects.
Since a NamedProtobufCache is a template class, all objects stored in an NamedProtobufCache will be of the same type. Avoid using the same cache name to instantiate two named caches with different types passed in as the template parameter—this can cause deserialization errors to occur. If different types need to be stored in the StateServer service, create different named caches for each type (that is, pass a different string into the NamedProtobufCache’s constructor to give it a different name).
sosscli::NamedProtobufCache<StockQuote> quote_cache("Stock Quotes"); // Bad: Don't store different types in a cache with the same name! // The ScaleOut service will store these different types in the same namespace: sosscli::NamedProtobufCache<Portfolio> bad_port_cache("Stock Quotes"); // Good: Use different names for caches of different types: sosscli::NamedProtobufCache<Portfolio> good_port_cache("Portfolios");
Objects can be created or updated in ScaleOut StateServer using one of the following methods on a NamedProtobufCache or NamedPrimitiveCache:
Method | Description |
---|---|
insert |
Inserts an object that does not already exist |
insert_and_lock |
Inserts an object that does not already exist and locks it |
update |
Updates an existing object |
update_locked_and_retain |
Updates an existing object and holds the lock |
update_locked_and_release |
Updates an existing object and releases the lock |
update_optimistic |
Performs an optimistic update of an object |
put |
Inserts or updates an object |
Once an object is in the named cache, it can be retrieved by any client using one of the following methods:
Method | Description |
---|---|
get |
Retrieves an existing object |
get_and_lock |
Retrieves and acquires an exclusive lock on an existing object |
get_locked |
Retrieves an existing object and retains the lock that is already held by the caller |
Objects can be deleted from the store using the remove family of methods:
Method | Description |
---|---|
remove |
Removes an object from the named cache |
remove_locked |
Removes a locked object from the named cache |
The C++ Native Client API reference documentation contains detailed documentation, including pre-conditions and post-conditions, for each method listed above. See Locking Objects for details on acquiring exclusive locks on objects.
Memory allocation for objects sent to and returned from a named cache is managed by smart pointers. Objects held in the named cache must be dynamically allocated and wrapped in a reference-counted smart pointer (boost::shared_ptr).
Note | |
---|---|
Whenever possible, use boost::make_shared to create a shared_ptr when creating a new instance of one of your objects. The make_shared call is exception-safe and performs
better than if you were to call |
Creating, Reading, Updating, and Deleting an Object in StateServer.
#include "soss_client/named_protobuf_cache.h" #include "StockQuote.pb.h" using namespace NativeClientSample; // StockQuote class' namespace int main(int argc, char* argv[]) { sosscli::NamedProtobufCache<StockQuote> quote_cache("Stock Quotes"); // Create a StockQuote protobuf object and fill out its required fields: auto quote = boost::make_shared<StockQuote>(); // quote->set_ticker("GOOG"); quote->set_price(1031.89f); quote->set_volume(1254310); // Create a key to identify the object in the named cache: sosscli::SossKey soss_key("GOOG"); // Add the protobuf object to a ScaleOut named cache: quote_cache.put(soss_key, quote); // Read the object back out of the StateServer service: auto get_result = quote_cache.get(soss_key); auto retrieved_quote = get_result.object_ptr(); // a boost::shared_ptr std::cout << retrieved_quote->price() << std::endl; // Change the price and update the quote in the StateServer service: retrieved_quote->set_price(1033.32f); quote_cache.update(soss_key, retrieved_quote); // Remove the object from the StateServer service: quote_cache.remove(soss_key); return 0; }
For the definition of the "StockQuote" Protocol Buffer class that is used throughout this guide’s examples, see the section on Using Protocol Buffer Objects. |
The sample in the prior section illustrates how to create an identifier for an object that is stored in a named cache using a string like "GOOG" as a key:
sosscli::SossKey soss_key("GOOG");
All NamedCache methods that access individual objects (insert, put, get, remove, etc…) take a sosscli::SossKey object as the first parameter to identify the object being accessed.
The SossKey can be constructed with one of the following types:
-
std::string
-
std::wstring
-
char *
-
wchar_t *
-
std::vector<uint8_t>
(a vector of unsigned chars, up to 32 bytes long) -
int32_t
-
uint32_t
-
int64_t
-
uint64_t
Note | |
---|---|
For integral types, the C++ Native Client API always uses type aliases defined in stdint.h. |
Internally, the ScaleOut StateServer service uses a 32-byte structure to identify objects. So the type of key passed to a SossKey constructor can have performance implications that should be considered, especially when using strings as keys:
- The StateServer service stores string-based keys as metadata along with the object in the server so that they may be retrieved later by a client application. Using strings to identify your objects, therefore, will increase memory consumption in the service.
- To fit an arbitrary-length key into the service’s 32-byte structure, the API hashes key strings using the SHA-256 hash algorithm. The resulting digest is then used as the primary identifier for the object be stored.
-
String key metadata is stored as Unicode in the StateServer service, so
std::string
andchar*
keys are always converted to wide character strings by the API prior hashing and being sent to the StateServer service. To improve performance, usestd::wstring
as your string type to avoid this conversion.
Integral types and byte vectors therefore provide better performance than strings and will result in less memory consumption
in the server. If you must use string keys, but they are always less than 32 characters long, consider passing them to API
calls as a vector<uint8_t>
for the best possible performance.
As a convenience, the single-argument SossKey constructors will perform implicit conversion. This allows you to pass your string or integral values directly into NamedCache methods as object identifiers. So in most cases, a SossKey object does not need to be explicitly constructed, leading to fewer lines of code:
// "GOOG" is automatically converted to a SossKey: quote_cache.put("GOOG", quote);
A number of policies can be associated with objects that can control their lifetime and behavior in the StateServer service.
The sosscli::ObjectPolicy class contains extended parameter information for the insert
and put
methods on the NamedProtobufCache and NamedPrimitiveCache:
ObjectPolicy Field | Description |
---|---|
|
The lifetime of the object in the named cache. |
|
The type of timeout (sliding, absolute) |
|
The priority of keeping an object in the cache under low memory conditions |
|
Whether the object is subject to GeoServer "push" replication |
|
Keys to objects on which the object being added depends |
Note | |
---|---|
The ObjectPolicy class, like all options and results classes in the C++ Native Client API, provides accessor methods to get
and set its private fields. Getters are simply functions with the field name (i.e., |
An ObjectPolicy can passed as the third parameter to insert
and put
calls:
// A policy for an object that will expire after 60 seconds: sosscli::ObjectPolicy policy; policy.set_timeout(boost::posix_time::seconds(60)); policy.set_timeout_type(sosscli::ObjectPolicy::Absolute); sosscli::NamedProtobufCache<StockQuote> quote_cache("Stock Quotes"); quote_cache.put("GOOG", quote, policy);
You may have noticed that the third policy
argument above was not supplied to put
calls in earlier examples. This is because the insert and put methods have a default value for the third parameter, a constant
called sosscli::ObjectPolicy::CACHE_DEFAULTS. The CACHE_DEFAULTS
constant indicates to the API that this insert/put operation does not specify any policies for the object being inserted,
and the API should instead use the policies that have been defined for the entire NamedCache instance. (See the next section for details on configuring polices for a named cache).
Note | |
---|---|
Many methods in the C++ Native Client API accept "Options" classes as parameters that allow you to perform fine tuning of the method’s behavior on a call-by-call basis (GetOptions, LockOptions, etc.). These Options classes all follow the same pattern as ObjectPolicy: They provide a CACHE_DEFAULT constant that is used as a default argument to tell the method to fall back to cache-level behavior. The examples in this guide will often avoid passing explicit values into these types of options parameters for the sake of brevity and clarity. |
Default options and policies for an entire named cache instance can be configured using the sosscli::NamedCache::DefaultCachePolicy class. This nested class is available in every named cache instance, and a reference to this object is available via the NamedCache::default_cache_policy() method:
// By default, all objects inserted into quote_cache should expire after 30 secs: sosscli::NamedProtobufCache<StockQuote> quote_cache("Stock Quotes"); quote_cache.default_cache_policy().set_timeout(boost::posix_time::seconds(30)); quote_cache.default_cache_policy().set_timeout_type(sosscli::ObjectPolicy::Absolute);
Note that any changes make to a named cache’s default cache policies are valid for only that instance of the NamedCache object. Default polices will need to be re-set if your NamedCache instance goes out of scope and is re-constructed.
The default polices for a cached object can be overridden on a call-by-call basis by providing a sosscli::ObjectPolicy object as an argument to individual insert
and put
calls. (See Policies for Individual Objects.)
Most individual named cache operations accept "options" arguments that can be used to control the call’s behavior. Methods on the NamedCache and its subclasses accept an options object whose name contains an "Options" suffix. Classes of this nature include the following:
Typical fields on these classes allow you to control how the method should behave in the event of a service error (throw_on_error
), or whether CRUD operations should use the local, in-process client cache (use_client_cache
). The C++ Native Client API reference documentation covers these Options classes in detail.
sosscli::NamedProtobufCache<StockQuote> quote_cache("Stock Quotes"); // Perform a get call that doesn't throw an exception and won't use // the in-process cache: sosscli::GetOptions<StockQuote> get_options; get_options.set_throw_on_error(false).set_use_client_cache(false); auto get_result = quote_cache.get("GOOG", get_options); auto retrieved_quote = get_result.object_ptr(); // a boost::shared_ptr std::cout << retrieved_quote->price() << std::endl;
Note that the setters on these options classes return references to the options object, which allows for the chaining of setter calls.
Like the ObjectPolicy class discussed above, all options classes provide a CACHE_DEFAULT constant member. Passing this constant as an argument to a NamedCache method will cause the call to revert to the cache-wide behavior that is configured on the NamedCache instance’s default policies (see Policies for an Entire Named Cache Instance). The CACHE_DEFAULT constant is the default argument for all NamedCache calls that take an options parameter, so options arguments can be omitted in cases where the cache defaults will suffice:
sosscli::NamedProtobufCache<StockQuote> quote_cache("Stock Quotes"); quote_cache.default_cache_policy().set_throw_on_error(false); quote_cache.default_cache_policy().set_use_client_cache(false); // Perform get() using cache defaults: auto get_result = quote_cache.get(soss_key); auto retrieved_quote = get_result.object_ptr(); std::cout << retrieved_quote->price() << std::endl;