SmellyStorage (Structured Storage)

In my previous post, Structuring my storage, I talked about purpose-built storage patterns. As I mentioned, I built a durable store for a queue that I was working on, and this is the results a proof-of-concept Spike. Since this was built for my purpose it will not do many of you much good but you are welcome to an early version of the code if you're interested.  

Implementing this is pretty easy... Here is a quick walk-through:

1.  Download the source code (SmellyStorage.zip (27.24 kb)) and compile the solution

2.  In the consuming application, add a reference to "Smelser.Storage.dll" and "Smelser.Container.dll"

3.  In the consuming application config file, register the configuration sections for the storage manager and the container

<configSections> <section name="smelser.container" type="Smelser.Container.Configuration.ContainerConfigSection, Smelser.Container" /> <section name="smelser.storage" type="Smelser.Storage.Configuration.StorageConfigSection, Smelser.Storage" /> </configSections>
 

4.  Register your concrete implementations of storage components or use the defaults

<smelser.container> <components resolver="Smelser.Container.DependencyResolver, Smelser.Container">     <component contract="Smelser.Storage.IStore, Smelser.Storage" implementation="Smelser.Storage.Store, Smelser.Storage" />
    <component contract="Smelser.Storage.IStoredItem, Smelser.Storage" implementation="Smelser.Storage.StoredItem, Smelser.Storage" />
    <component contract="Smelser.Storage.IIndex, Smelser.Storage" implementation="Smelser.Storage.Index, Smelser.Storage" />
    <component contract="Smelser.Storage.IItemIndex, Smelser.Storage" implementation="Smelser.Storage.ItemIndex, Smelser.Storage" />
</components> </smelser.container>
 

5.  Configure the max size of any single store instance

<smelser.storage maxStoreSizeInBytes="30000000" />

6.  Import the namespace into the consuming class file

using Smelser.Storage;

7.  Create a store instance

/* Create the store */ IStore store = StorageManager.CreateStore("test");

8.  Create an object to be stored... This will be different for each implementation and this is just a demo

Guid key = Guid.NewGuid(); var message = IoC.Resolve<IMessage>(); message.Id = 0x1234; byte[] bytes = message.ToBinaryMessagePayload();

9.  Store an item 

store.StoreItem(key, bytes); /* Alternatively you could make calls directly to the StoreManager */ /* to avoid managing instances, although this is slightly more performant */ /* Ex. StorageManager.StoreItem("test", key, bytes); */

10.  Remove a single item from the store 

store.RemoveItem(key);

11.  Retrieve an item from the store and re-translate it into a full object. Keep in mind this does not remove it

IStoredItem storedItem = store.RetrieveItem(guid); /* Alternatively you could make make calls directory to the StoreManager */ /* to avoid managing instances, although this is slightly more performant */ /* Ex. IStoredItem storedItem = StorageManager.RetrieveItem("test", guid); */ IMessage returnMessage = storedItem.Bytes.ToMessage();

12.  Remove all items from the store

store.Clear();

13.  Close the store and persist all items to disk. Technically, the items are written to disk when they are stored, however the store index is only written periodically. 

/* Close the store which will persist any remaining values */ store.Close();

14.  Remove all items and delete the store files from the disk 

/* Delete the store and index files */ store.Purge();

 

Thats it...