<?xml version="1.0"?><?xml-stylesheet type="text/xsl" href="/rss.xsl"?><rss version="2.0"><channel><title>ManagedEsent Wiki &amp; Documentation Rss Feed</title><link>http://www.codeplex.com/ManagedEsent/Wiki/View.aspx?title=Home</link><description>ManagedEsent Wiki Rss Description</description><item><title>New Comment on "PersistentDictionaryDocumentation"</title><link>http://managedesent.codeplex.com/wikipage?title=PersistentDictionaryDocumentation&amp;ANCHOR#C26779</link><description>I love this thing. It&amp;#39;s every thing I needed and then some. Thanks for making this, you&amp;#39;re awesome &amp;#58;&amp;#41;</description><author>Grimbly</author><pubDate>Tue, 05 Mar 2013 23:19:08 GMT</pubDate><guid isPermaLink="false">New Comment on "PersistentDictionaryDocumentation" 20130305111908P</guid></item><item><title>New Comment on "Documentation"</title><link>http://managedesent.codeplex.com/documentation?&amp;ANCHOR#C22127</link><description>Thanx for this documentation and code snippets.</description><author>hindermath</author><pubDate>Thu, 05 Jan 2012 07:39:22 GMT</pubDate><guid isPermaLink="false">New Comment on "Documentation" 20120105073922A</guid></item><item><title>New Comment on "ManagedEsentSample"</title><link>http://managedesent.codeplex.com/wikipage?title=ManagedEsentSample&amp;ANCHOR#C22120</link><description>Cool, works as designed &amp;#58;-&amp;#41;&amp;#33; Fine work... much more coming in other database parts&amp;#63; Perfect NoSQL database without use of a comples server.</description><author>hindermath</author><pubDate>Wed, 04 Jan 2012 23:57:35 GMT</pubDate><guid isPermaLink="false">New Comment on "ManagedEsentSample" 20120104115735P</guid></item><item><title>New Comment on "PersistentDictionaryDocumentation"</title><link>http://managedesent.codeplex.com/wikipage?title=PersistentDictionaryDocumentation&amp;ANCHOR#C19231</link><description>awesome&amp;#33;</description><author>kpoxa</author><pubDate>Mon, 11 Apr 2011 11:27:46 GMT</pubDate><guid isPermaLink="false">New Comment on "PersistentDictionaryDocumentation" 20110411112746A</guid></item><item><title>Updated Wiki: StockSample</title><link>http://managedesent.codeplex.com/wikipage?title=StockSample&amp;version=5</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;ManagedEsent Stock Example&lt;/h1&gt;
This sample code creates a database of stock prices and performs some basic queries and updates. This sample is included in the ManagedEsent release.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Create a sample database containing some stock prices and&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; perform some basic queries.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; StockSample
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Name of the table that will store the prices.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;const&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; TableName = &lt;span style="color:#A31515;"&gt;&amp;quot;stocks&amp;quot;&lt;/span&gt;;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Columnid of the stock symbol.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; JET_COLUMNID columnidSymbol;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Columnid of the company name.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; JET_COLUMNID columnidName;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Columnid of the stock price.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; JET_COLUMNID columnidPrice;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Columnid of the number of shares owned.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; JET_COLUMNID columnidShares;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Called on program startup.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; Main()
    {
        Console.WriteLine();

        &lt;span style="color:Blue;"&gt;const&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; DatabaseName = &lt;span style="color:#A31515;"&gt;&amp;quot;stocksample.edb&amp;quot;&lt;/span&gt;;

        &lt;span style="color:Green;"&gt;// First create the database. A real application would probably&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// check for the database first and only create it if needed.&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// Checking for the database can be done with File.Exists or&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// by calling JetAttachDatabase and seeing if a JET_ERR.DatabaseNotFound&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// error is thrown. (Check the Error property of the&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// EsentErrorException).&lt;/span&gt;
        CreateDatabase(DatabaseName);

        &lt;span style="color:Green;"&gt;// Now the database has been created we can attach to it.&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// The Instance object we create is disposable, so the underlying ESENT&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// resource can be freed. The disposable objects wrapped around ESENT resources&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// _must_ be disposed properly. ESENT resources must be freed in a&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// specific order, which the finalizer doesn&amp;#39;t necessarily respect.&lt;/span&gt;
        &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; instance = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Instance(&lt;span style="color:#A31515;"&gt;&amp;quot;stocksample&amp;quot;&lt;/span&gt;))
        {
            &lt;span style="color:Green;"&gt;// Creating an Instance object doesn&amp;#39;t call JetInit. &lt;/span&gt;
            &lt;span style="color:Green;"&gt;// This is done to allow some parameters to be set&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// before the instance is initialized.&lt;/span&gt;

            &lt;span style="color:Green;"&gt;// Circular logging is very useful; it automatically deletes&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// logfiles that are no longer needed. Most applications&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// should use it.&lt;/span&gt;
            instance.Parameters.CircularLog = &lt;span style="color:Blue;"&gt;true&lt;/span&gt;;

            &lt;span style="color:Green;"&gt;// Initialize the instance. This creates the logs and temporary database.&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// If logs are present in the log directory then recovery will run&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// automatically.&lt;/span&gt;
            instance.Init();

            &lt;span style="color:Green;"&gt;// Create a disposable wrapper around a new JET_SESID. All database&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// access is done with a session (JET_SESID). Transactions and database&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// record visibility is per-session. Do not share sessions between&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// threads, instead create different sessions for different threads.&lt;/span&gt;
            &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; session = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Session(instance))
            {
                JET_DBID dbid;

                &lt;span style="color:Green;"&gt;// The database only has to be attached once per instance, but each&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// session has to open the database. Redundant JetAttachDatabase calls&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// are safe to make though.&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// Here we use the fact that Instance, Session, and Table objects all have&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// implicit conversions to the underlying JET_* types. This allows the&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// disposable wrappers to be used with any APIs that expect the JET_*&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// structures.&lt;/span&gt;
                Api.JetAttachDatabase(session, DatabaseName, AttachDatabaseGrbit.None);
                Api.JetOpenDatabase(session, DatabaseName, &lt;span style="color:Blue;"&gt;null&lt;/span&gt;, &lt;span style="color:Blue;"&gt;out&lt;/span&gt; dbid, OpenDatabaseGrbit.None);

                &lt;span style="color:Green;"&gt;// Create a disposable wrapper around the JET_TABLEID.&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// A JET_TABLEID acts as a database cursor, it can be used to:&lt;/span&gt;
                &lt;span style="color:Green;"&gt;//  - Seek to a record&lt;/span&gt;
                &lt;span style="color:Green;"&gt;//  - Retrieve columns from a record&lt;/span&gt;
                &lt;span style="color:Green;"&gt;//  - Insert/Update/Delete a record&lt;/span&gt;
                &lt;span style="color:Green;"&gt;//  - Move to the next/previous record&lt;/span&gt;
                &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; table = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Table(session, dbid, TableName, OpenTableGrbit.None))
                {
                    &lt;span style="color:Green;"&gt;// Load the columnids from the table. This should be done each time the database is attached&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// because an offline defrag (esentutl /d) can change the name =&amp;gt; columnid mapping.&lt;/span&gt;
                    IDictionary&amp;lt;&lt;span style="color:Blue;"&gt;string&lt;/span&gt;, JET_COLUMNID&amp;gt; columnids = Api.GetColumnDictionary(session, table);
                    columnidSymbol = columnids[&lt;span style="color:#A31515;"&gt;&amp;quot;symbol&amp;quot;&lt;/span&gt;];
                    columnidName = columnids[&lt;span style="color:#A31515;"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;];
                    columnidPrice = columnids[&lt;span style="color:#A31515;"&gt;&amp;quot;price&amp;quot;&lt;/span&gt;];
                    columnidShares = columnids[&lt;span style="color:#A31515;"&gt;&amp;quot;shares_owned&amp;quot;&lt;/span&gt;];

                    &lt;span style="color:Green;"&gt;// Dump records by the primary index; this will be in stock symbol order.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Populating the table&amp;quot;&lt;/span&gt;);
                    PopulateTable(session, table);
                    DumpByIndex(session, table, &lt;span style="color:Blue;"&gt;null&lt;/span&gt;);

                    &lt;span style="color:Green;"&gt;// The shares index is sparse; it only contains records where the&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// shares_owned column is non null.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Owned shares&amp;quot;&lt;/span&gt;);
                    DumpByIndex(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;shares&amp;quot;&lt;/span&gt;);

                    &lt;span style="color:Green;"&gt;// The noshares index is sparse; it only contains records where the&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// shares_owned column is null.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Companies with no owned shares&amp;quot;&lt;/span&gt;);
                    DumpByIndex(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;noshares&amp;quot;&lt;/span&gt;);

                    &lt;span style="color:Green;"&gt;// Use the price index to find stocks sorted by price.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Sorted by price&amp;quot;&lt;/span&gt;);
                    DumpByIndex(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;price&amp;quot;&lt;/span&gt;);

                    &lt;span style="color:Green;"&gt;// Seek to, and update an existing record.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Updating owned shares&amp;quot;&lt;/span&gt;);
                    BuyShares(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;SBUX&amp;quot;&lt;/span&gt;, 50);
                    BuyShares(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;MSFT&amp;quot;&lt;/span&gt;, 100);
                    DumpByIndex(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;shares&amp;quot;&lt;/span&gt;);

                    &lt;span style="color:Green;"&gt;// Delete a record.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Deleting EBAY&amp;quot;&lt;/span&gt;);
                    DeleteStock(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;EBAY&amp;quot;&lt;/span&gt;);
                    DumpByIndex(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;);

                    &lt;span style="color:Green;"&gt;// Create an index range over a prefix.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Company names starting with &amp;#39;app&amp;#39;&amp;quot;&lt;/span&gt;);
                    DumpByNamePrefix(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;app&amp;quot;&lt;/span&gt;);

                    &lt;span style="color:Green;"&gt;// Create an empty index range.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Company names starting with &amp;#39;xyz&amp;#39;&amp;quot;&lt;/span&gt;);
                    DumpByNamePrefix(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;xyz&amp;quot;&lt;/span&gt;);

                    &lt;span style="color:Green;"&gt;// Create an index range over multiple records.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Company names starting with &amp;#39;m&amp;#39;&amp;quot;&lt;/span&gt;);
                    DumpByNamePrefix(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;m&amp;quot;&lt;/span&gt;);

                    &lt;span style="color:Green;"&gt;// Move to the start of an index.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Lowest price&amp;quot;&lt;/span&gt;);
                    Api.JetSetCurrentIndex(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;price&amp;quot;&lt;/span&gt;);
                    Api.JetMove(session, table, JET_Move.First, MoveGrbit.None);
                    PrintOneRow(session, table);
                    Console.WriteLine();

                    &lt;span style="color:Green;"&gt;// Move to the end of an index.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Highest price&amp;quot;&lt;/span&gt;);
                    Api.JetSetCurrentIndex(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;price&amp;quot;&lt;/span&gt;);
                    Api.JetMove(session, table, JET_Move.Last, MoveGrbit.None);
                    PrintOneRow(session, table);
                    Console.WriteLine();

                    &lt;span style="color:Green;"&gt;// Create a index range between two values.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Prices fom $10-$20&amp;quot;&lt;/span&gt;);
                    DumpPriceRange(session, table, 1000, 2000);

                    &lt;span style="color:Green;"&gt;// Use intersect indexes to find records that meet multiple criteria.&lt;/span&gt;
                    Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;** Select by name and price&amp;quot;&lt;/span&gt;);
                    IntersectIndexes(session, table, &lt;span style="color:#A31515;"&gt;&amp;quot;Apple&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Pear&amp;quot;&lt;/span&gt;, 1000, 2000);
                }
            }
        }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Dump all records from the index.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table to dump.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;index&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The index to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; DumpByIndex(JET_SESID sesid, JET_TABLEID tableid, &lt;span style="color:Blue;"&gt;string&lt;/span&gt; index)
    {
        Api.JetSetCurrentIndex(sesid, tableid, index);
        PrintAllRecords(sesid, tableid);
        Console.WriteLine();
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Populate the stock table with a set of symbols and prices.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; PopulateTable(JET_SESID sesid, JET_TABLEID tableid)
    {
        &lt;span style="color:Green;"&gt;// Create a disposable wrapper around JetBeginTransaction and JetCommitTransaction.&lt;/span&gt;
        &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; transaction = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Transaction(sesid))
        {
            InsertOneStock(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;SBUX&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Starbucks Corp.&amp;quot;&lt;/span&gt;, 988, 0);
            InsertOneStock(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;MSFT&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Microsoft Corp.&amp;quot;&lt;/span&gt;, 1965, 200);
            InsertOneStock(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;AAPL&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Apple Inc.&amp;quot;&lt;/span&gt;, 9000, 0);
            InsertOneStock(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;GOOG&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Google Inc.&amp;quot;&lt;/span&gt;, 31017, 0);
            InsertOneStock(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;M&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Macy&amp;#39;s Inc.&amp;quot;&lt;/span&gt;, 1062, 0);
            InsertOneStock(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;MCD&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;MacDonald&amp;#39;s Corp.&amp;quot;&lt;/span&gt;, 1062, 0);
            InsertOneStock(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;GE&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;General Electric Company&amp;quot;&lt;/span&gt;, 1650, 0);
            InsertOneStock(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;MMM&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;3M Company&amp;quot;&lt;/span&gt;, 5662, 100);
            InsertOneStock(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;IBM&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;International Business Machines Corp.&amp;quot;&lt;/span&gt;, 8352, 150);
            InsertOneStock(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;EBAY&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;eBay Inc.&amp;quot;&lt;/span&gt;, 1445, 0);

            &lt;span style="color:Green;"&gt;// Commit the transaction at the end of the using block!&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// If transaction.Commit isn&amp;#39;t called then the transaction will &lt;/span&gt;
            &lt;span style="color:Green;"&gt;// automatically rollback when disposed (throwing away&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// the records that were just inserted).&lt;/span&gt;
            transaction.Commit(CommitTransactionGrbit.None);
        }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Insert information about one stock into the table.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;remarks&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session must already be in a transaction.&amp;lt;/remarks&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table to insert into.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;symbol&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The stock symbol.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;name&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The name of the company.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;price&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The current price.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sharesOwned&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;Number of shares owned.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; InsertOneStock(
        JET_SESID sesid,
        JET_TABLEID tableid,
        &lt;span style="color:Blue;"&gt;string&lt;/span&gt; symbol,
        &lt;span style="color:Blue;"&gt;string&lt;/span&gt; name,
        &lt;span style="color:Blue;"&gt;int&lt;/span&gt; price,
        &lt;span style="color:Blue;"&gt;int&lt;/span&gt; sharesOwned)
    {
        &lt;span style="color:Green;"&gt;// Prepare an update, set some columns, and then save the update.&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// First create a disposable wrapper around JetPrepareUpdate and JetUpdate.&lt;/span&gt;
        &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; update = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Update(sesid, tableid, JET_prep.Insert))
        {
            Api.SetColumn(sesid, tableid, columnidSymbol, symbol, Encoding.Unicode);
            Api.SetColumn(sesid, tableid, columnidName, name, Encoding.Unicode);
            Api.SetColumn(sesid, tableid, columnidPrice, price);

            &lt;span style="color:Green;"&gt;// This column defaults to null. Only set it if we have some shares.&lt;/span&gt;
            &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (0 != sharesOwned)
            {
                Api.SetColumn(sesid, tableid, columnidShares, sharesOwned);
            }

            &lt;span style="color:Green;"&gt;// Save the update at the end of the using block!&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// If update.Save isn&amp;#39;t called then the update will &lt;/span&gt;
            &lt;span style="color:Green;"&gt;// be canceled when disposed (and the record won&amp;#39;t&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// be inserted).&lt;/span&gt;
            &lt;span style="color:Green;"&gt;//&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// Inserting a record does not change the location of&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// the cursor (JET_TABLEID); it will have the same&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// location that it did before the insert.&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// To insert a record and then position the cursor&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// on the record, use Update.SaveAndGotoBookmark. That&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// call uses the bookmark returned from JetUpdate to&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// position the tableid on the new record.&lt;/span&gt;
            update.Save();
        }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Increment the number of shares for a specified symbol.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table to insert into.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;symbol&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The stock symbol to buy.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;shares&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The number of shares to buy.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; BuyShares(
        JET_SESID sesid,
        JET_TABLEID tableid,
        &lt;span style="color:Blue;"&gt;string&lt;/span&gt; symbol,
        &lt;span style="color:Blue;"&gt;int&lt;/span&gt; shares)
    {
        &lt;span style="color:Green;"&gt;// Seek to the record, get the current value of the column,&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// prepare an update, set the column to the new value and the&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// save the update.&lt;/span&gt;
        &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; transaction = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Transaction(sesid))
        {
            SeekToSymbol(sesid, tableid, symbol);
            &lt;span style="color:Blue;"&gt;int&lt;/span&gt; currentShares = Api.RetrieveColumnAsInt32(sesid, tableid, columnidShares).GetValueOrDefault();
            &lt;span style="color:Blue;"&gt;int&lt;/span&gt; newShares = currentShares + shares;

            &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; update = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Update(sesid, tableid, JET_prep.Replace))
            {
                Api.SetColumn(sesid, tableid, columnidShares, newShares);

                &lt;span style="color:Green;"&gt;// Save the update at the end of the using block!&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// If update.Save isn&amp;#39;t called then the update will &lt;/span&gt;
                &lt;span style="color:Green;"&gt;// be cancelled when disposed (undoing the updates &lt;/span&gt;
                &lt;span style="color:Green;"&gt;// to the record).&lt;/span&gt;
                update.Save();
            }

            &lt;span style="color:Green;"&gt;// Commit the transaction at the end of the using block!&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// If transaction.Commit isn&amp;#39;t called then the transaction will &lt;/span&gt;
            &lt;span style="color:Green;"&gt;// automatically rollback when disposed (throwing away&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// the changes to the record).&lt;/span&gt;
            transaction.Commit(CommitTransactionGrbit.None);
        }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Delete the stock with the given symbol.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table cursor to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;symbol&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The symbol to delete.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; DeleteStock(JET_SESID sesid, JET_TABLEID tableid, &lt;span style="color:Blue;"&gt;string&lt;/span&gt; symbol)
    {
        &lt;span style="color:Green;"&gt;// Seek to the record and delete it.&lt;/span&gt;
        &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; transaction = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Transaction(sesid))
        {
            SeekToSymbol(sesid, tableid, symbol);
            Api.JetDelete(sesid, tableid);

            &lt;span style="color:Green;"&gt;// Commit the transaction at the end of the using block!&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// If transaction.Commit isn&amp;#39;t called then the transaction will &lt;/span&gt;
            &lt;span style="color:Green;"&gt;// automatically rollback when disposed (undeleting the record).&lt;/span&gt;
            transaction.Commit(CommitTransactionGrbit.None);
        }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Find the record with the given stock symbol.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table to dump the records from.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;symbol&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The symbol to seek for.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; SeekToSymbol(JET_SESID sesid, JET_TABLEID tableid, &lt;span style="color:Blue;"&gt;string&lt;/span&gt; symbol)
    {
        &lt;span style="color:Green;"&gt;// We need to be on the primary index (which indexes the &amp;#39;symbol&amp;#39; column).&lt;/span&gt;
        Api.JetSetCurrentIndex(sesid, tableid, &lt;span style="color:Blue;"&gt;null&lt;/span&gt;);
        Api.MakeKey(sesid, tableid, symbol, Encoding.Unicode, MakeKeyGrbit.NewKey);

        &lt;span style="color:Green;"&gt;// This seek expects the record to be present. To test for a record&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// use TrySeek(), which won&amp;#39;t throw an exception if the record isn&amp;#39;t&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// found.&lt;/span&gt;
        Api.JetSeek(sesid, tableid, SeekGrbit.SeekEQ);
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Dump all records where the name has the given prefix.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table to dump.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;namePrefix&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The prefix to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; DumpByNamePrefix(JET_SESID sesid, JET_TABLEID tableid, &lt;span style="color:Blue;"&gt;string&lt;/span&gt; namePrefix)
    {
        &lt;span style="color:Green;"&gt;// We are about to set up an index range on the name index.&lt;/span&gt;
        Api.JetSetCurrentIndex(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;);

        &lt;span style="color:Green;"&gt;// First, seek to the beginning of the range.&lt;/span&gt;
        Api.MakeKey(sesid, tableid, namePrefix, Encoding.Unicode, MakeKeyGrbit.NewKey);
        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (Api.TrySeek(sesid, tableid, SeekGrbit.SeekGE))
        {
            &lt;span style="color:Green;"&gt;// We are on the first record with name &amp;gt;= namePrefix. This record may not&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// be in the index range! We will now set the end of the index range, which&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// will tell us if the range is empty.&lt;/span&gt;
            Api.MakeKey(sesid, tableid, namePrefix, Encoding.Unicode, MakeKeyGrbit.NewKey | MakeKeyGrbit.SubStrLimit);
            &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (Api.TrySetIndexRange(sesid, tableid, SetIndexRangeGrbit.RangeUpperLimit | SetIndexRangeGrbit.RangeInclusive))
            {
                &lt;span style="color:Green;"&gt;// There are records in the range. We can now iterate through the range.&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// When the end of the range is hit we will get a &amp;#39;no more records&amp;#39; error and&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// the range will be removed (so subsequent moves will go to the end of the table).&lt;/span&gt;
                PrintRecordsToEnd(sesid, tableid);
            }
        }

        Console.WriteLine();
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Dump all records from the index whose price is in the given range.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table to dump.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;low&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The low end of the price range.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;high&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The high end of the price range.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; DumpPriceRange(JET_SESID sesid, JET_TABLEID tableid, &lt;span style="color:Blue;"&gt;int&lt;/span&gt; low, &lt;span style="color:Blue;"&gt;int&lt;/span&gt; high)
    {
        &lt;span style="color:Green;"&gt;// We are about to set up an index range on the price index.&lt;/span&gt;
        Api.JetSetCurrentIndex(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;price&amp;quot;&lt;/span&gt;);

        &lt;span style="color:Green;"&gt;// First, seek to the beginning of the range.&lt;/span&gt;
        Api.MakeKey(sesid, tableid, low, MakeKeyGrbit.NewKey);
        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (Api.TrySeek(sesid, tableid, SeekGrbit.SeekGE))
        {
            Api.MakeKey(sesid, tableid, high, MakeKeyGrbit.NewKey);
            &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (Api.TrySetIndexRange(sesid, tableid, SetIndexRangeGrbit.RangeUpperLimit))
            {
                &lt;span style="color:Green;"&gt;// There are records in the range. We can now iterate through the range.&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// When the end of the range is hit we will get a &amp;#39;no more records&amp;#39; error and&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// the range will be removed (so subsequent moves will go to the end of the table).&lt;/span&gt;
                PrintRecordsToEnd(sesid, tableid);
            }
        }

        Console.WriteLine();
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Print records for companies whose name is between firstName and lastName and whose&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; price is between lowPrice and highPrice. This is done by intersecting two different&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; indexes, which can be an efficient way of finding records that meet multiple criteria.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;fromName&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The first name of the companies to dump.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;toName&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The last name of the companies to dump.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;lowPrice&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The lowest price to dump.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;highPrice&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The highest price to dump.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; IntersectIndexes(
        JET_SESID sesid,
        JET_TABLEID tableid,
        &lt;span style="color:Blue;"&gt;string&lt;/span&gt; fromName,
        &lt;span style="color:Blue;"&gt;string&lt;/span&gt; toName,
        &lt;span style="color:Blue;"&gt;int&lt;/span&gt; lowPrice,
        &lt;span style="color:Blue;"&gt;int&lt;/span&gt; highPrice)
    {
        &lt;span style="color:Green;"&gt;// We need one cursor for each index. Remember to close these cursors&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// to avoid resource leaks. Here we use JetDupCursor, but JetOpenTable&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// would work as well.&lt;/span&gt;
        JET_TABLEID nameIndex;
        Api.JetDupCursor(sesid, tableid, &lt;span style="color:Blue;"&gt;out&lt;/span&gt; nameIndex, DupCursorGrbit.None);
        Api.JetSetCurrentIndex(sesid, nameIndex, &lt;span style="color:#A31515;"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;);

        JET_TABLEID priceIndex;
        Api.JetDupCursor(sesid, tableid, &lt;span style="color:Blue;"&gt;out&lt;/span&gt; priceIndex, DupCursorGrbit.None);
        Api.JetSetCurrentIndex(sesid, priceIndex, &lt;span style="color:#A31515;"&gt;&amp;quot;price&amp;quot;&lt;/span&gt;);

        &lt;span style="color:Green;"&gt;// Set the index range on the name index&lt;/span&gt;
        Api.MakeKey(sesid, nameIndex, fromName, Encoding.Unicode, MakeKeyGrbit.NewKey);
        Api.JetSeek(sesid, nameIndex, SeekGrbit.SeekLE);
        Api.MakeKey(sesid, nameIndex, toName, Encoding.Unicode, MakeKeyGrbit.NewKey);
        Api.JetSetIndexRange(sesid, nameIndex, SetIndexRangeGrbit.RangeInclusive | SetIndexRangeGrbit.RangeUpperLimit);

        &lt;span style="color:Green;"&gt;// Set the index range on the prices&lt;/span&gt;
        Api.MakeKey(sesid, priceIndex, lowPrice, MakeKeyGrbit.NewKey);
        Api.JetSeek(sesid, priceIndex, SeekGrbit.SeekLE);
        Api.MakeKey(sesid, priceIndex, highPrice, MakeKeyGrbit.NewKey);
        Api.JetSetIndexRange(sesid, priceIndex, SetIndexRangeGrbit.RangeInclusive | SetIndexRangeGrbit.RangeUpperLimit);

        &lt;span style="color:Green;"&gt;// This call will generate a set of bookmarks. The bookmarks are&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// returned in primary key order (for this table that will be symbol&lt;/span&gt;
        &lt;span style="color:Green;"&gt;// order).&lt;/span&gt;
        &lt;span style="color:Blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color:Blue;"&gt;byte&lt;/span&gt;[] bookmark &lt;span style="color:Blue;"&gt;in&lt;/span&gt; Api.IntersectIndexes(sesid, nameIndex, priceIndex))
        {
            Api.JetGotoBookmark(sesid, tableid, bookmark, bookmark.Length);
            PrintOneRow(sesid, tableid);
        }

        Console.WriteLine();

        Api.JetCloseTable(sesid, nameIndex);
        Api.JetCloseTable(sesid, priceIndex);
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Print all rows in the table.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table to dump the records from.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; PrintAllRecords(JET_SESID sesid, JET_TABLEID tableid)
    {
        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (Api.TryMoveFirst(sesid, tableid))
        {
            PrintRecordsToEnd(sesid, tableid);
        }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Print records from the current point to the end of the table.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table to dump the records from.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; PrintRecordsToEnd(JET_SESID sesid, JET_TABLEID tableid)
    {
        &lt;span style="color:Blue;"&gt;do&lt;/span&gt;
        {
            PrintOneRow(sesid, tableid);
        }
        &lt;span style="color:Blue;"&gt;while&lt;/span&gt; (Api.TryMoveNext(sesid, tableid));
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Print the current record.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The table to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; PrintOneRow(JET_SESID sesid, JET_TABLEID tableid)
    {
        &lt;span style="color:Blue;"&gt;string&lt;/span&gt; symbol = Api.RetrieveColumnAsString(sesid, tableid, columnidSymbol);
        &lt;span style="color:Blue;"&gt;string&lt;/span&gt; name = Api.RetrieveColumnAsString(sesid, tableid, columnidName);

        &lt;span style="color:Green;"&gt;// This column can&amp;#39;t be null so we cast to an int.&lt;/span&gt;
        &lt;span style="color:Blue;"&gt;int&lt;/span&gt; price = (&lt;span style="color:Blue;"&gt;int&lt;/span&gt;)Api.RetrieveColumnAsInt32(sesid, tableid, columnidPrice);

        &lt;span style="color:Green;"&gt;// This column can be null so we keep the nullable type.&lt;/span&gt;
        &lt;span style="color:Blue;"&gt;int&lt;/span&gt;? shares = Api.RetrieveColumnAsInt32(sesid, tableid, columnidShares);

        Console.Write(&lt;span style="color:#A31515;"&gt;&amp;quot;\t{0,-40} {1,-4} ${2,-6}&amp;quot;&lt;/span&gt;, name, symbol, price / 100.0);
        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (shares.HasValue)
        {
            Console.Write(&lt;span style="color:#A31515;"&gt;&amp;quot; {0} shares&amp;quot;&lt;/span&gt;, shares);
        }

        Console.WriteLine();
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Create a new database. Create the table, columns, and indexes.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;database&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;Name of the database to create.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; CreateDatabase(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; database)
    {
        &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; instance = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Instance(&lt;span style="color:#A31515;"&gt;&amp;quot;createdatabase&amp;quot;&lt;/span&gt;))
        {
            instance.Init();
            &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; session = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Session(instance))
            {
                JET_DBID dbid;
                Api.JetCreateDatabase(session, database, &lt;span style="color:Blue;"&gt;null&lt;/span&gt;, &lt;span style="color:Blue;"&gt;out&lt;/span&gt; dbid, CreateDatabaseGrbit.OverwriteExisting);
                &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; transaction = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Transaction(session))
                {
                    &lt;span style="color:Green;"&gt;// A newly created table is opened exclusively. This is necessary to add&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// a primary index to the table (a primary index can only be added if the table&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// is empty and opened exclusively). Columns and indexes can be added to a &lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// table which is opened normally.&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// The other way to create a table is to use JetCreateTableColumnIndex to&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// add all columns and indexes with one call.&lt;/span&gt;
                    JET_TABLEID tableid;
                    Api.JetCreateTable(session, dbid, TableName, 16, 100, &lt;span style="color:Blue;"&gt;out&lt;/span&gt; tableid);
                    CreateColumnsAndIndexes(session, tableid);
                    Api.JetCloseTable(session, tableid);

                    &lt;span style="color:Green;"&gt;// Lazily commit the transaction. Normally committing a transaction forces the&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// associated log records to be flushed to disk, so the commit has to wait for&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// the I/O to complete. Using the LazyFlush option means that the log records&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// are kept in memory and will be flushed later. This will preserve transaction&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// atomicity (all operations in the transaction will either happen or be rolled&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// back) but will not preserve durability (a crash after the commit call may&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// result in the transaction updates being lost). Lazy transaction commits are&lt;/span&gt;
                    &lt;span style="color:Green;"&gt;// considerably faster though, as they don&amp;#39;t have to wait for an I/O.&lt;/span&gt;
                    transaction.Commit(CommitTransactionGrbit.LazyFlush);
                }
            }
        }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Setup the meta-data for the given table.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sesid&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The session to use.&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;tableid&amp;quot;&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The table to add the columns/indexes to. This table must be opened exclusively.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; CreateColumnsAndIndexes(JET_SESID sesid, JET_TABLEID tableid)
    {
        &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (&lt;span style="color:Blue;"&gt;var&lt;/span&gt; transaction = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Transaction(sesid))
        {
            JET_COLUMNID columnid;

            &lt;span style="color:Green;"&gt;// Stock symbol : text column&lt;/span&gt;
            &lt;span style="color:Blue;"&gt;var&lt;/span&gt; columndef = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; JET_COLUMNDEF
                                  {
                                      coltyp = JET_coltyp.LongText,
                                      cp = JET_CP.Unicode
                                  };

            Api.JetAddColumn(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;symbol&amp;quot;&lt;/span&gt;, columndef, &lt;span style="color:Blue;"&gt;null&lt;/span&gt;, 0, &lt;span style="color:Blue;"&gt;out&lt;/span&gt; columnid);

            &lt;span style="color:Green;"&gt;// Name of the company : text column&lt;/span&gt;
            Api.JetAddColumn(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;, columndef, &lt;span style="color:Blue;"&gt;null&lt;/span&gt;, 0, &lt;span style="color:Blue;"&gt;out&lt;/span&gt; columnid);

            &lt;span style="color:Green;"&gt;// Current price, stored in cents : 32-bit integer&lt;/span&gt;
            columndef = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; JET_COLUMNDEF
            {
                coltyp = JET_coltyp.Long,

                &lt;span style="color:Green;"&gt;// Be careful with ColumndefGrbit.ColumnNotNULL. Older versions of ESENT&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// (e.g. Windows XP) do not support this grbit for tagged or variable columns&lt;/span&gt;
                &lt;span style="color:Green;"&gt;// (JET_coltyp.Text, JET_coltyp.LongText, JET_coltyp.Binary, JET_coltyp.LongBinary)&lt;/span&gt;
                grbit = ColumndefGrbit.ColumnNotNULL
            };

            Api.JetAddColumn(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;price&amp;quot;&lt;/span&gt;, columndef, &lt;span style="color:Blue;"&gt;null&lt;/span&gt;, 0, &lt;span style="color:Blue;"&gt;out&lt;/span&gt; columnid);

            &lt;span style="color:Green;"&gt;// Number of shares owned (this column may be null) : 32-bit integer&lt;/span&gt;
            columndef.grbit = ColumndefGrbit.None;
            Api.JetAddColumn(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;shares_owned&amp;quot;&lt;/span&gt;, columndef, &lt;span style="color:Blue;"&gt;null&lt;/span&gt;, 0, &lt;span style="color:Blue;"&gt;out&lt;/span&gt; columnid);

            &lt;span style="color:Green;"&gt;// Now add indexes. An index consists of several index segments (see&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// EsentVersion.Capabilities.ColumnsKeyMost to determine the maximum number of&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// segments). Each segment consists of a sort direction (&amp;#39;+&amp;#39; for ascending,&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// &amp;#39;-&amp;#39; for descending), a column name, and a &amp;#39;\0&amp;#39; separator. The index definition&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// must end with &amp;quot;\0\0&amp;quot;. The count of characters should include all terminators.&lt;/span&gt;

            &lt;span style="color:Green;"&gt;// The primary index is the stock symbol. The primary index is always unique.&lt;/span&gt;
            &lt;span style="color:Blue;"&gt;string&lt;/span&gt; indexDef = &lt;span style="color:#A31515;"&gt;&amp;quot;+symbol\0\0&amp;quot;&lt;/span&gt;;
            Api.JetCreateIndex(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;primary&amp;quot;&lt;/span&gt;, CreateIndexGrbit.IndexPrimary, indexDef, indexDef.Length, 100);

            &lt;span style="color:Green;"&gt;// An index on the company name.&lt;/span&gt;
            indexDef = &lt;span style="color:#A31515;"&gt;&amp;quot;+name\0+symbol\0\0&amp;quot;&lt;/span&gt;;
            Api.JetCreateIndex(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;, CreateIndexGrbit.IndexUnique, indexDef, indexDef.Length, 100);

            &lt;span style="color:Green;"&gt;// An index on the price. This index is not unique.&lt;/span&gt;
            indexDef = &lt;span style="color:#A31515;"&gt;&amp;quot;+price\0\0&amp;quot;&lt;/span&gt;;
            Api.JetCreateIndex(sesid, tableid, &lt;span style="color:#A31515;"&gt;&amp;quot;price&amp;quot;&lt;/span&gt;, CreateIndexGrbit.None, indexDef, indexDef.Length, 100);

            &lt;span style="color:Green;"&gt;// Create 2 indexes that contain either companies where we own shares or companies&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// where we don&amp;#39;t own shares. To do this we make the indexes conditional on the&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// &amp;#39;shares_owned&amp;#39; column being null or non-null. When the &amp;#39;shares_owned&amp;#39; column&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// is null entries will only appear in the &amp;#39;noshares&amp;#39; index. When the &amp;#39;shares_owned&amp;#39;&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// column is non-null (i.e. it has a value) entries will only appear in the &amp;#39;shares&amp;#39;&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// index. Here we don&amp;#39;t index the &amp;#39;shares_owned&amp;#39; column (that would be valid too),&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// we just use it to determine membership in the index.&lt;/span&gt;
            &lt;span style="color:Blue;"&gt;const&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; IndexKey = &lt;span style="color:#A31515;"&gt;&amp;quot;+name\0\0&amp;quot;&lt;/span&gt;;
            JET_INDEXCREATE[] indexcreates = &lt;span style="color:Blue;"&gt;new&lt;/span&gt;[]
            {
                &lt;span style="color:Blue;"&gt;new&lt;/span&gt; JET_INDEXCREATE
                {
                    szIndexName = &lt;span style="color:#A31515;"&gt;&amp;quot;shares&amp;quot;&lt;/span&gt;,
                    szKey = IndexKey,
                    cbKey = IndexKey.Length,
                    rgconditionalcolumn = &lt;span style="color:Blue;"&gt;new&lt;/span&gt;[]
                    {
                        &lt;span style="color:Blue;"&gt;new&lt;/span&gt; JET_CONDITIONALCOLUMN
                        {
                            szColumnName = &lt;span style="color:#A31515;"&gt;&amp;quot;shares_owned&amp;quot;&lt;/span&gt;,
                            grbit = ConditionalColumnGrbit.ColumnMustBeNonNull
                        }
                    },
                    cConditionalColumn = 1
                },
            };

            &lt;span style="color:Green;"&gt;// This is important: only create one index at a time with JetCreateIndex2!&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// The API takes an array of JET_INDEXCREATE objects, but if more than one&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// index is passed in then the API operates in batch mode, which requires&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// the caller NOT be in a transaction.&lt;/span&gt;
            Api.JetCreateIndex2(sesid, tableid, indexcreates, indexcreates.Length);

            &lt;span style="color:Green;"&gt;// Now the first index has been created we change the name and invert the&lt;/span&gt;
            &lt;span style="color:Green;"&gt;// condition and create a second index.&lt;/span&gt;
            indexcreates[0].szIndexName = &lt;span style="color:#A31515;"&gt;&amp;quot;noshares&amp;quot;&lt;/span&gt;;
            indexcreates[0].rgconditionalcolumn[0].grbit = ConditionalColumnGrbit.ColumnMustBeNull;
            Api.JetCreateIndex2(sesid, tableid, indexcreates, indexcreates.Length);

            transaction.Commit(CommitTransactionGrbit.LazyFlush);
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Thu, 17 Feb 2011 20:08:05 GMT</pubDate><guid isPermaLink="false">Updated Wiki: StockSample 20110217080805P</guid></item><item><title>Updated Wiki: SystemStats</title><link>http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;version=10</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;SystemStats Sample&lt;/h1&gt;This shows how to use a PersistentDictionary to build a simple application to track and report on some performance counters. There are two main parts:
&lt;ol&gt;&lt;li&gt;A mode that periodically collects performance counter values and stores them.&lt;/li&gt;
&lt;li&gt;A mode that queries the stored data.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;The Sample structure&lt;/h2&gt;This program will use a PersistentDictionary to map a DateTime to a collection of samples. We will group the samples together into a serializable structure.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; One sample of the statistics we are collecting. This struct is stored in&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; the PersistentDictionary, keyed by time.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;internal&lt;/span&gt; &lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Sample
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; processorTime;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; paging;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; freeBytes;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; ProcessorTime
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; Paging
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; FreeBytes
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes = value; }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Collecting Performance Counters&lt;/h2&gt;
To collect performance counters we just add a new Sample to the dictionary. A PersistentDictionary is backed by an ESENT database which will always be consistent after a crash. That means we don&amp;#39;t need to worry about data consistency after a crash.&lt;br /&gt; &lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Collect stats. This method never returns (just kill the program).&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The path to the dictionary.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; CollectStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath)
{
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;% Processor Time&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;_Total&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Pages/Sec&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter freeMemory = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Available Bytes&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        &lt;span style="color:Blue;"&gt;while&lt;/span&gt; (&lt;span style="color:Blue;"&gt;true&lt;/span&gt;)
        {
            dictionary[DateTime.Now] = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Sample
                {
                    ProcessorTime = processor.NextValue(),
                    Paging = paging.NextValue(),
                    FreeBytes = freeMemory.NextValue(),
                };

            Thread.Sleep(TimeSpan.FromSeconds(0.5));
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Updates to a PersistentDictionary are logged lazily -- after a crash some updates may be lost. It is possible to force the updates to be written to disk by calling the Flush() method on the PersistentDictionary, but that has to perform an I/O so it is considerably slower than a lazy update. In this case we are willing to lose a few updates after a crash.&lt;br /&gt;
&lt;h2&gt;Calculating statistics&lt;/h2&gt;
While querying the data we will want to calculate the min, max and average of the samples. This class will be used to do the calculations:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Calculates the average, min and max of a set of samples.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; Aggregator
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Number of samples seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; numSamples = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Running total of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; total = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The smallest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; min = Double.MaxValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The largest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; max = Double.MinValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the number of samples that were seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; NumSamples
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the average of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; Average
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; 0 == &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples ? 0 : &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total / &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Add a new sample.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sample&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The sample value/&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; AddSample(&lt;span style="color:Blue;"&gt;double&lt;/span&gt; sample)
    {
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples++;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total += sample;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min = Math.Min(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, sample);
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max = Math.Max(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, sample);
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets a string representation of the aggregate calculation.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; A string representation of the aggregate calculation&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;override&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; ToString()
    {
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt; String.Format(&lt;span style="color:#A31515;"&gt;&amp;quot;min = {0:N2}, max = {1:N2}, average = {2:N2}&amp;quot;&lt;/span&gt;, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.Average);
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Querying the PersistentDictionary&lt;/h2&gt;
The PersistentDictionary supports LINQ queries. Given a query like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
DateTime startTime = ...;
DateTime endTime = ...;
IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Only records which match the key criteria will be retrieved from the database. That means the runtime is determined by the number of samples retrieved, not the total number of samples. For best performance we only want to iterate over the samples once so we accumulate all the statistics at the same time, using the Aggregator class:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Dump the aggregate stats for the specified time period.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The path to the dictionary.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;startTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The starting time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;endTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The ending time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; DumpStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath, DateTime startTime, DateTime endTime)
{
    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(dictionaryPath))
    {
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt;;
    }

    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        Stopwatch queryTimer = Stopwatch.StartNew();
        IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;

        Aggregator processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator freeBytes = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        &lt;span style="color:Blue;"&gt;foreach&lt;/span&gt; (Sample s &lt;span style="color:Blue;"&gt;in&lt;/span&gt; samples)
        {
            processor.AddSample(s.ProcessorTime);
            paging.AddSample(s.Paging);
            freeBytes.AddSample(s.FreeBytes);
        }

        queryTimer.Stop();
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;{0} samples from {1} to {2}&amp;quot;&lt;/span&gt;, processor.NumSamples, startTime, endTime);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor time: {0}&amp;quot;&lt;/span&gt;, processor);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Paging: {0}&amp;quot;&lt;/span&gt;, paging);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Free bytes: {0}&amp;quot;&lt;/span&gt;, freeBytes);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Query took {0}&amp;quot;&lt;/span&gt;, queryTimer.Elapsed);
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The PersistentDictionary is multi-thread safe so it is fine to run (multiple) queries while the dictionary is being updated. It is possible to have multiple threads updating the dictionary as well.&lt;br /&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;
Now we just need a main method.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The main method. Called on program startup.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;args&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;Arguments to the program.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; Main(&lt;span style="color:Blue;"&gt;string&lt;/span&gt;[] args)
{
    &lt;span style="color:Blue;"&gt;const&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; DictionaryPath = &lt;span style="color:#A31515;"&gt;&amp;quot;SystemStats&amp;quot;&lt;/span&gt;;

    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (0 == args.Length)
    {
        CollectStats(DictionaryPath);
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt; &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (2 == args.Length)
    {
        DumpStats(DictionaryPath, DateTime.Parse(args[0]), DateTime.Parse(args[1]));
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
    {
        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(DictionaryPath))
        {
            Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        }
        &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
        {
            &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(DictionaryPath))
            {
                &lt;span style="color:Green;"&gt;// Getting the first item, last item or count of items are all O(1) operations.&lt;/span&gt;
                Console.WriteLine(
                    &lt;span style="color:#A31515;"&gt;&amp;quot;Stats available from {0} to {1} ({2}) records&amp;quot;&lt;/span&gt;,
                    dictionary.Keys.FirstOrDefault(),
                    dictionary.Keys.LastOrDefault(),
                    dictionary.Count);
            }                    
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Performance&lt;/h2&gt;
These numbers are from a database where samples were taken 100 times/second, there are slightly over 500,000 entries and the database is around 1.5Gb.&lt;br /&gt;&lt;br /&gt;&lt;span class="codeInline"&gt;Stats available from 2/15/2011 12:59:48 PM to 2/16/2011 11:30:15 AM (7560591) records&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here are the results of a few queries. Each run is a new process so none of the database is cached. In a real-world scenario a process might keep the dictionary open so subsequent queries would be even faster:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;.\SystemStats.exe &amp;quot;2/15/2011 4:34:30 PM&amp;quot; &amp;quot;2/15/2011 4:34:33 PM&amp;quot;
235 samples from 2/15/2011 4:34:30 PM to 2/15/2011 4:34:33 PM
Processor time: min = 0.00, max = 100.00, average = 52.47
Paging: min = 0.00, max = 872.37, average = 4.11
Free bytes: min = 3,659,247,616.00, max = 3,678,650,368.00, average = 3,667,921,270.74
Query took 00:00:00.1053856

&amp;gt;.\SystemStats.exe &amp;quot;2/15/2011 2:13:00 PM&amp;quot; &amp;quot;2/15/2011 2:15:00 PM&amp;quot;
11805 samples from 2/15/2011 2:13:00 PM to 2/15/2011 2:15:00 PM
Processor time: min = 0.00, max = 100.00, average = 38.04
Paging: min = 0.00, max = 4,100.28, average = 3.39
Free bytes: min = 4,026,720,256.00, max = 4,069,093,376.00, average = 4,063,535,199.76
Query took 00:00:00.8090867

&amp;gt;.\SystemStats.exe &amp;quot;2/15/2011 5:23:00 PM&amp;quot; &amp;quot;2/15/2011 6:25:00 PM&amp;quot;
346751 samples from 2/15/2011 5:23:00 PM to 2/15/2011 6:25:00 PM
Processor time: min = 0.00, max = 100.00, average = 37.36
Paging: min = 0.00, max = 36,016.09, average = 11.27
Free bytes: min = 3,183,525,888.00, max = 3,589,419,008.00, average = 3,413,498,109.31
Query took 00:00:21.6863322&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The query performance is proportional to the number of entries processed, it will be basically independent of the database size.&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Wed, 16 Feb 2011 19:34:45 GMT</pubDate><guid isPermaLink="false">Updated Wiki: SystemStats 20110216073445P</guid></item><item><title>Updated Wiki: SystemStats</title><link>http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;version=9</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;SystemStats Sample&lt;/h1&gt;This shows how to use a PersistentDictionary to build a simple application to track and report on some performance counters. There are two main parts:
&lt;ol&gt;&lt;li&gt;A mode that periodically collects performance counter values and stores them.&lt;/li&gt;
&lt;li&gt;A mode that queries the stored data.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;The Sample structure&lt;/h2&gt;This program will use a PersistentDictionary to map a DateTime to a collection of samples. We will group the samples together into a serializable structure.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; One sample of the statistics we are collecting. This struct is stored in&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; the PersistentDictionary, keyed by time.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;internal&lt;/span&gt; &lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Sample
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; processorTime;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; paging;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; freeBytes;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; ProcessorTime
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; Paging
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; FreeBytes
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes = value; }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Collecting Performance Counters&lt;/h2&gt;
To collect performance counters we just add a new Sample to the dictionary. A PersistentDictionary is backed by an ESENT database which will always be consistent after a crash. That means we don&amp;#39;t need to worry about data consistency after a crash.&lt;br /&gt; &lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Collect stats. This method never returns (just kill the program).&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The path to the dictionary.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; CollectStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath)
{
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;% Processor Time&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;_Total&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Pages/Sec&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter freeMemory = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Available Bytes&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        &lt;span style="color:Blue;"&gt;while&lt;/span&gt; (&lt;span style="color:Blue;"&gt;true&lt;/span&gt;)
        {
            dictionary[DateTime.Now] = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Sample
                {
                    ProcessorTime = processor.NextValue(),
                    Paging = paging.NextValue(),
                    FreeBytes = freeMemory.NextValue(),
                };

            Thread.Sleep(TimeSpan.FromSeconds(0.5));
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Updates to a PersistentDictionary are logged lazily -- after a crash some updates may be lost. It is possible to force the updates to be written to disk by calling the Flush() method on the PersistentDictionary, but that has to perform an I/O so it is considerably slower than a lazy update. In this case we are willing to lose a few updates after a crash.&lt;br /&gt;
&lt;h2&gt;Calculating statistics&lt;/h2&gt;
While querying the data we will want to calculate the min, max and average of the samples. This class will be used to do the calculations:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Calculates the average, min and max of a set of samples.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; Aggregator
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Number of samples seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; numSamples = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Running total of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; total = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The smallest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; min = Double.MaxValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The largest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; max = Double.MinValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the number of samples that were seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; NumSamples
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the average of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; Average
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; 0 == &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples ? 0 : &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total / &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Add a new sample.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sample&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The sample value/&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; AddSample(&lt;span style="color:Blue;"&gt;double&lt;/span&gt; sample)
    {
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples++;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total += sample;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min = Math.Min(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, sample);
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max = Math.Max(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, sample);
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets a string representation of the aggregate calculation.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; A string representation of the aggregate calculation&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;override&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; ToString()
    {
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt; String.Format(&lt;span style="color:#A31515;"&gt;&amp;quot;min = {0:N2}, max = {1:N2}, average = {2:N2}&amp;quot;&lt;/span&gt;, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.Average);
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Querying the PersistentDictionary&lt;/h2&gt;
The PersistentDictionary supports LINQ queries. Given a query like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
DateTime startTime = ...;
DateTime endTime = ...;
IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Only records which match the key criteria will be retrieved from the database. That means the runtime is determined by the number of samples retrieved, not the total number of samples. For best performance we only want to iterate over the samples once so we accumulate all the statistics at the same time, using the Aggregator class:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Dump the aggregate stats for the specified time period.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The path to the dictionary.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;startTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The starting time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;endTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The ending time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; DumpStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath, DateTime startTime, DateTime endTime)
{
    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(dictionaryPath))
    {
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt;;
    }

    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        Stopwatch queryTimer = Stopwatch.StartNew();
        IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;

        Aggregator processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator freeBytes = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        &lt;span style="color:Blue;"&gt;foreach&lt;/span&gt; (Sample s &lt;span style="color:Blue;"&gt;in&lt;/span&gt; samples)
        {
            processor.AddSample(s.ProcessorTime);
            paging.AddSample(s.Paging);
            freeBytes.AddSample(s.FreeBytes);
        }

        queryTimer.Stop();
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;{0} samples from {1} to {2}&amp;quot;&lt;/span&gt;, processor.NumSamples, startTime, endTime);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor time: {0}&amp;quot;&lt;/span&gt;, processor);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Paging: {0}&amp;quot;&lt;/span&gt;, paging);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Free bytes: {0}&amp;quot;&lt;/span&gt;, freeBytes);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Query took {0}&amp;quot;&lt;/span&gt;, queryTimer.Elapsed);
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The PersistentDictionary is multi-thread safe so it is fine to run (multiple) queries while the dictionary is being updated. It is possible to have multiple threads updating the dictionary as well.&lt;br /&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;
Now we just need a main method.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The main method. Called on program startup.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;args&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;Arguments to the program.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; Main(&lt;span style="color:Blue;"&gt;string&lt;/span&gt;[] args)
{
    &lt;span style="color:Blue;"&gt;const&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; DictionaryPath = &lt;span style="color:#A31515;"&gt;&amp;quot;SystemStats&amp;quot;&lt;/span&gt;;

    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (0 == args.Length)
    {
        CollectStats(DictionaryPath);
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt; &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (2 == args.Length)
    {
        DumpStats(DictionaryPath, DateTime.Parse(args[0]), DateTime.Parse(args[1]));
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
    {
        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(DictionaryPath))
        {
            Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        }
        &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
        {
            &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(DictionaryPath))
            {
                &lt;span style="color:Green;"&gt;// Getting the first item, last item or count of items are all O(1) operations.&lt;/span&gt;
                Console.WriteLine(
                    &lt;span style="color:#A31515;"&gt;&amp;quot;Stats available from {0} to {1} ({2}) records&amp;quot;&lt;/span&gt;,
                    dictionary.Keys.FirstOrDefault(),
                    dictionary.Keys.LastOrDefault(),
                    dictionary.Count);
            }                    
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Performance&lt;/h2&gt;
These numbers are from a database where samples were taken 100 times/second, there are slightly over 500,000 entries and the database is around 110MB.&lt;br /&gt;&lt;br /&gt;&lt;span class="codeInline"&gt;Stats available from 2/15/2011 12:59:48 PM to 2/15/2011 2:33:19 PM (492174) records&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here are the results of a few queries. Each run is a new process so none of the database is cached. In a real-world scenario a process might keep the dictionary open so subsequent queries would be even faster:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;.\SystemStats.exe &amp;quot;2/15/2011 2:43:00 PM&amp;quot; &amp;quot;2/15/2011 2:43:01 PM&amp;quot;
82 samples from 2/15/2011 2:43:00 PM to 2/15/2011 2:43:01 PM
Processor time: min = 0.00, max = 100.00, average = 42.89
Paging: min = 0.00, max = 464.90, average = 6.28
Free bytes: min = 3,873,783,808.00, max = 3,911,086,080.00, average = 3,901,525,966.05
Query took 00:00:00.1149587

&amp;gt;.\SystemStats.exe &amp;quot;2/15/2011 2:33:00 PM&amp;quot; &amp;quot;2/15/2011 2:34:00 PM&amp;quot;
1795 samples from 2/15/2011 2:33:00 PM to 2/15/2011 2:34:00 PM
Processor time: min = 0.00, max = 100.00, average = 41.26
Paging: min = 0.00, max = 3,075.65, average = 7.93
Free bytes: min = 3,995,095,040.00, max = 4,011,421,696.00, average = 4,005,309,211.24
Query took 00:00:00.2190249

&amp;gt;.\SystemStats.exe &amp;quot;2/15/2011 2:34:30 PM&amp;quot; &amp;quot;2/15/2011 2:49:30 PM&amp;quot;
64002 samples from 2/15/2011 2:34:30 PM to 2/15/2011 2:49:30 PM
Processor time: min = 0.00, max = 100.00, average = 40.30
Paging: min = 0.00, max = 11,241.36, average = 4.79
Free bytes: min = 3,860,332,544.00, max = 4,047,314,944.00, average = 3,927,072,817.73
Query took 00:00:03.9911891

&amp;gt;.\SystemStats.exe &amp;quot;2/15/2011 1:27:48 PM&amp;quot; &amp;quot;2/15/2011 2:27:48 PM&amp;quot;
337585 samples from 2/15/2011 1:27:48 PM to 2/15/2011 2:27:48 PM
Processor time: min = 0.00, max = 100.00, average = 37.83
Paging: min = 0.00, max = 54,169.92, average = 68.10
Free bytes: min = 3,986,374,656.00, max = 4,128,804,864.00, average = 4,068,317,649.07
Query took 00:00:20.6299002&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The query performance is proportional to the number of entries processed, it will be basically independent of the database size.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>martinc</author><pubDate>Wed, 16 Feb 2011 01:04:04 GMT</pubDate><guid isPermaLink="false">Updated Wiki: SystemStats 20110216010404A</guid></item><item><title>Updated Wiki: PersistentDictionaryDocumentation</title><link>http://managedesent.codeplex.com/wikipage?title=PersistentDictionaryDocumentation&amp;version=7</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;Data Storage with PersistentDictionary&lt;/h1&gt;PersistentDictionary is a database-backed dictionary built on top of the ESENT database engine. It is a drop-in compatible replacement for the generic &lt;i&gt;Dictionary&lt;/i&gt;&amp;lt;TKey,TValue&amp;gt;, &lt;i&gt;SortedDictionary&lt;/i&gt;&amp;lt;TKey, TValue&amp;gt; and &lt;i&gt;SortedList&lt;/i&gt;&amp;lt;TKey, TValue&amp;gt; classes found in the System.Collections.Generic namespace.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Blue;"&gt;class&lt;/span&gt; PersistentDictionary&amp;lt;TKey, TValue&amp;gt; : IDictionary&amp;lt;TKey, TValue&amp;gt;, ICollection&amp;lt;KeyValuePair&amp;lt;TKey, TValue&amp;gt;&amp;gt;, IEnumerable&amp;lt;KeyValuePair&amp;lt;TKey, TValue&amp;gt;&amp;gt;, IDisposable
    &lt;span style="color:Blue;"&gt;where&lt;/span&gt; TKey : IComparable&amp;lt;TKey&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;PersistentDictionary Features&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;u&gt;No setup&lt;/u&gt;: the ESENT database engine is part of Windows and requires no setup. EsentCollections will work on any version of Windows from XP onwards.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Performance&lt;/u&gt;: ESENT supports a high rate of updates and retrieves. Write-ahead logging decreases the cost of making small updates to the data. Information is inserted into or retrieved from the database in-process so data access has very low overhead. B-trees give O(log n) access to data by key and the records are stored in sorted order.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Simplicity&lt;/u&gt;: a PersistentDictionary looks and behaves like the .NET Dictionary/SortedDictionary/SortedList classes. No extra method calls are required.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Administration-free&lt;/u&gt;: ESENT automatically manages the database cache size, transaction logfiles, and crash recovery so no database administration is needed. The code is structured so that there are no deadlocks or conflicts, even when multiple threads use the same dictionary. ESENT runs in-process and doesn’t expose any network access, providing a high degree of security.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Reliability&lt;/u&gt;: ESENT’s write-ahead logging system means that a database is automatically recovered after a process crash or unexpected machine shutdown (e.g. power outage). Database transactions are used to ensure the logical consistency of the database.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Concurrency&lt;/u&gt;: each data structure can be accessed by multiple threads. Reads are non-blocking and updates to different items in the collection are allowed to proceed concurrently.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Scale&lt;/u&gt;: A collection can contain up to 2^31 objects, and values can be up to 2GB in size. The maximum database size is 16TB . &lt;/li&gt;&lt;/ul&gt;

&lt;h2&gt;Sample Code&lt;/h2&gt;Here is an application that remembers a first name → last name mapping in a persistent dictionary.&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Blue;"&gt;using&lt;/span&gt; System;
&lt;span style="color:Blue;"&gt;using&lt;/span&gt; Microsoft.Isam.Esent.Collections.Generic;

&lt;span style="color:Blue;"&gt;namespace&lt;/span&gt; PersistentDictionarySample
{
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; HelloWorld
    {
        &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; Main()
        {
            &lt;span style="color:Blue;"&gt;var&lt;/span&gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;&lt;span style="color:Blue;"&gt;string&lt;/span&gt;, &lt;span style="color:Blue;"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color:#A31515;"&gt;&amp;quot;Names&amp;quot;&lt;/span&gt;);
            Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;What is your first name?&amp;quot;&lt;/span&gt;);
            &lt;span style="color:Blue;"&gt;string&lt;/span&gt; firstName = Console.ReadLine();
            &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (dictionary.ContainsKey(firstName))
            {
                Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Welcome back {0} {1}&amp;quot;&lt;/span&gt;,
                    firstName,
                    dictionary[firstName]);
            }
            &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
            {
                Console.WriteLine(
                    &lt;span style="color:#A31515;"&gt;&amp;quot;I don&amp;#39;t know you, {0}. What is your last name?&amp;quot;&lt;/span&gt;,
                    firstName);
                dictionary[firstName] = Console.ReadLine();
            }
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Sample Code in other languages&lt;/h3&gt;&lt;a href="http://managedesent.codeplex.com/wikipage?title=VbNetDictionarySample&amp;referringTitle=PersistentDictionaryDocumentation"&gt;VB.NET Sample&lt;/a&gt;&lt;br /&gt;&lt;a href="http://managedesent.codeplex.com/wikipage?title=CppDictionarySample&amp;referringTitle=PersistentDictionaryDocumentation"&gt;C&amp;#43;&amp;#43;&amp;#47;CLI Sample&lt;/a&gt;&lt;br /&gt;
&lt;h2&gt;Sample Application&lt;/h2&gt;A more sophisticated &lt;a href="http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;referringTitle=PersistentDictionaryDocumentation"&gt;sample application&lt;/a&gt; that tracks some perf counters and performs a simple LINQ query.&lt;br /&gt;
&lt;h2&gt;Quick Start&lt;/h2&gt;To get started with PersistentDictionary you should:
&lt;ol&gt;&lt;li&gt;Download the latest version of the PersistentDictionary project. &lt;a href="http://managedesent.codeplex.com/releases" class="externalLink"&gt;http://managedesent.codeplex.com/releases&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Copy Esent.Interop.dll and Esent.Collections.dll to your project.&lt;/li&gt;
&lt;li&gt;Add a reference to Esent.Collections.dll.&lt;/li&gt;
&lt;li&gt;Use the namespace ‘Microsoft.Isam.Esent.Collections.Generic’.&lt;/li&gt;
&lt;li&gt;Pick a directory to contain the persistent dictionary. The directory will contain all the files (database, logfiles, and checkpoint) needed for the database that stores the data.&lt;/li&gt;
&lt;li&gt;Create a PersistentDictionary, passing the directory name into the constructor.&lt;/li&gt;
&lt;li&gt;Use the PersistentDictionary like an ordinary Dictionary or SortedDictionary.&lt;/li&gt;
&lt;li&gt;Dispose of the PersistentDictionary when finished with it. If the dictionary isn’t disposed then ESENT will have the database open until the instance is finalized.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;Supported Key Types&lt;/h2&gt;Only these types are supported as dictionary keys:&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt; Boolean	&lt;/td&gt;&lt;td&gt; Byte &lt;/td&gt;&lt;td&gt; Int16 &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; UInt16 &lt;/td&gt;&lt;td&gt; Int32 &lt;/td&gt;&lt;td&gt; UInt32 &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Int64 &lt;/td&gt;&lt;td&gt; UInt64 &lt;/td&gt;&lt;td&gt; Float &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Double &lt;/td&gt;&lt;td&gt; Guid &lt;/td&gt;&lt;td&gt; DateTime &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; TimeSpan &lt;/td&gt;&lt;td&gt; String &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;
&lt;h2&gt;Supported Value Types&lt;/h2&gt;Dictionary values can be any of the key types, Nullable&amp;lt;T&amp;gt; versions of the key types, Uri, IPAddress or a serializable structure. A structure is only considered serializable if it meets all these criteria:
&lt;ul&gt;&lt;li&gt;The structure is marked as serializable&lt;/li&gt;
&lt;li&gt;Every member of the struct is either:
&lt;ul&gt;&lt;li&gt;A primitive data type (e.g. Int32)&lt;/li&gt;
&lt;li&gt;A String, Uri or IPAddress&lt;/li&gt;
&lt;li&gt;A serializable structure.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;
Or, to put it another way, a serializable structure cannot contain any references to a class object. This is done to preserve API consistency. Adding an object to a PersistentDictionary creates a copy of the object though serialization. Modifying the original object will not modify the copy, which would lead to confusing behavior. To avoid those problems the PersistentDictionary will only accept value types as values.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Can Be Serialized&lt;/b&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Good
{
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; DateTime? Received;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; Name;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; Decimal Price;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; Uri Url;
}	
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Can’t Be Serialized&lt;/b&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Bad
{
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;byte&lt;/span&gt;[] Data; &lt;span style="color:Green;"&gt;// arrays aren’t supported&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; Exception Error; &lt;span style="color:Green;"&gt;// reference object &lt;/span&gt;
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;PersistentDictionary API&lt;/h2&gt;PersistentDictionary implements the generic IDictionary interface. See the MSDN entry for &lt;a href="http://msdn.microsoft.com/en-us/library/s4ys34ea.aspx" class="externalLink"&gt;System.Collections.Generic.IDictionary&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt; for documentation. Additional methods are:&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Constructors&lt;/u&gt;&lt;br /&gt;&lt;i&gt;The constructor has to specify the location of the database files.&lt;/i&gt;&lt;br /&gt;&lt;b&gt;PersistentDictionary(string directory)&lt;/b&gt; : Create a PersistentDictionary in the specified directory.&lt;br /&gt;&lt;b&gt;PersistentDictionary(IEnumerable&amp;lt;KeyValuePair&amp;lt;TKey, TValue&amp;gt;&amp;gt; dictionary, string directory)&lt;/b&gt; : Create a PersistentDictionary in the specified directory, copying entries from the specified collection.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Methods&lt;/u&gt;&lt;br /&gt;&lt;b&gt;PersistentDictionary.Flush()&lt;/b&gt; :  Force all changes made to this dictionary to be written to disk.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;File Manipulation&lt;/u&gt;&lt;br /&gt;&lt;i&gt;These are static methods of the PersistentDictionaryFile class.&lt;/i&gt;&lt;br /&gt;&lt;b&gt;PersistentDictionaryFile.Exists(string directory)&lt;/b&gt; : Determine if a dictionary database file exists in the specified directory.&lt;br /&gt;&lt;b&gt;PersistentDictionaryFile.DeleteFiles(string directory)&lt;/b&gt; : Delete all files associated with a PersistedDictionary database from the specified directory.&lt;br /&gt;
&lt;h2&gt;LINQ Support&lt;/h2&gt;A PersistentDictionary can optimize some LINQ operators by retrieving only matching records from the database. For this to happen the LINQ query should specify a subset of item keys using comparison operators. Supported operators are: &amp;lt;, &amp;lt;=, ==, !=, &amp;gt;, &amp;gt;=, Equals, CompareTo and StartsWith (for strings). LINQ queries that only examine values cannot be optimized at all.&lt;br /&gt;&lt;br /&gt;Besides &amp;#39;where&amp;#39;, these LINQ operators can be optimized: Any, Min, Max, First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault, Count, Reverse.&lt;br /&gt;&lt;br /&gt;Examples of LINQ statements which have efficient support:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Blue;"&gt;var&lt;/span&gt; q = persistentDictionary.Where(x =&amp;gt; x.Key &amp;lt; 5 &amp;amp;&amp;amp; x.Key &amp;gt; 2 &amp;amp;&amp;amp; x.Key != 4).Reverse();
&lt;span style="color:Blue;"&gt;var&lt;/span&gt; q = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; persistentDictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key.StartsWith(&lt;span style="color:#A31515;"&gt;&amp;quot;de&amp;quot;&lt;/span&gt;) || x.Key.StartsWith(&lt;span style="color:#A31515;"&gt;&amp;quot;bi&amp;quot;&lt;/span&gt;) &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;
&lt;span style="color:Blue;"&gt;if&lt;/span&gt; (persistentDictionary.Keys.Any(x =&amp;gt; x &amp;lt; 5)) { ... }
&lt;span style="color:Blue;"&gt;var&lt;/span&gt; q = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; persistentDictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; (x.Key.CompareTo(&lt;span style="color:#A31515;"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;) &amp;gt; 0 &amp;amp;&amp;amp; x.Key.CompareTo(&lt;span style="color:#A31515;"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;) &amp;lt;= 0) &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Data Consistency&lt;/h2&gt;Each database update is performed in a separate transaction and the logfile and database updates are performed in the background. This means that dictionary updates are atomic and consistent, but not always durable. If the application crashes only updates whose log records have been written to disk will be recovered. It is possible to force the dictionary updates created so far to be persisted to disk using &lt;b&gt;PersistentDictionary.Flush()&lt;/b&gt;. Note that every Flush() call requires a disk I/O so using this too frequently will severely limit the update rate. Disposing the dictionary also flushes all its changes to disk.&lt;br /&gt;
&lt;h2&gt;Performance Measurements&lt;/h2&gt;These are very basic performance measurements made with a PersistentDictionary&amp;lt;long, string&amp;gt; where the string data was 64 bytes in length. These measurements were taken on my desktop system.&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt; Sequential inserts &lt;/td&gt;&lt;td&gt; 32,000 entries/second &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Random inserts &lt;/td&gt;&lt;td&gt; 17,000 entries/second &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Random Updates &lt;/td&gt;&lt;td&gt; 36,000 entries/second &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Random lookups (database cached in memory) &lt;/td&gt;&lt;td&gt; 137,000 entries/second &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Linq queries (range of records) &lt;/td&gt;&lt;td&gt; 14,000 queries/second &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Performance will vary from application to application. Factors that affect performance include:
&lt;ul&gt;&lt;li&gt;Total number of items in the dictionary.&lt;/li&gt;
&lt;li&gt;Size of the data. Retrieving an int will be faster than retrieving a 55MB string.&lt;/li&gt;
&lt;li&gt;How much of the database is cached in memory. When first opening a populated dictionary the data will not be cached in memory so initial lookups will be slow.&lt;/li&gt;
&lt;li&gt;Update patterns. Sequential inserts are much faster than random inserts.&lt;/li&gt;
&lt;li&gt;Structure serialization. Using structures as dictionary data can be much slower than using basic data types.&lt;/li&gt;
&lt;li&gt;Disk performance.&lt;/li&gt;&lt;/ul&gt;

&lt;h2&gt;File Management&lt;/h2&gt;The PersistentDictionary code will automatically open or create a database in the specified directory. To determine if a dictionary database already exists use &lt;b&gt;PersistentDictionaryFile.Exists()&lt;/b&gt;. To remove a dictionary use &lt;b&gt;PersistentDictionaryFile.DeleteFiles()&lt;/b&gt;. &lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Tue, 15 Feb 2011 23:29:10 GMT</pubDate><guid isPermaLink="false">Updated Wiki: PersistentDictionaryDocumentation 20110215112910P</guid></item><item><title>Updated Wiki: PersistentDictionaryDocumentation</title><link>http://managedesent.codeplex.com/wikipage?title=PersistentDictionaryDocumentation&amp;version=6</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;Data Storage with PersistentDictionary&lt;/h1&gt;PersistentDictionary is a database-backed dictionary built on top of the ESENT database engine. It is a drop-in compatible replacement for the generic &lt;i&gt;Dictionary&lt;/i&gt;&amp;lt;TKey,TValue&amp;gt;, &lt;i&gt;SortedDictionary&lt;/i&gt;&amp;lt;TKey, TValue&amp;gt; and &lt;i&gt;SortedList&lt;/i&gt;&amp;lt;TKey, TValue&amp;gt; classes found in the System.Collections.Generic namespace.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Blue;"&gt;class&lt;/span&gt; PersistentDictionary&amp;lt;TKey, TValue&amp;gt; : IDictionary&amp;lt;TKey, TValue&amp;gt;, ICollection&amp;lt;KeyValuePair&amp;lt;TKey, TValue&amp;gt;&amp;gt;, IEnumerable&amp;lt;KeyValuePair&amp;lt;TKey, TValue&amp;gt;&amp;gt;, IDisposable
    &lt;span style="color:Blue;"&gt;where&lt;/span&gt; TKey : IComparable&amp;lt;TKey&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;PersistentDictionary Features&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;u&gt;No setup&lt;/u&gt;: the ESENT database engine is part of Windows and requires no setup. EsentCollections will work on any version of Windows from XP onwards.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Performance&lt;/u&gt;: ESENT supports a high rate of updates and retrieves. Write-ahead logging decreases the cost of making small updates to the data. Information is inserted into or retrieved from the database in-process so data access has very low overhead. B-trees give O(log n) access to data by key and the records are stored in sorted order.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Simplicity&lt;/u&gt;: a PersistentDictionary looks and behaves like the .NET Dictionary/SortedDictionary/SortedList classes. No extra method calls are required.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Administration-free&lt;/u&gt;: ESENT automatically manages the database cache size, transaction logfiles, and crash recovery so no database administration is needed. The code is structured so that there are no deadlocks or conflicts, even when multiple threads use the same dictionary. ESENT runs in-process and doesn’t expose any network access, providing a high degree of security.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Reliability&lt;/u&gt;: ESENT’s write-ahead logging system means that a database is automatically recovered after a process crash or unexpected machine shutdown (e.g. power outage). Database transactions are used to ensure the logical consistency of the database.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Concurrency&lt;/u&gt;: each data structure can be accessed by multiple threads. Reads are non-blocking and updates to different items in the collection are allowed to proceed concurrently.&lt;/li&gt;
&lt;li&gt;&lt;u&gt;Scale&lt;/u&gt;: A collection can contain up to 2^31 objects, and values can be up to 2GB in size. The maximum database size is 16TB . &lt;/li&gt;&lt;/ul&gt;

&lt;h2&gt;Sample Code&lt;/h2&gt;Here is an application that remembers a first name → last name mapping in a persistent dictionary.&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Blue;"&gt;using&lt;/span&gt; System;
&lt;span style="color:Blue;"&gt;using&lt;/span&gt; Microsoft.Isam.Esent.Collections.Generic;

&lt;span style="color:Blue;"&gt;namespace&lt;/span&gt; PersistentDictionarySample
{
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; HelloWorld
    {
        &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; Main()
        {
            &lt;span style="color:Blue;"&gt;var&lt;/span&gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;&lt;span style="color:Blue;"&gt;string&lt;/span&gt;, &lt;span style="color:Blue;"&gt;string&lt;/span&gt;&amp;gt;(&lt;span style="color:#A31515;"&gt;&amp;quot;Names&amp;quot;&lt;/span&gt;);
            Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;What is your first name?&amp;quot;&lt;/span&gt;);
            &lt;span style="color:Blue;"&gt;string&lt;/span&gt; firstName = Console.ReadLine();
            &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (dictionary.ContainsKey(firstName))
            {
                Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Welcome back {0} {1}&amp;quot;&lt;/span&gt;,
                    firstName,
                    dictionary[firstName]);
            }
            &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
            {
                Console.WriteLine(
                    &lt;span style="color:#A31515;"&gt;&amp;quot;I don&amp;#39;t know you, {0}. What is your last name?&amp;quot;&lt;/span&gt;,
                    firstName);
                dictionary[firstName] = Console.ReadLine();
            }
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Sample Code in other languages&lt;/h3&gt;&lt;a href="http://managedesent.codeplex.com/wikipage?title=VbNetDictionarySample&amp;referringTitle=PersistentDictionaryDocumentation"&gt;VB.NET Sample&lt;/a&gt;&lt;br /&gt;&lt;a href="http://managedesent.codeplex.com/wikipage?title=CppDictionarySample&amp;referringTitle=PersistentDictionaryDocumentation"&gt;C&amp;#43;&amp;#43;&amp;#47;CLI Sample&lt;/a&gt;&lt;br /&gt;
&lt;h2&gt;Sample Application&lt;/h2&gt;A more sophisticated &lt;a href="http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;referringTitle=PersistentDictionaryDocumentation"&gt;sample application&lt;/a&gt; that tracks some perf counters and performs a simple LINQ query.&lt;br /&gt;
&lt;h2&gt;Quick Start&lt;/h2&gt;To get started with PersistentDictionary you should:
&lt;ol&gt;&lt;li&gt;Download the latest version of the PersistentDictionary project. &lt;a href="http://managedesent.codeplex.com/releases" class="externalLink"&gt;http://managedesent.codeplex.com/releases&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Copy Esent.Interop.dll and Esent.Collections.dll to your project.&lt;/li&gt;
&lt;li&gt;Add a reference to Esent.Collections.dll.&lt;/li&gt;
&lt;li&gt;Use the namespace ‘Microsoft.Isam.Esent.Collections.Generic’.&lt;/li&gt;
&lt;li&gt;Pick a directory to contain the persistent dictionary. The directory will contain all the files (database, logfiles, and checkpoint) needed for the database that stores the data.&lt;/li&gt;
&lt;li&gt;Create a PersistentDictionary, passing the directory name into the constructor.&lt;/li&gt;
&lt;li&gt;Use the PersistentDictionary like an ordinary Dictionary or SortedDictionary.&lt;/li&gt;
&lt;li&gt;Dispose of the PersistentDictionary when finished with it. If the dictionary isn’t disposed then ESENT will have the database open until the instance is finalized.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;Supported Key Types&lt;/h2&gt;Only these types are supported as dictionary keys:&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt; Boolean	&lt;/td&gt;&lt;td&gt; Byte &lt;/td&gt;&lt;td&gt; Int16 &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; UInt16 &lt;/td&gt;&lt;td&gt; Int32 &lt;/td&gt;&lt;td&gt; UInt32 &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Int64 &lt;/td&gt;&lt;td&gt; UInt64 &lt;/td&gt;&lt;td&gt; Float &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Double &lt;/td&gt;&lt;td&gt; Guid &lt;/td&gt;&lt;td&gt; DateTime &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; TimeSpan &lt;/td&gt;&lt;td&gt; String &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;
&lt;h2&gt;Supported Value Types&lt;/h2&gt;Dictionary values can be any of the key types, Nullable&amp;lt;T&amp;gt; versions of the key types, Uri, IPAddress or a serializable structure. A structure is only considered serializable if it meets all these criteria:
&lt;ul&gt;&lt;li&gt;The structure is marked as serializable&lt;/li&gt;
&lt;li&gt;Every member of the struct is either:
&lt;ul&gt;&lt;li&gt;A primitive data type (e.g. Int32)&lt;/li&gt;
&lt;li&gt;A String, Uri or IPAddress&lt;/li&gt;
&lt;li&gt;A serializable structure.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;
Or, to put it another way, a serializable structure cannot contain any references to a class object. This is done to preserve API consistency. Adding an object to a PersistentDictionary creates a copy of the object though serialization. Modifying the original object will not modify the copy, which would lead to confusing behavior. To avoid those problems the PersistentDictionary will only accept value types as values.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Can Be Serialized&lt;/b&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Good
{
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; DateTime? Received;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; Name;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; Decimal Price;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; Uri Url;
}	
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Can’t Be Serialized&lt;/b&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Bad
{
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;byte&lt;/span&gt;[] Data; &lt;span style="color:Green;"&gt;// arrays aren’t supported&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; Exception Error; &lt;span style="color:Green;"&gt;// reference object &lt;/span&gt;
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;PersistentDictionary API&lt;/h2&gt;PersistentDictionary implements the generic IDictionary interface. See the MSDN entry for &lt;a href="http://msdn.microsoft.com/en-us/library/s4ys34ea.aspx" class="externalLink"&gt;System.Collections.Generic.IDictionary&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt; for documentation. Additional methods are:&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Constructors&lt;/u&gt;&lt;br /&gt;&lt;i&gt;The constructor has to specify the location of the database files.&lt;/i&gt;&lt;br /&gt;&lt;b&gt;PersistentDictionary(string directory)&lt;/b&gt; : Create a PersistentDictionary in the specified directory.&lt;br /&gt;&lt;b&gt;PersistentDictionary(IEnumerable&amp;lt;KeyValuePair&amp;lt;TKey, TValue&amp;gt;&amp;gt; dictionary, string directory)&lt;/b&gt; : Create a PersistentDictionary in the specified directory, copying entries from the specified collection.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Methods&lt;/u&gt;&lt;br /&gt;&lt;b&gt;PersistentDictionary.Flush()&lt;/b&gt; :  Force all changes made to this dictionary to be written to disk.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;File Manipulation&lt;/u&gt;&lt;br /&gt;&lt;i&gt;These are static methods of the PersistentDictionaryFile class.&lt;/i&gt;&lt;br /&gt;&lt;b&gt;PersistentDictionaryFile.Exists(string directory)&lt;/b&gt; : Determine if a dictionary database file exists in the specified directory.&lt;br /&gt;&lt;b&gt;PersistentDictionaryFile.DeleteFiles(string directory)&lt;/b&gt; : Delete all files associated with a PersistedDictionary database from the specified directory.&lt;br /&gt;
&lt;h2&gt;Data Consistency&lt;/h2&gt;Each database update is performed in a separate transaction and the logfile and database updates are performed in the background. This means that dictionary updates are atomic and consistent, but not always durable. If the application crashes only updates whose log records have been written to disk will be recovered. It is possible to force the dictionary updates created so far to be persisted to disk using &lt;b&gt;PersistentDictionary.Flush()&lt;/b&gt;. Note that every Flush() call requires a disk I/O so using this too frequently will severely limit the update rate. Disposing the dictionary also flushes all its changes to disk.&lt;br /&gt;
&lt;h2&gt;Performance Measurements&lt;/h2&gt;These are very basic performance measurements made with a PersistentDictionary&amp;lt;long, string&amp;gt; where the string data was 64 bytes in length. These measurements were taken on my desktop system.&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt; Sequential inserts &lt;/td&gt;&lt;td&gt; 32,000 entries/second &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Random inserts &lt;/td&gt;&lt;td&gt; 17,000 entries/second &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Random Updates &lt;/td&gt;&lt;td&gt; 36,000 entries/second &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Random lookups (database cached in memory) &lt;/td&gt;&lt;td&gt; 137,000 entries/second &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt; Linq queries (range of records) &lt;/td&gt;&lt;td&gt; 14,000 queries/second &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Performance will vary from application to application. Factors that affect performance include:
&lt;ul&gt;&lt;li&gt;Total number of items in the dictionary.&lt;/li&gt;
&lt;li&gt;Size of the data. Retrieving an int will be faster than retrieving a 55MB string.&lt;/li&gt;
&lt;li&gt;How much of the database is cached in memory. When first opening a populated dictionary the data will not be cached in memory so initial lookups will be slow.&lt;/li&gt;
&lt;li&gt;Update patterns. Sequential inserts are much faster than random inserts.&lt;/li&gt;
&lt;li&gt;Structure serialization. Using structures as dictionary data can be much slower than using basic data types.&lt;/li&gt;
&lt;li&gt;Disk performance.&lt;/li&gt;&lt;/ul&gt;

&lt;h2&gt;File Management&lt;/h2&gt;The PersistentDictionary code will automatically open or create a database in the specified directory. To determine if a dictionary database already exists use &lt;b&gt;PersistentDictionaryFile.Exists()&lt;/b&gt;. To remove a dictionary use &lt;b&gt;PersistentDictionaryFile.DeleteFiles()&lt;/b&gt;. &lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Tue, 15 Feb 2011 22:56:34 GMT</pubDate><guid isPermaLink="false">Updated Wiki: PersistentDictionaryDocumentation 20110215105634P</guid></item><item><title>Updated Wiki: SystemStats</title><link>http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;version=8</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;SystemStats Sample&lt;/h1&gt;This shows how to use a PersistentDictionary to build a simple application to track and report on some performance counters. There are two main parts:
&lt;ol&gt;&lt;li&gt;A mode that periodically collects performance counter values and stores them.&lt;/li&gt;
&lt;li&gt;A mode that queries the stored data.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;The Sample structure&lt;/h2&gt;This program will use a PersistentDictionary to map a DateTime to a collection of samples. We will group the samples together into a serializable structure.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; One sample of the statistics we are collecting. This struct is stored in&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; the PersistentDictionary, keyed by time.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;internal&lt;/span&gt; &lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Sample
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; processorTime;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; paging;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; freeBytes;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; ProcessorTime
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; Paging
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; FreeBytes
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes = value; }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Collecting Performance Counters&lt;/h2&gt;
To collect performance counters we just add a new Sample to the dictionary. A PersistentDictionary is backed by an ESENT database which will always be consistent after a crash. That means we don&amp;#39;t need to worry about data consistency after a crash.&lt;br /&gt; &lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Collect stats. This method never returns (just kill the program).&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The path to the dictionary.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; CollectStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath)
{
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;% Processor Time&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;_Total&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Pages/Sec&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter freeMemory = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Available Bytes&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        &lt;span style="color:Blue;"&gt;while&lt;/span&gt; (&lt;span style="color:Blue;"&gt;true&lt;/span&gt;)
        {
            dictionary[DateTime.Now] = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Sample
                {
                    ProcessorTime = processor.NextValue(),
                    Paging = paging.NextValue(),
                    FreeBytes = freeMemory.NextValue(),
                };

            Thread.Sleep(TimeSpan.FromSeconds(0.5));
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Updates to a PersistentDictionary are logged lazily -- after a crash some updates may be lost. It is possible to force the updates to be written to disk by calling the Flush() method on the PersistentDictionary, but that has to perform an I/O so it is considerably slower than a lazy update. In this case we are willing to lose a few updates after a crash.&lt;br /&gt;
&lt;h2&gt;Calculating statistics&lt;/h2&gt;
While querying the data we will want to calculate the min, max and average of the samples. This class will be used to do the calculations:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Calculates the average, min and max of a set of samples.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; Aggregator
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Number of samples seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; numSamples = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Running total of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; total = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The smallest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; min = Double.MaxValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The largest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; max = Double.MinValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the number of samples that were seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; NumSamples
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the average of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; Average
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; 0 == &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples ? 0 : &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total / &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Add a new sample.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sample&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The sample value/&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; AddSample(&lt;span style="color:Blue;"&gt;double&lt;/span&gt; sample)
    {
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples++;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total += sample;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min = Math.Min(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, sample);
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max = Math.Max(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, sample);
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets a string representation of the aggregate calculation.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; A string representation of the aggregate calculation&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;override&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; ToString()
    {
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt; String.Format(&lt;span style="color:#A31515;"&gt;&amp;quot;min = {0:N2}, max = {1:N2}, average = {2:N2}&amp;quot;&lt;/span&gt;, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.Average);
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Querying the PersistentDictionary&lt;/h2&gt;
The PersistentDictionary supports LINQ queries. Given a query like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
DateTime startTime = ...;
DateTime endTime = ...;
IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Only records which match the key criteria will be retrieved from the database. That means the runtime is determined by the number of samples retrieved, not the total number of samples. For best performance we only want to iterate over the samples once so we accumulate all the statistics at the same time, using the Aggregator class:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Dump the aggregate stats for the specified time period.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The path to the dictionary.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;startTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The starting time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;endTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The ending time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; DumpStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath, DateTime startTime, DateTime endTime)
{
    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(dictionaryPath))
    {
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt;;
    }

    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        Stopwatch queryTimer = Stopwatch.StartNew();
        IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;

        Aggregator processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator freeBytes = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        &lt;span style="color:Blue;"&gt;foreach&lt;/span&gt; (Sample s &lt;span style="color:Blue;"&gt;in&lt;/span&gt; samples)
        {
            processor.AddSample(s.ProcessorTime);
            paging.AddSample(s.Paging);
            freeBytes.AddSample(s.FreeBytes);
        }

        queryTimer.Stop();
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;{0} samples from {1} to {2}&amp;quot;&lt;/span&gt;, processor.NumSamples, startTime, endTime);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor time: {0}&amp;quot;&lt;/span&gt;, processor);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Paging: {0}&amp;quot;&lt;/span&gt;, paging);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Free bytes: {0}&amp;quot;&lt;/span&gt;, freeBytes);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Query took {0}&amp;quot;&lt;/span&gt;, queryTimer.Elapsed);
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The PersistentDictionary is multi-thread safe so it is fine to run (multiple) queries while the dictionary is being updated. It is possible to have multiple threads updating the dictionary as well.&lt;br /&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;
Now we just need a main method.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The main method. Called on program startup.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;args&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;Arguments to the program.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; Main(&lt;span style="color:Blue;"&gt;string&lt;/span&gt;[] args)
{
    &lt;span style="color:Blue;"&gt;const&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; DictionaryPath = &lt;span style="color:#A31515;"&gt;&amp;quot;SystemStats&amp;quot;&lt;/span&gt;;

    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (0 == args.Length)
    {
        CollectStats(DictionaryPath);
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt; &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (2 == args.Length)
    {
        DumpStats(DictionaryPath, DateTime.Parse(args[0]), DateTime.Parse(args[1]));
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
    {
        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(DictionaryPath))
        {
            Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        }
        &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
        {
            &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(DictionaryPath))
            {
                &lt;span style="color:Green;"&gt;// Getting the first item, last item or count of items are all O(1) operations.&lt;/span&gt;
                Console.WriteLine(
                    &lt;span style="color:#A31515;"&gt;&amp;quot;Stats available from {0} to {1} ({2}) records&amp;quot;&lt;/span&gt;,
                    dictionary.Keys.FirstOrDefault(),
                    dictionary.Keys.LastOrDefault(),
                    dictionary.Count);
            }                    
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Performance&lt;/h2&gt;
These numbers are from a database where samples were taken 100 times/second, there are slightly over 500,000 entries and the database is around 110MB.&lt;br /&gt;&lt;br /&gt;&lt;span class="codeInline"&gt;Stats available from 2/15/2011 12:59:48 PM to 2/15/2011 2:33:19 PM (492174) records&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here are the results of a few queries. Each run is a new process so none of the database is cached. In a real-world scenario a process might keep the dictionary open so subsequent queries would be even faster:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;.\SystemStats.exe &amp;quot;2/15/2011 2:43:00 PM&amp;quot; &amp;quot;2/15/2011 2:43:01 PM&amp;quot;
82 samples from 2/15/2011 2:43:00 PM to 2/15/2011 2:43:01 PM
Processor time: min = 0.00, max = 100.00, average = 42.89
Paging: min = 0.00, max = 464.90, average = 6.28
Free bytes: min = 3,873,783,808.00, max = 3,911,086,080.00, average = 3,901,525,966.05
Query took 00:00:00.1149587

&amp;gt;.\SystemStats.exe &amp;quot;2/15/2011 2:33:00 PM&amp;quot; &amp;quot;2/15/2011 2:34:00 PM&amp;quot;
1795 samples from 2/15/2011 2:33:00 PM to 2/15/2011 2:34:00 PM
Processor time: min = 0.00, max = 100.00, average = 41.26
Paging: min = 0.00, max = 3,075.65, average = 7.93
Free bytes: min = 3,995,095,040.00, max = 4,011,421,696.00, average = 4,005,309,211.24
Query took 00:00:00.2190249

&amp;gt;.\SystemStats.exe &amp;quot;2/15/2011 2:34:30 PM&amp;quot; &amp;quot;2/15/2011 2:49:30 PM&amp;quot;
64002 samples from 2/15/2011 2:34:30 PM to 2/15/2011 2:49:30 PM
Processor time: min = 0.00, max = 100.00, average = 40.30
Paging: min = 0.00, max = 11,241.36, average = 4.79
Free bytes: min = 3,860,332,544.00, max = 4,047,314,944.00, average = 3,927,072,817.73
Query took 00:00:03.9911891

&amp;gt;.\SystemStats.exe &amp;quot;2/15/2011 1:27:48 PM&amp;quot; &amp;quot;2/15/2011 2:27:48 PM&amp;quot;
337585 samples from 2/15/2011 1:27:48 PM to 2/15/2011 2:27:48 PM
Processor time: min = 0.00, max = 100.00, average = 37.83
Paging: min = 0.00, max = 54,169.92, average = 68.10
Free bytes: min = 3,986,374,656.00, max = 4,128,804,864.00, average = 4,068,317,649.07
Query took 00:00:20.6299002&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The query performance is proportional to the number of entries processed, it will be basically independant of the database size.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Tue, 15 Feb 2011 22:54:29 GMT</pubDate><guid isPermaLink="false">Updated Wiki: SystemStats 20110215105429P</guid></item><item><title>Updated Wiki: SystemStats</title><link>http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;version=7</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;SystemStats Sample&lt;/h1&gt;This shows how to use a PersistentDictionary to build a simple application to track and report on some performance counters. There are two main parts:
&lt;ol&gt;&lt;li&gt;A mode that periodically collects performance counter values and stores them.&lt;/li&gt;
&lt;li&gt;A mode that queries the stored data.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;The Sample structure&lt;/h2&gt;This program will use a PersistentDictionary to map a DateTime to a collection of samples. We will group the samples together into a serializable structure.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; One sample of the statistics we are collecting. This struct is stored in&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; the PersistentDictionary, keyed by time.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;internal&lt;/span&gt; &lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Sample
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; processorTime;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; paging;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; freeBytes;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; ProcessorTime
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; Paging
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; FreeBytes
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes = value; }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Collecting Performance Counters&lt;/h2&gt;
To collect performance counters we just add a new Sample to the dictionary. A PersistentDictionary is backed by an ESENT database which will always be consistent after a crash. That means we don&amp;#39;t need to worry about data consistency after a crash.&lt;br /&gt; &lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Collect stats. This method never returns (just kill the program).&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The path to the dictionary.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; CollectStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath)
{
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;% Processor Time&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;_Total&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Pages/Sec&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter freeMemory = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Available Bytes&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        &lt;span style="color:Blue;"&gt;while&lt;/span&gt; (&lt;span style="color:Blue;"&gt;true&lt;/span&gt;)
        {
            dictionary[DateTime.Now] = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Sample
                {
                    ProcessorTime = processor.NextValue(),
                    Paging = paging.NextValue(),
                    FreeBytes = freeMemory.NextValue(),
                };

            Thread.Sleep(TimeSpan.FromSeconds(0.5));
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Updates to a PersistentDictionary are logged lazily -- after a crash some updates may be lost. It is possible to force the updates to be written to disk by calling the Flush() method on the PersistentDictionary, but that has to perform an I/O so it is considerably slower than a lazy update. In this case we are willing to lose a few updates after a crash.&lt;br /&gt;
&lt;h2&gt;Calculating statistics&lt;/h2&gt;
While querying the data we will want to calculate the min, max and average of the samples. This class will be used to do the calculations:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Calculates the average, min and max of a set of samples.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; Aggregator
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Number of samples seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; numSamples = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Running total of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; total = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The smallest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; min = Double.MaxValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The largest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; max = Double.MinValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the number of samples that were seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; NumSamples
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the average of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; Average
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; 0 == &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples ? 0 : &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total / &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Add a new sample.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sample&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The sample value/&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; AddSample(&lt;span style="color:Blue;"&gt;double&lt;/span&gt; sample)
    {
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples++;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total += sample;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min = Math.Min(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, sample);
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max = Math.Max(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, sample);
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets a string representation of the aggregate calculation.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; A string representation of the aggregate calculation&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;override&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; ToString()
    {
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt; String.Format(&lt;span style="color:#A31515;"&gt;&amp;quot;min = {0:N2}, max = {1:N2}, average = {2:N2}&amp;quot;&lt;/span&gt;, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.Average);
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Querying the PersistentDictionary&lt;/h2&gt;
The PersistentDictionary supports LINQ queries. Given a query like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
DateTime startTime = ...;
DateTime endTime = ...;
IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Only records which match the key criteria will be retrieved from the database. That means the runtime is determined by the number of samples retrieved, not the total number of samples. For best performance we only want to iterate over the samples once so we accumulate all the statistics at the same time, using the Aggregator class:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Dump the aggregate stats for the specified time period.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The path to the dictionary.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;startTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The starting time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;endTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The ending time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; DumpStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath, DateTime startTime, DateTime endTime)
{
    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(dictionaryPath))
    {
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt;;
    }

    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        Stopwatch queryTimer = Stopwatch.StartNew();
        IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;

        Aggregator processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator freeBytes = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        &lt;span style="color:Blue;"&gt;foreach&lt;/span&gt; (Sample s &lt;span style="color:Blue;"&gt;in&lt;/span&gt; samples)
        {
            processor.AddSample(s.ProcessorTime);
            paging.AddSample(s.Paging);
            freeBytes.AddSample(s.FreeBytes);
        }

        queryTimer.Stop();
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;{0} samples from {1} to {2}&amp;quot;&lt;/span&gt;, processor.NumSamples, startTime, endTime);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor time: {0}&amp;quot;&lt;/span&gt;, processor);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Paging: {0}&amp;quot;&lt;/span&gt;, paging);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Free bytes: {0}&amp;quot;&lt;/span&gt;, freeBytes);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Query took {0}&amp;quot;&lt;/span&gt;, queryTimer.Elapsed);
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The PersistentDictionary is multi-thread safe so it is fine to run (multiple) queries while the dictionary is being updated. It is possible to have multiple threads updating the dictionary as well.&lt;br /&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;
Now we just need a main method.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The main method. Called on program startup.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;args&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;Arguments to the program.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; Main(&lt;span style="color:Blue;"&gt;string&lt;/span&gt;[] args)
{
    &lt;span style="color:Blue;"&gt;const&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; DictionaryPath = &lt;span style="color:#A31515;"&gt;&amp;quot;SystemStats&amp;quot;&lt;/span&gt;;

    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (0 == args.Length)
    {
        CollectStats(DictionaryPath);
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt; &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (2 == args.Length)
    {
        DumpStats(DictionaryPath, DateTime.Parse(args[0]), DateTime.Parse(args[1]));
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
    {
        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(DictionaryPath))
        {
            Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        }
        &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
        {
            &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(DictionaryPath))
            {
                &lt;span style="color:Green;"&gt;// Getting the first item, last item or count of items are all O(1) operations.&lt;/span&gt;
                Console.WriteLine(
                    &lt;span style="color:#A31515;"&gt;&amp;quot;Stats available from {0} to {1} ({2}) records&amp;quot;&lt;/span&gt;,
                    dictionary.Keys.FirstOrDefault(),
                    dictionary.Keys.LastOrDefault(),
                    dictionary.Count);
            }                    
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Tue, 15 Feb 2011 21:52:37 GMT</pubDate><guid isPermaLink="false">Updated Wiki: SystemStats 20110215095237P</guid></item><item><title>Updated Wiki: SystemStats</title><link>http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;version=6</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;SystemStats Sample&lt;/h1&gt;This shows how to use a PersistentDictionary to build a simple application to track and report on some performance counters. There are two main parts:
&lt;ol&gt;&lt;li&gt;A mode that periodically collects performance counter values and stores them.&lt;/li&gt;
&lt;li&gt;A mode that queries the stored data.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;The Sample structure&lt;/h2&gt;This program will use a PersistentDictionary to map a DateTime to a collection of samples. We will group the samples together into a serializable structure.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; One sample of the statistics we are collecting. This struct is stored in&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; the PersistentDictionary, keyed by time.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;internal&lt;/span&gt; &lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Sample
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; processorTime;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; paging;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; freeBytes;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; ProcessorTime
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; Paging
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; FreeBytes
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes = value; }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Collecting Performance Counters&lt;/h2&gt;
To collect performance counters we just add a new Sample to the dictionary. A PersistentDictionary is backed by an ESENT database which will always be consistent after a crash. That means we don&amp;#39;t need to worry about data consistency after a crash.&lt;br /&gt; &lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Collect stats. This method never returns (just kill the program).&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The path to the dictionary.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; CollectStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath)
{
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;% Processor Time&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;_Total&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Pages/Sec&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter freeMemory = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Available Bytes&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        &lt;span style="color:Blue;"&gt;while&lt;/span&gt; (&lt;span style="color:Blue;"&gt;true&lt;/span&gt;)
        {
            dictionary[DateTime.Now] = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Sample
                {
                    ProcessorTime = processor.NextValue(),
                    Paging = paging.NextValue(),
                    FreeBytes = freeMemory.NextValue(),
                };

            Thread.Sleep(TimeSpan.FromSeconds(0.5));
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Updates to a PersistentDictionary are logged lazily -- after a crash some updates may be lost. It is possible to force the updates to be written to disk by calling the Flush() method on the PersistentDictionary, but that has to perform an I/O so it is considerably slower than a lazy update. In this case we are willing to lose a few updates after a crash.&lt;br /&gt;
&lt;h2&gt;Calculating statistics&lt;/h2&gt;
While querying the data we will want to calculate the min, max and average of the samples. This class will be used to do the calculations:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Calculates the average, min and max of a set of samples.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; Aggregator
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Number of samples seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; numSamples = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Running total of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; total = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The smallest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; min = Double.MaxValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The largest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; max = Double.MinValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the number of samples that were seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; NumSamples
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the average of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; Average
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; 0 == &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples ? 0 : &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total / &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Add a new sample.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sample&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The sample value/&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; AddSample(&lt;span style="color:Blue;"&gt;double&lt;/span&gt; sample)
    {
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples++;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total += sample;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min = Math.Min(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, sample);
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max = Math.Max(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, sample);
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets a string representation of the aggregate calculation.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; A string representation of the aggregate calculation&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;override&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; ToString()
    {
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt; String.Format(&lt;span style="color:#A31515;"&gt;&amp;quot;min = {0:N2}, max = {1:N2}, average = {2:N2}&amp;quot;&lt;/span&gt;, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.Average);
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Querying the PersistentDictionary&lt;/h2&gt;
The PersistentDictionary supports LINQ queries. Given a query like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
DateTime startTime = ...;
DateTime endTime = ...;
IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Only records which match the key criteria will be retrieved from the database. That means the runtime is determined by the number of samples retrieved, not the total number of samples. For best performance we only want to iterate over the samples once so we accumulate all the statistics at the same time, using the Aggregator class:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Dump the aggregate stats for the specified time period.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The path to the dictionary.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;startTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The starting time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;endTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The ending time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; DumpStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath, DateTime startTime, DateTime endTime)
{
    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(dictionaryPath))
    {
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt;;
    }

    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        Stopwatch queryTimer = Stopwatch.StartNew();
        IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;

        Aggregator processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator freeBytes = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        &lt;span style="color:Blue;"&gt;foreach&lt;/span&gt; (Sample s &lt;span style="color:Blue;"&gt;in&lt;/span&gt; samples)
        {
            processor.AddSample(s.ProcessorTime);
            paging.AddSample(s.Paging);
            freeBytes.AddSample(s.FreeBytes);
        }

        queryTimer.Stop();
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;{0} samples from {1} to {2}&amp;quot;&lt;/span&gt;, processor.NumSamples, startTime, endTime);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor time: {0}&amp;quot;&lt;/span&gt;, processor);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Paging: {0}&amp;quot;&lt;/span&gt;, paging);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Free bytes: {0}&amp;quot;&lt;/span&gt;, freeBytes);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Query took {0}&amp;quot;&lt;/span&gt;, queryTimer.Elapsed);
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;
Now we just need a main method.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The main method. Called on program startup.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;args&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;Arguments to the program.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; Main(&lt;span style="color:Blue;"&gt;string&lt;/span&gt;[] args)
{
    &lt;span style="color:Blue;"&gt;const&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; DictionaryPath = &lt;span style="color:#A31515;"&gt;&amp;quot;SystemStats&amp;quot;&lt;/span&gt;;

    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (0 == args.Length)
    {
        CollectStats(DictionaryPath);
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt; &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (2 == args.Length)
    {
        DumpStats(DictionaryPath, DateTime.Parse(args[0]), DateTime.Parse(args[1]));
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
    {
        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(DictionaryPath))
        {
            Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        }
        &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
        {
            &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(DictionaryPath))
            {
                &lt;span style="color:Green;"&gt;// Getting the first item, last item or count of items are all O(1) operations.&lt;/span&gt;
                Console.WriteLine(
                    &lt;span style="color:#A31515;"&gt;&amp;quot;Stats available from {0} to {1} ({2}) records&amp;quot;&lt;/span&gt;,
                    dictionary.Keys.FirstOrDefault(),
                    dictionary.Keys.LastOrDefault(),
                    dictionary.Count);
            }                    
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Tue, 15 Feb 2011 21:47:33 GMT</pubDate><guid isPermaLink="false">Updated Wiki: SystemStats 20110215094733P</guid></item><item><title>Updated Wiki: SystemStats</title><link>http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;version=5</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;SystemStats Sample&lt;/h1&gt;This shows how to use a PersistentDictionary to build a simple application to track and report on some performance counters. There are two main parts:
&lt;ol&gt;&lt;li&gt;A mode that periodically collects performance counter values and stores them.&lt;/li&gt;
&lt;li&gt;A mode that queries the stored data.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;The Sample structure&lt;/h2&gt;This program will use a PersistentDictionary to map a DateTime to a collection of samples. We will group the samples together into a serializable structure.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; One sample of the statistics we are collecting. This struct is stored in&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; the PersistentDictionary, keyed by time.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;internal&lt;/span&gt; &lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Sample
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; processorTime;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; paging;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; freeBytes;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; ProcessorTime
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; Paging
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; FreeBytes
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes = value; }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Collecting Performance Counters&lt;/h2&gt;
To collect performance counters we just add a new Sample to the dictionary. A PersistentDictionary is backed by an ESENT database which will always be consistent after a crash. That means we don&amp;#39;t need to worry about data consistency after a crash.&lt;br /&gt; &lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Collect stats. This method never returns (just kill the program).&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The path to the dictionary.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; CollectStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath)
{
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;% Processor Time&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;_Total&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Pages/Sec&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter freeMemory = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Available Bytes&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        &lt;span style="color:Blue;"&gt;while&lt;/span&gt; (&lt;span style="color:Blue;"&gt;true&lt;/span&gt;)
        {
            dictionary[DateTime.Now] = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Sample
                {
                    ProcessorTime = processor.NextValue(),
                    Paging = paging.NextValue(),
                    FreeBytes = freeMemory.NextValue(),
                };

            Thread.Sleep(TimeSpan.FromSeconds(0.5));
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Updates to a PersistentDictionary are logged lazily -- after a crash some updates may be lost. It is possible to force the updates to be written to disk by calling the Flush() method on the PersistentDictionary, but that has to perform an I/O so it is considerably slower than a lazy update. In this case we are willing to lose a few updates after a crash.&lt;br /&gt;
&lt;h2&gt;Calculating statistics&lt;/h2&gt;
While querying the data we will want to calculate the min, max and average of the samples. This class will be used to do the calculations:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Calculates the average, min and max of a set of samples.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; Aggregator
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Number of samples seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; numSamples = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Running total of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; total = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The smallest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; min = Double.MaxValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The largest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; max = Double.MinValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the number of samples that were seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; NumSamples
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the average of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; Average
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; 0 == &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples ? 0 : &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total / &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Add a new sample.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sample&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The sample value/&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; AddSample(&lt;span style="color:Blue;"&gt;double&lt;/span&gt; sample)
    {
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples++;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total += sample;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min = Math.Min(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, sample);
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max = Math.Max(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, sample);
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets a string representation of the aggregate calculation.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; A string representation of the aggregate calculation&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;override&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; ToString()
    {
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt; String.Format(&lt;span style="color:#A31515;"&gt;&amp;quot;min = {0:N2}, max = {1:N2}, average = {2:N2}&amp;quot;&lt;/span&gt;, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.Average);
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Querying the PersistentDictionary&lt;/h2&gt;
The PersistentDictionary supports LINQ queries. Given a query like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
DateTime startTime = ...;
DateTime endTime = ...;
IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Only records which match the key criteria will be retrieved from the database. That means the runtime is determined by the number of samples retrieved, not the total number of samples. For best performance we only want to iterate over the samples once so we accumulate all the statistics at the same time, using the Aggregator class:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Dump the aggregate stats for the specified time period.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;startTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The starting time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;endTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The ending time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; DumpStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath, DateTime startTime, DateTime endTime)
{
    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(dictionaryPath))
    {
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt;;
    }

    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        Stopwatch queryTimer = Stopwatch.StartNew();
        IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;

        Aggregator processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator freeBytes = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        &lt;span style="color:Blue;"&gt;foreach&lt;/span&gt; (Sample s &lt;span style="color:Blue;"&gt;in&lt;/span&gt; samples)
        {
            processor.AddSample(s.ProcessorTime);
            paging.AddSample(s.Paging);
            freeBytes.AddSample(s.FreeBytes);
        }

        queryTimer.Stop();
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;{0} samples from {1} to {2}&amp;quot;&lt;/span&gt;, processor.NumSamples, startTime, endTime);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor time: {0}&amp;quot;&lt;/span&gt;, processor);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Paging: {0}&amp;quot;&lt;/span&gt;, paging);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Free bytes: {0}&amp;quot;&lt;/span&gt;, freeBytes);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Query took {0}&amp;quot;&lt;/span&gt;, queryTimer.Elapsed);
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;
Now we just need a main method.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The main method. Called on program startup.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;args&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;Arguments to the program.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; Main(&lt;span style="color:Blue;"&gt;string&lt;/span&gt;[] args)
{
    &lt;span style="color:Blue;"&gt;const&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; DictionaryPath = &lt;span style="color:#A31515;"&gt;&amp;quot;SystemStats&amp;quot;&lt;/span&gt;;

    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (0 == args.Length)
    {
        CollectStats(DictionaryPath);
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt; &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (2 == args.Length)
    {
        DumpStats(DictionaryPath, DateTime.Parse(args[0]), DateTime.Parse(args[1]));
    }
    &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
    {
        &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(DictionaryPath))
        {
            Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        }
        &lt;span style="color:Blue;"&gt;else&lt;/span&gt;
        {
            &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(DictionaryPath))
            {
                Console.WriteLine(
                    &lt;span style="color:#A31515;"&gt;&amp;quot;Stats available from {0} to {1} ({2}) records&amp;quot;&lt;/span&gt;,
                    dictionary.Keys.FirstOrDefault(),
                    dictionary.Keys.LastOrDefault(),
                    dictionary.Count);
            }                    
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Tue, 15 Feb 2011 21:36:06 GMT</pubDate><guid isPermaLink="false">Updated Wiki: SystemStats 20110215093606P</guid></item><item><title>Updated Wiki: SystemStats</title><link>http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;version=4</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;SystemStats Sample&lt;/h1&gt;This shows how to use a PersistentDictionary to build a simple application to track and report on some performance counters. There are two main parts:
&lt;ol&gt;&lt;li&gt;A mode that periodically collects performance counter values and stores them.&lt;/li&gt;
&lt;li&gt;A mode that queries the stored data.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;The Sample structure&lt;/h2&gt;This program will use a PersistentDictionary to map a DateTime to a collection of samples. We will group the samples together into a serializable structure.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; One sample of the statistics we are collecting. This struct is stored in&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; the PersistentDictionary, keyed by time.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;internal&lt;/span&gt; &lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Sample
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; processorTime;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; paging;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; freeBytes;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; ProcessorTime
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; Paging
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; FreeBytes
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes = value; }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Collecting Performance Counters&lt;/h2&gt;
To collect performance counters we just add a new Sample to the dictionary. A PersistentDictionary is backed by an ESENT database which will always be consistent after a crash. That means we don&amp;#39;t need to worry about data consistency after a crash.&lt;br /&gt; &lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Collect stats. This method never returns (just kill the program).&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The path to the dictionary.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; CollectStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath)
{
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;% Processor Time&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;_Total&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Pages/Sec&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter freeMemory = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Available Bytes&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        &lt;span style="color:Blue;"&gt;while&lt;/span&gt; (&lt;span style="color:Blue;"&gt;true&lt;/span&gt;)
        {
            dictionary[DateTime.Now] = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Sample
                {
                    ProcessorTime = processor.NextValue(),
                    Paging = paging.NextValue(),
                    FreeBytes = freeMemory.NextValue(),
                };

            Thread.Sleep(TimeSpan.FromSeconds(0.5));
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Updates to a PersistentDictionary are logged lazily -- after a crash some updates may be lost. It is possible to force the updates to be written to disk by calling the Flush() method on the PersistentDictionary, but that has to perform an I/O so it is considerably slower than a lazy update. In this case we are willing to lose a few updates after a crash.&lt;br /&gt;
&lt;h2&gt;Calculating statistics&lt;/h2&gt;
While querying the data we will want to calculate the min, max and average of the samples. This class will be used to do the calculations:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Calculates the average, min and max of a set of samples.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; Aggregator
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Number of samples seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; numSamples = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Running total of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; total = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The smallest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; min = Double.MaxValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The largest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; max = Double.MinValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the number of samples that were seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; NumSamples
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the average of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; Average
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; 0 == &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples ? 0 : &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total / &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Add a new sample.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sample&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The sample value/&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; AddSample(&lt;span style="color:Blue;"&gt;double&lt;/span&gt; sample)
    {
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples++;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total += sample;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min = Math.Min(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, sample);
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max = Math.Max(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, sample);
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets a string representation of the aggregate calculation.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; A string representation of the aggregate calculation&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;override&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; ToString()
    {
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt; String.Format(&lt;span style="color:#A31515;"&gt;&amp;quot;min = {0:N2}, max = {1:N2}, average = {2:N2}&amp;quot;&lt;/span&gt;, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.Average);
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Querying the PersistentDictionary&lt;/h2&gt;
The PersistentDictionary supports LINQ queries. Given a query like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
DateTime startTime = ...;
DateTime endTime = ...;
IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Only records which match the key criteria will be retrieved from the database. That means the runtime is determined by the number of samples retrieved, not the total number of samples. For best performance we only want to iterate over the samples once so we accumulate all the statistics at the same time, using the Aggregator class:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Dump the aggregate stats for the specified time period.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;startTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The starting time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;endTime&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The ending time.&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; DumpStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath, DateTime startTime, DateTime endTime)
{
    &lt;span style="color:Blue;"&gt;if&lt;/span&gt; (!PersistentDictionaryFile.Exists(dictionaryPath))
    {
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;No stats collected&amp;quot;&lt;/span&gt;);
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt;;
    }

    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        Stopwatch queryTimer = Stopwatch.StartNew();
        IEnumerable&amp;lt;Sample&amp;gt; samples = &lt;span style="color:Blue;"&gt;from&lt;/span&gt; x &lt;span style="color:Blue;"&gt;in&lt;/span&gt; dictionary &lt;span style="color:Blue;"&gt;where&lt;/span&gt; x.Key &amp;gt;= startTime &amp;amp;&amp;amp; x.Key &amp;lt;= endTime &lt;span style="color:Blue;"&gt;select&lt;/span&gt; x.Value;

        Aggregator processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        Aggregator freeBytes = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Aggregator();
        &lt;span style="color:Blue;"&gt;foreach&lt;/span&gt; (Sample s &lt;span style="color:Blue;"&gt;in&lt;/span&gt; samples)
        {
            processor.AddSample(s.ProcessorTime);
            paging.AddSample(s.Paging);
            freeBytes.AddSample(s.FreeBytes);
        }

        queryTimer.Stop();
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;{0} samples from {1} to {2}&amp;quot;&lt;/span&gt;, processor.NumSamples, startTime, endTime);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor time: {0}&amp;quot;&lt;/span&gt;, processor);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Paging: {0}&amp;quot;&lt;/span&gt;, paging);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Free bytes: {0}&amp;quot;&lt;/span&gt;, freeBytes);
        Console.WriteLine(&lt;span style="color:#A31515;"&gt;&amp;quot;Query took {0}&amp;quot;&lt;/span&gt;, queryTimer.Elapsed);
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Tue, 15 Feb 2011 21:34:42 GMT</pubDate><guid isPermaLink="false">Updated Wiki: SystemStats 20110215093442P</guid></item><item><title>Updated Wiki: SystemStats</title><link>http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;version=3</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;SystemStats Sample&lt;/h1&gt;This shows how to use a PersistentDictionary to build a simple application to track and report on some performance counters. There are two main parts:
&lt;ol&gt;&lt;li&gt;A mode that periodically collects performance counter values and stores them.&lt;/li&gt;
&lt;li&gt;A mode that queries the stored data.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;The Sample structure&lt;/h2&gt;This program will use a PersistentDictionary to map a DateTime to a collection of samples. We will group the samples together into a serializable structure.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; One sample of the statistics we are collecting. This struct is stored in&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; the PersistentDictionary, keyed by time.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;internal&lt;/span&gt; &lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Sample
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; processorTime;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; paging;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; freeBytes;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; ProcessorTime
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; Paging
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; FreeBytes
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes = value; }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Collecting Performance Counters&lt;/h2&gt;
To collect performance counters we just add a new Sample to the dictionary. A PersistentDictionary is backed by an ESENT database which will always be consistent after a crash. That means we don&amp;#39;t need to worry about data consistency after a crash.&lt;br /&gt; &lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Collect stats. This method never returns (just kill the program).&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The path to the dictionary.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; CollectStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath)
{
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;% Processor Time&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;_Total&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Pages/Sec&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter freeMemory = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Available Bytes&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        &lt;span style="color:Blue;"&gt;while&lt;/span&gt; (&lt;span style="color:Blue;"&gt;true&lt;/span&gt;)
        {
            dictionary[DateTime.Now] = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Sample
                {
                    ProcessorTime = processor.NextValue(),
                    Paging = paging.NextValue(),
                    FreeBytes = freeMemory.NextValue(),
                };

            Thread.Sleep(TimeSpan.FromSeconds(0.5));
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Updates to a PersistentDictionary are logged lazily -- after a crash some updates may be lost. It is possible to force the updates to be written to disk by calling the Flush() method on the PersistentDictionary, but that has to perform an I/O so it is considerably slower than a lazy update. In this case we are willing to lose a few updates after a crash.&lt;br /&gt;
&lt;h2&gt;Calculating statistics&lt;/h2&gt;
While querying the data we will want to calculate the min, max and average of the samples. This class will be used to do the calculations:&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Calculates the average, min and max of a set of samples.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;class&lt;/span&gt; Aggregator
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Number of samples seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; numSamples = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Running total of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; total = 0;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The smallest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; min = Double.MaxValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The largest sample seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; max = Double.MinValue;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the number of samples that were seen.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;int&lt;/span&gt; NumSamples
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets the average of all the samples.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;double&lt;/span&gt; Average
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; 0 == &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples ? 0 : &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total / &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Add a new sample.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;sample&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color:Green;"&gt;The sample value/&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; AddSample(&lt;span style="color:Blue;"&gt;double&lt;/span&gt; sample)
    {
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.numSamples++;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.total += sample;
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min = Math.Min(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, sample);
        &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max = Math.Max(&lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, sample);
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets a string representation of the aggregate calculation.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; A string representation of the aggregate calculation&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;override&lt;/span&gt; &lt;span style="color:Blue;"&gt;string&lt;/span&gt; ToString()
    {
        &lt;span style="color:Blue;"&gt;return&lt;/span&gt; String.Format(&lt;span style="color:#A31515;"&gt;&amp;quot;min = {0:N2}, max = {1:N2}, average = {2:N2}&amp;quot;&lt;/span&gt;, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.min, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.max, &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.Average);
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Tue, 15 Feb 2011 21:29:31 GMT</pubDate><guid isPermaLink="false">Updated Wiki: SystemStats 20110215092931P</guid></item><item><title>Updated Wiki: SystemStats</title><link>http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;version=2</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;SystemStats Sample&lt;/h1&gt;This shows how to use a PersistentDictionary to build a simple application to track and report on some performance counters. There are two main parts:
&lt;ol&gt;&lt;li&gt;A mode that periodically collects performance counter values and stores them.&lt;/li&gt;
&lt;li&gt;A mode that queries the stored data.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;The Sample structure&lt;/h2&gt;This program will use a PersistentDictionary to map a DateTime to a collection of samples. We will group the samples together into a serializable structure.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; One sample of the statistics we are collecting. This struct is stored in&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; the PersistentDictionary, keyed by time.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;internal&lt;/span&gt; &lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Sample
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; processorTime;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; paging;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; freeBytes;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; ProcessorTime
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; Paging
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; FreeBytes
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes = value; }
    }
}
&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;Collecting Performance Counters&lt;/h1&gt;
To collect performance counters we just add a new Sample to the dictionary. A PersistentDictionary is backed by an ESENT database which will always be consistent after a crash. That means we don&amp;#39;t need to worry about data consistency after a crash.&lt;br /&gt; &lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Collect stats. This method never returns (just kill the program).&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;param name=&amp;quot;dictionaryPath&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The path to the dictionary.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
&lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;static&lt;/span&gt; &lt;span style="color:Blue;"&gt;void&lt;/span&gt; CollectStats(&lt;span style="color:Blue;"&gt;string&lt;/span&gt; dictionaryPath)
{
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter processor = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Processor&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;% Processor Time&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;_Total&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter paging = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Pages/Sec&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PerformanceCounter freeMemory = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PerformanceCounter(&lt;span style="color:#A31515;"&gt;&amp;quot;Memory&amp;quot;&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;&amp;quot;Available Bytes&amp;quot;&lt;/span&gt;))
    &lt;span style="color:Blue;"&gt;using&lt;/span&gt; (PersistentDictionary&amp;lt;DateTime, Sample&amp;gt; dictionary = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; PersistentDictionary&amp;lt;DateTime, Sample&amp;gt;(dictionaryPath))
    {
        &lt;span style="color:Blue;"&gt;while&lt;/span&gt; (&lt;span style="color:Blue;"&gt;true&lt;/span&gt;)
        {
            dictionary[DateTime.Now] = &lt;span style="color:Blue;"&gt;new&lt;/span&gt; Sample
                {
                    ProcessorTime = processor.NextValue(),
                    Paging = paging.NextValue(),
                    FreeBytes = freeMemory.NextValue(),
                };

            Thread.Sleep(TimeSpan.FromSeconds(0.5));
        }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Updates to a PersistentDictionary are logged lazily -- after a crash some updates may be lost. It is possible to force the updates to be written to disk by calling the Flush() method on the PersistentDictionary, but that has to perform an I/O so it is considerably slower than a lazy update. In this case we are willing to lose a few updates after a crash.&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Tue, 15 Feb 2011 21:24:52 GMT</pubDate><guid isPermaLink="false">Updated Wiki: SystemStats 20110215092452P</guid></item><item><title>Updated Wiki: SystemStats</title><link>http://managedesent.codeplex.com/wikipage?title=SystemStats&amp;version=1</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;SystemStats Sample&lt;/h1&gt;This shows how to use a PersistentDictionary to build a simple application to track and report on some performance counters. There are two main parts:
&lt;ol&gt;&lt;li&gt;A mode that periodically collects performance counter values and stores them.&lt;/li&gt;
&lt;li&gt;A mode that queries the stored data.&lt;/li&gt;&lt;/ol&gt;

&lt;h2&gt;The Sample structure&lt;/h2&gt;This program will use a PersistentDictionary to map a DateTime to a collection of samples. We will group the samples together into a structure.&lt;br /&gt;&lt;br /&gt;&lt;div style="color:Black;background-color:White;"&gt;&lt;pre&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; One sample of the statistics we are collecting. This struct is stored in&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; the PersistentDictionary, keyed by time.&lt;/span&gt;
&lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
[Serializable]
&lt;span style="color:Blue;"&gt;internal&lt;/span&gt; &lt;span style="color:Blue;"&gt;struct&lt;/span&gt; Sample
{
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; processorTime;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; paging;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; The amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;private&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; freeBytes;

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the processor usage.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; ProcessorTime
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.processorTime = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of system paging.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; Paging
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.paging = value; }
    }

    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt;&lt;span style="color:Green;"&gt; Gets or sets the amount of free memory.&lt;/span&gt;
    &lt;span style="color:Gray;"&gt;///&lt;/span&gt; &lt;span style="color:Gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span style="color:Blue;"&gt;public&lt;/span&gt; &lt;span style="color:Blue;"&gt;float&lt;/span&gt; FreeBytes
    {
        &lt;span style="color:Blue;"&gt;get&lt;/span&gt; { &lt;span style="color:Blue;"&gt;return&lt;/span&gt; &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes; }
        &lt;span style="color:Blue;"&gt;set&lt;/span&gt; { &lt;span style="color:Blue;"&gt;this&lt;/span&gt;.freeBytes = value; }
    }
}
&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Tue, 15 Feb 2011 21:15:04 GMT</pubDate><guid isPermaLink="false">Updated Wiki: SystemStats 20110215091504P</guid></item><item><title>Updated Wiki: Home</title><link>http://managedesent.codeplex.com/wikipage?version=25</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;ESENT Managed Interop&lt;/h1&gt;ManagedEsent provides managed access to ESENT, the embeddable database engine native to Windows. ManagedEsent uses the esent.dll that is part of Microsoft Windows so there are no extra unmanaged binaries to download and install.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Project Components&lt;/u&gt;&lt;br /&gt;The &lt;b&gt;&lt;a href="http://managedesent.codeplex.com/wikipage?title=ManagedEsentDocumentation&amp;referringTitle=Home"&gt;Microsoft.Isam.Esent.Interop&lt;/a&gt;&lt;/b&gt; namespace in EsentInterop.dll provides managed access to the basic ESENT API. Use this for applications that want access to the full ESENT feature set.&lt;br /&gt;&lt;br /&gt;The &lt;b&gt;&lt;a href="http://managedesent.codeplex.com/wikipage?title=PersistentDictionaryDocumentation&amp;referringTitle=Home"&gt;PersistentDictionary&lt;/a&gt;&lt;/b&gt; class in EsentCollections.dll provides a persistent, generic dictionary for .NET, with LINQ support. A PersistentDictionary is backed by an ESENT database and can be used to replace a standard Dictionary, HashTable, or SortedList. Use it when you want extremely simple, reliable and fast data persistence.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;esedb&lt;/b&gt; provides both dbm and shelve modules built on top of ESENT IronPython users.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Sat, 12 Feb 2011 02:03:01 GMT</pubDate><guid isPermaLink="false">Updated Wiki: Home 20110212020301A</guid></item><item><title>Updated Wiki: ManagedEsentApis</title><link>http://managedesent.codeplex.com/wikipage?title=ManagedEsentApis&amp;version=6</link><description>&lt;div class="wikidoc"&gt;These links go to the MSDN documentation for the unmanaged API. The ManagedEsent version will be called Api.&lt;i&gt;name&lt;/i&gt; and will have the same semantics. As much as possible, the managed version of the API will have the same arguments as the unmanaged.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294122.aspx" class="externalLink"&gt;JetAddColumn&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294074.aspx" class="externalLink"&gt;JetAttachDatabase&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269322.aspx" class="externalLink"&gt;JetAttachDatabase2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269318.aspx" class="externalLink"&gt;JetBackupInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294132.aspx" class="externalLink"&gt;JetBeginExternalBackupInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294131.aspx" class="externalLink"&gt;JetBeginSession&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294083.aspx" class="externalLink"&gt;JetBeginTransaction&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269268.aspx" class="externalLink"&gt;JetBeginTransaction2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294123.aspx" class="externalLink"&gt;JetCloseDatabase&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269270.aspx" class="externalLink"&gt;JetCloseFileInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294087.aspx" class="externalLink"&gt;JetCloseTable&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269191.aspx" class="externalLink"&gt;JetCommitTransaction&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269284.aspx" class="externalLink"&gt;JetCompact&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269192.aspx" class="externalLink"&gt;JetComputeStats&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269212.aspx" class="externalLink"&gt;JetCreateDatabase&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269208.aspx" class="externalLink"&gt;JetCreateDatabase2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294099.aspx" class="externalLink"&gt;JetCreateIndex&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269324.aspx" class="externalLink"&gt;JetCreateIndex2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294075.aspx" class="externalLink"&gt;JetCreateIndex3&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269354.aspx" class="externalLink"&gt;JetCreateInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269202.aspx" class="externalLink"&gt;JetCreateInstance2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269210.aspx" class="externalLink"&gt;JetCreateTable&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269343.aspx" class="externalLink"&gt;JetCreateTableColumnIndex&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294057.aspx" class="externalLink"&gt;JetCreateTableColumnIndex2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294079.aspx" class="externalLink"&gt;JetCreateTableColumnIndex3&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269317.aspx" class="externalLink"&gt;JetDefragment&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294095.aspx" class="externalLink"&gt;JetDefragment2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294121.aspx" class="externalLink"&gt;JetDefragment3&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269315.aspx" class="externalLink"&gt;JetDelete&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294062.aspx" class="externalLink"&gt;JetDeleteColumn&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269320.aspx" class="externalLink"&gt;JetDeleteColumn2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294081.aspx" class="externalLink"&gt;JetDeleteIndex&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294128.aspx" class="externalLink"&gt;JetDeleteTable&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269266.aspx" class="externalLink"&gt;JetDetachDatabase&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294105.aspx" class="externalLink"&gt;JetDetachDatabase2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269193.aspx" class="externalLink"&gt;JetDupCursor&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294141.aspx" class="externalLink"&gt;JetDupSession&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269204.aspx" class="externalLink"&gt;JetEndExternalBackupInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294047.aspx" class="externalLink"&gt;JetEndExternalBackupInstance2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294054.aspx" class="externalLink"&gt;JetEndSession&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269321.aspx" class="externalLink"&gt;JetEnumerateColumns&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294125.aspx" class="externalLink"&gt;JetEscrowUpdate&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294134.aspx" class="externalLink"&gt;JetFreeBuffer&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269350.aspx" class="externalLink"&gt;JetGetAttachInfoInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269221.aspx" class="externalLink"&gt;JetGetBookmark&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269215.aspx" class="externalLink"&gt;JetGetColumnInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294041.aspx" class="externalLink"&gt;JetGetCurrentIndex&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294126.aspx" class="externalLink"&gt;JetGetCursorInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269239.aspx" class="externalLink"&gt;JetGetDatabaseFileInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294076.aspx" class="externalLink"&gt;JetGetDatabaseInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294084.aspx" class="externalLink"&gt;JetGetIndexInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294149.aspx" class="externalLink"&gt;JetGetInstanceInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269183.aspx" class="externalLink"&gt;JetGetInstanceMiscInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294094.aspx" class="externalLink"&gt;JetGetLock&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269246.aspx" class="externalLink"&gt;JetGetLogInfoInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269247.aspx" class="externalLink"&gt;JetGetLogInfoInstance2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269234.aspx" class="externalLink"&gt;JetGetLS&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269232.aspx" class="externalLink"&gt;JetGetObjectInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269316.aspx" class="externalLink"&gt;JetGetRecordPosition&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294045.aspx" class="externalLink"&gt;JetGetRecordSize&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269314.aspx" class="externalLink"&gt;JetGetRecordSize2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269285.aspx" class="externalLink"&gt;JetGetSecondaryIndexBookmark&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269291.aspx" class="externalLink"&gt;JetGetSystemParameter&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294061.aspx" class="externalLink"&gt;JetGetTableColumnInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294102.aspx" class="externalLink"&gt;JetGetTableIndexInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269177.aspx" class="externalLink"&gt;JetGetTableInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269196.aspx" class="externalLink"&gt;JetGetThreadStats&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269199.aspx" class="externalLink"&gt;JetGetTruncateLogInfoInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294133.aspx" class="externalLink"&gt;JetGetVersion&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294053.aspx" class="externalLink"&gt;JetGotoBookmark&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269300.aspx" class="externalLink"&gt;JetGotoPosition&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269180.aspx" class="externalLink"&gt;JetGotoSecondaryIndexBookmark&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294109.aspx" class="externalLink"&gt;JetGrowDatabase&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269301.aspx" class="externalLink"&gt;JetIdle&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269267.aspx" class="externalLink"&gt;JetIndexRecordCount&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294068.aspx" class="externalLink"&gt;JetInit&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294065.aspx" class="externalLink"&gt;JetInit2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269296.aspx" class="externalLink"&gt;JetInit3&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269289.aspx" class="externalLink"&gt;JetIntersectIndexes&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269329.aspx" class="externalLink"&gt;JetMakeKey&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294117.aspx" class="externalLink"&gt;JetMove&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269299.aspx" class="externalLink"&gt;JetOpenDatabase&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269238.aspx" class="externalLink"&gt;JetOpenFileInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294118.aspx" class="externalLink"&gt;JetOpenTable&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294144.aspx" class="externalLink"&gt;JetOpenTemporaryTable&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269211.aspx" class="externalLink"&gt;JetOpenTempTable&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269302.aspx" class="externalLink"&gt;JetOpenTempTable2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269255.aspx" class="externalLink"&gt;JetOpenTempTable3&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269265.aspx" class="externalLink"&gt;JetOSSnapshotAbort&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294136.aspx" class="externalLink"&gt;JetOSSnapshotEnd&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269332.aspx" class="externalLink"&gt;JetOSSnapshotFreeze&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294070.aspx" class="externalLink"&gt;JetOSSnapshotGetFreezeInfo&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269224.aspx" class="externalLink"&gt;JetOSSnapshotPrepare&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294064.aspx" class="externalLink"&gt;JetOSSnapshotPrepareInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269229.aspx" class="externalLink"&gt;JetOSSnapshotThaw&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269231.aspx" class="externalLink"&gt;JetOSSnapshotTruncateLog&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294115.aspx" class="externalLink"&gt;JetOSSnapshotTruncateLogInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269339.aspx" class="externalLink"&gt;JetPrepareUpdate&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294143.aspx" class="externalLink"&gt;JetPrereadKeys&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294060.aspx" class="externalLink"&gt;JetReadFileInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269175.aspx" class="externalLink"&gt;JetRegisterCallback&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269218.aspx" class="externalLink"&gt;JetRenameColumn&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294142.aspx" class="externalLink"&gt;JetRenameTable&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269250.aspx" class="externalLink"&gt;JetResetSessionContext&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269261.aspx" class="externalLink"&gt;JetResetTableSequential&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269306.aspx" class="externalLink"&gt;JetRestoreInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269198.aspx" class="externalLink"&gt;JetRetrieveColumn&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294135.aspx" class="externalLink"&gt;JetRetrieveColumns&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294051.aspx" class="externalLink"&gt;JetRetrieveKey&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269273.aspx" class="externalLink"&gt;JetRollback&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294103.aspx" class="externalLink"&gt;JetSeek&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294137.aspx" class="externalLink"&gt;JetSetColumn&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269295.aspx" class="externalLink"&gt;JetSetColumnDefaultValue&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294050.aspx" class="externalLink"&gt;JetSetColumns&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294046.aspx" class="externalLink"&gt;JetSetCurrentIndex&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294110.aspx" class="externalLink"&gt;JetSetCurrentIndex2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269244.aspx" class="externalLink"&gt;JetSetCurrentIndex3&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269262.aspx" class="externalLink"&gt;JetSetCurrentIndex4&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269242.aspx" class="externalLink"&gt;JetSetDatabaseSize&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294112.aspx" class="externalLink"&gt;JetSetIndexRange&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269243.aspx" class="externalLink"&gt;JetSetLS&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294124.aspx" class="externalLink"&gt;JetSetSessionContext&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294044.aspx" class="externalLink"&gt;JetSetSystemParameter&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269323.aspx" class="externalLink"&gt;JetSetTableSequential&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269309.aspx" class="externalLink"&gt;JetStopBackupInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294108.aspx" class="externalLink"&gt;JetStopServiceInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269298.aspx" class="externalLink"&gt;JetTerm&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269223.aspx" class="externalLink"&gt;JetTerm2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269352.aspx" class="externalLink"&gt;JetTruncateLogInstance&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg294116.aspx" class="externalLink"&gt;JetUnregisterCallback&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269288.aspx" class="externalLink"&gt;JetUpdate&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/gg269190.aspx" class="externalLink"&gt;JetUpdate2&lt;span class="externalLinkIcon"&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Sat, 12 Feb 2011 01:59:14 GMT</pubDate><guid isPermaLink="false">Updated Wiki: ManagedEsentApis 20110212015914A</guid></item><item><title>Updated Wiki: Home</title><link>http://managedesent.codeplex.com/wikipage?version=24</link><description>&lt;div class="wikidoc"&gt;&lt;h1&gt;ESENT Managed Interop&lt;/h1&gt;ManagedEsent provides managed access to ESENT, the embeddable database engine native to Windows. ManagedEsent uses the esent.dll that is part of Microsoft Windows so there are no extra unmanaged binaries to download and install.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Project Components&lt;/u&gt;&lt;br /&gt;The &lt;b&gt;&lt;a href="http://managedesent.codeplex.com/wikipage?title=ManagedEsentDocumentation&amp;referringTitle=Home"&gt;Microsoft.Isam.Esent.Interop&lt;/a&gt;&lt;/b&gt; namespace in EsentInterop.dll provides managed access to the basic ESENT API. Use this for applications that want access to the full ESENT feature set.&lt;br /&gt;&lt;br /&gt;The &lt;b&gt;&lt;a href="http://managedesent.codeplex.com/wikipage?title=PersistentDictionaryDocumentation&amp;referringTitle=Home"&gt;PersistentDictionary&lt;/a&gt;&lt;/b&gt; class in EsentCollections.dll provides a persistent, generic dictionary for .NET, with LINQ support. A PersistentDictionary is backed by an ESENT database and can be used to replace a standard Dictionary, HashTable, or SortedList. Use it when you want extremely simple, reliable and fast data persistence.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;esedb&lt;/b&gt; is a dbm-like interface to ESENT for IronPython users.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ClearBoth"&gt;&lt;/div&gt;</description><author>laurionb</author><pubDate>Sat, 12 Feb 2011 01:42:28 GMT</pubDate><guid isPermaLink="false">Updated Wiki: Home 20110212014228A</guid></item></channel></rss>