|
|
|
|
|
|
|
|
|
Code Examples
|
This page contains an assortment code snippets that serve to demonstrate how Persistore is
actually used in application code.
C# - Creating a shared dictionary.
A shared dictionary is a managed .Net object that encapsulates a reference to a kernel
managed collection. The shared dictionary class appears to be a conventional collection
class, but the data in the collection is not stored in the managed heap. The data is
stored in shared memory, within a datapool.
If the datapool is persistent, then all of the items that you add to the dictionary
are persistent too. It is therefore extremely simple to rapidly persist data by persisting
individual items. The design does not simply persist a dictionary, rather it persists items
as and when they are added and provides a dictionary-like wrapper that allows your
code to treat the data as a dictionary.
This snippet shows how a shared/persistent dictionary can be created, populated
and modified. A shared dictionary element may also be accessed and modfied using express
data access, although this is not part of this example.
class Program
{
static void Main(string[] args)
{
Datapool pool;
Dir collections_dir;
DataStruct test_item;
SharedDictionary<string, DataStruct> strucs;
test_item = default(DataStruct);
pool = new Datapool();
pool.Load("test_dictionary_pool", 50000, FileMode.Create);
if (pool.IsLoaded == false)
throw
new
InvalidOperationException
("Unable to load the specified datapool.");
collections_dir = pool.CreateDir("Collections");
strucs = new SharedDictionary<string, DataStruct>(collections_dir, "test_dictionary");
/* Add an item */
test_item.Count = 1;
test_item.Name = "john";
strucs.Add("first",test_item);
/* Add an item */
test_item.Count = 2;
test_item.Name = "mike";
strucs.Add("second",test_item);
/* Add an item */
test_item.Count = 3;
test_item.Name = "mike";
strucs.Add("third",test_item);
/* Overwrite the first item */
strucs["first"] = test_item;
}
}
C# - Loading and initializing a datapool
This snippet shows how straightfoward it is to create and load a new datapool.
Once loaded it becomes possible to create directories, shared variables etc as well
as persist objects. Simply by terminating the application, all data will be safely retained and visible
when next loaded.
{
Datapool pool;
// Create a datapool object and specify an init delegate.
pool = new Datapool(initialize_pool);
// Load (i.e. map and initialize) a 2 GB datapool
// During this method call, the init handler will
// be invoked.
pool.Load(AllocationMode.Standard,
AccessMode.Unprotected,
BackingMode.Persistent,
StorageMode.DynamicCompressed,
datapool_path,
Sizing.GigaBytes(2),
FileMode.CreateNew,
false);
}
// If the pool is new and no other thread in any other
// process is already doing an init, then this handler
// will be called before the call to 'Load' completes.
private void initialize_pool (Datapool new_pool)
{
// The second arg below, is an info string. It is shown by a
// tooltip when the mouse hovers over the dir node in the
// Datapool Explorer utility.
new_pool.Root.CreateDir ("MyTestDir","A test dir for demo purposes");
}
C# - Using express data access.
Express Data Access is a powerful feature built-in to Persistore. In essence, it provides
a way for application code to "ask" for a .Net memory memory reference to a persisted item.
Persistore then identifies, locates or searches for the item, if the item exists
a memory reference to it is created and a user defined update handler is invoked
and the reference passed in as an argument.
Because the item does not need to be copied, instantiated, moved, deserialized or
reflected upon, the update handler can perform updates to the item's field or properties
extremely rapidly.
This snippet shows how instances of persisted structs may be accessed and updated
in real-time using Express Data Access. The reference that is passed to the updater
method is a real reference that points to the persisted instance in the mapped
datapool memory space.
{
ExpressAccessResult status;
// Define the express access update handler.
// Express data access is supported by several classes
// including cursors, dictionaries and shared variables.
strucs.ItemAccessed += update_handler;
// Find and update the required instance. This operation
// will search the collection's index for the key
// and if found, will set a write lock on the datum and
// invoked the express update handler.
status = strucs.ExpressAccess(SearchCriteria.Equal,
"mike",
SpinlockType.WriteLock);
if (status == ExpressAccessResult.NoMatchingItem)
{
// Error, no item was found with the specified key...
}
}
// This update handler will be called by persistore and passed a
// reference to the persisted instance of a data structure.
// The ref is (in effect) a pointer to the actual persisted
// item's memory block. Thus we are able to update the item in-situ and
// completely avoid the copying and moving of the data item.
private static ExpressAccessResult update_handler (ref DataStruct item)
{
if (item.Flag == 0)
{
item.Flag = 1;
item.Count = 1;
return(ExpressAccessResult.BasicUpdatesMade);
}
// Tell the system that no updates were made.
return (ExpressAccessResult.NoUpdatesMade);
}
C# - Using index attributes and proxy fields.
This snippet shows how you can decorate a class or struct with attributes
that direct persistore to create and populate indices. These indices can
be used for subsequent high performance accessing and updating of your
data. The snippet also shows how strings can be embedded in a type without
restricting the type's supported persistence modes. In a real implementaion
it is preferable to use partial structs for separating the member field
defintions from the various access properties.
/// <summary>
/// A hypothetical fixed income bond defintion.
/// </summary>
/// <remarks>
/// This structure is an example of a "pure" struct, one that contains
/// no reference type instance fields. Because of this instances of it
/// may be persisted rapdily and can be later updated using persistore's
/// express data access (EDA) support.
/// Despite not containing refernce fields, we can still store string
/// data by using "proxy" fields and special properties.
/// </remarks>
public unsafe struct Bond
{
private decimal accrued_interest;
private decimal coupon_rate;
private decimal current_yield;
private decimal current_ytm;
private DateTime maturity_date;
private decimal face_value;
private decimal redemption_value;
/*-----------------------------------------------------------------------*/
/* These two fields are referred to as "proxy" fields in persistore. */
/* They are the means by which strings (either ANSI or Unicode) may be */
/* exposed as properties by a class or struct, while internally being */
/* implemented as fixed buffers (either Byte or Char). This allows the */
/* system to employ high performance persistence modes that do not allow */
/* reference types member fields. */
/*-----------------------------------------------------------------------*/
private Byte_8 bond_symbol; // a proxy field.
private Byte_64 bond_name; // a proxy field.
public decimal AccruedInterest
{
get { return accrued_interest; }
}
public decimal CouponRate
{
get { return coupon_rate; }
}
public decimal CurrentYield
{
get { return current_yield; }
}
public decimal CurremtYtm
{
get { return current_ytm; }
}
public DateTime MaturityDate
{
get { return maturity_date; }
}
public decimal FaceValue
{
get { return face_value; }
}
public decimal MaturityValue
{
get { return redemption_value; }
}
/*----------------------------------------------------------------*/
/* This property will be used by persistore to extract key values */
/* for the symbol. This is done when instances of the struct are */
/* are written using a Cursor<Bond> object. This also allows */
/* other code to perform searches and updates on the item by */
/* using the "Symbol" to locate the persisted item. */
/*----------------------------------------------------------------*/
[Indexed("Symbol", "Security Symbol", Disposition.NoDuplicates, Collation.Ascending)]
public string Symbol
{
// Create and return a managed string from the fixed buffer, or copy the data
// in a string into the fixed buffer.
get
{
fixed (byte* p = bond_symbol.buffer)
return (StringWrapper.ANSIPtrToString(p, Marshal.SizeOf(bond_symbol)));
}
set
{
fixed (byte* p = bond_symbol.buffer)
StringWrapper.StringToANSIPtr(value, p, Marshal.SizeOf(bond_symbol));
}
}
[Indexed("Name", "Security Name", Disposition.Duplicates, Collation.Ascending)]
public string Name
{
// Create and return a managed string from the fixed buffer, or copy the data
// in a string into the fixed buffer.
get
{
fixed (byte* p = bond_name.buffer)
return (StringWrapper.ANSIPtrToString(p, Marshal.SizeOf(bond_name)));
}
set
{
fixed (byte* p = bond_name.buffer)
StringWrapper.StringToANSIPtr(value, p, Marshal.SizeOf(bond_name));
}
}
}
///
/// Helper types for simplifying proxy field coding.
///
public unsafe struct Byte_8 { internal fixed byte buffer[8]; }
public unsafe struct Byte_64 { internal fixed byte buffer[64];}
|
|
|
|
|
|
|
|
|
|
 |
All content copyright
© 2006 - 2010 Morantex Information Systems, Inc.
Morantex™, Persistore™,
MAQS™ and NoIO™ are trademarks of
Morantex Information Systems, Inc.
|
 |
|
|
Number of site visits: 5125 |
|
|
|
|