cpp50Example_main.cpp
                                            
                                            A simple performance test for basic RDM Core functions. This example needs a compiled schema, cpp50.sdl.
/* \file cpp50_main.cpp
                                                    
                                                     *  \brief Source code for a simple performance example
                                                    
                                                     *
                                                    
                                                     *  Below is a simple performance example.  It uses the C API.
                                                    
                                                     *  However, this code is in C++ as two C++ classes and the standard
                                                    
                                                     *  C++ libarary are used for I/O.
                                                    
                                                     *
                                                    
                                                     *  All the memory used by RDM is provided by a buffer compiled into
                                                    
                                                     *  this application (static char buf[MEM_SIZE]) except for possibly
                                                    
                                                     *  some memory allocated by system functions used by RDM for the
                                                    
                                                     *  implementation of the Platform Support Layer (PSP).
                                                    
                                                     *
                                                    
                                                     *  There is three main parts to this performance example.
                                                    
                                                     *
                                                    
                                                     *  First we do a number of operations where we do not guarantee
                                                    
                                                     *  database durability:
                                                    
                                                     *
                                                    
                                                     *  - Initialize the database
                                                    
                                                     *
                                                    
                                                     *  - Insert 1 million entries with a transaction size of 1000
                                                    
                                                     *
                                                    
                                                     *  - Lookup 1000 random rows from the data inserted above
                                                    
                                                     *
                                                    
                                                     *  - Loopup 1000 random rows where 90% of them does not exist and
                                                    
                                                     *    10% from the data inserted above
                                                    
                                                     *
                                                    
                                                     *  - Update the database by adding 1000 new entries
                                                    
                                                     *
                                                    
                                                     *  - Update the database by deleting 1000 random entries
                                                    
                                                     *
                                                    
                                                     *  Then the second part where we are fully durable:
                                                    
                                                     *
                                                    
                                                     *  - Update the database by adding 1000 new entries
                                                    
                                                     *
                                                    
                                                     *  - Update the database by deleting 1000 random entries
                                                    
                                                     *
                                                    
                                                     *
                                                    
                                                     *  The third part where we do inserts and lookups in parallel where
                                                    
                                                     *  we are not durable:
                                                    
                                                     *
                                                    
                                                     *  - 1000 inserts, deletes, and reads in parallel using locks
                                                    
                                                     *
                                                    
                                                     *  - 1000 inserts, deletes, and reads in parallel using snapshots
                                                    
                                                     *
                                                    
                                                     *  - Clean up
                                                    
                                                     *
                                                    
                                                     *  Performance numbers are printed out in the following format:
                                                    
                                                     *
                                                    
                                                     *    AVERAGE +/- DEV [MIN, MAX], n: #, total: TOTAL, DESCRIPTION
                                                    
                                                     *
                                                    
                                                     *  Please be aware that the schema does not have any explicit keys.
                                                    
                                                     *  We instead utilize the row-ID where we explicitly assign it a hash
                                                    
                                                     *  of column c2.  However, if we get a collision we increment one to
                                                    
                                                     *  the hash.  This is done by using a mask when we hash.  That mask
                                                    
                                                     *  have space in the least significants bits for duplicates.  We make
                                                    
                                                     *  sure to use a mask that limit it's size for more efficient
                                                    
                                                     *  encoding.
                                                    
                                                     */
                                                    
                                                    #include "sw.h"
                                                    
                                                    #include "rand.h"
                                                    
                                                    #include "hash.h"
                                                    
                                                    #include "thread_api.h"
                                                    
                                                    #include "rdmtfsapi.h"
                                                    
                                                    #include "rdmdbapi.h"
                                                    
                                                    #include "rdmcursorapi.h"
                                                    
                                                    #include "rdmcmdlineapi.h"
                                                    
                                                    #include "rdmstartupapi.h"
                                                    
                                                    #include "cpp50_structs.h"
                                                    
                                                    #include "cpp50_cat.h"
                                                    
                                                    #include <string.h>
                                                    
                                                    #include <stdio.h>
                                                    
                                                    #include <stdlib.h>
                                                    
                                                    using namespace std;
                                                    using namespace RDM_CPP::CPP50;
                                                    uint32_t total_number_of_rows;
                                                    uint32_t rows_per_transaction;
                                                    /* \brief Standard error print macro */
                                                    
                                                    #define print_error(rc) print_errorEx (rc, __FILE__, __LINE__)
                                                    
                                                    /* \brief Standard error print format
                                                    
                                                     *
                                                    
                                                     *  This demonstrates the usage of the rdm_retcodeGetName() and
                                                    
                                                     *  rdm_retcodeGetDescription() functions.
                                                    
                                                     */
                                                    
                                                    
                                                    RDM_RETCODE rc,   /*< [in] RDM_RETCODE to analyze */
                                                    const char *file, /*< [in] Sourcec filename */
                                                    int line          /*< [in] Lineno in source file */
                                                    )
                                                    {
                                                    
                                                        {
                                                            cerr << file << ":" << line << ": error: " <<
                                                    
                                                        }
                                                    }
                                                    /* Hash mask where masked numbers can always be endoded in 5 bytes */
                                                    
                                                    const uint64_t hash_mask = 0X7FFFFFF00ULL;
                                                    /* Number of duplicates allowed.  This is derived from the hash mask */
                                                    
                                                    const uint64_t max_hash_duplicates = ((~hash_mask + 1) & hash_mask);
                                                    /* \brief Generate data
                                                    
                                                     *
                                                    
                                                     * Generate sample data for the purpose of inserting it into the
                                                    
                                                     * database or we can use this for looking up data that have already
                                                    
                                                     * been inserted.  Looking up existing data has to use a pseudo random
                                                    
                                                     * generator that is able to reproduce the original pseudo random
                                                    
                                                     * sequence.
                                                    
                                                     */
                                                    
                                                    static void genData (
                                                        SAMPLE &sample,    /*< [out] The sample to be generated */
                                                    RDM_ROWID_T &hash, /*< [out] The rowId to use for this row unless there is collisions */
                                                    
                                                    )
                                                    {
                                                        sample.c1 = rand.draw (10000, 9999);
                                                    /* Inserts are more efficient if the key values are in order */
                                                    
                                                    for (int j = 0; j < 44; j++)
                                                        {
                                                            sample.c2[j] = rand.draw (33, 126);
                                                        }
                                                        hash = rdm_hash ((uint8_t *) sample.c2, sizeof (sample.c2)) & hash_mask;
                                                        sample.c3 = rand.draw (1000000000, 4200000000);
                                                    }
                                                    /* \brief Compare key values
                                                    
                                                     *
                                                    
                                                     *  Compare the two key values.  Return 0 if they are the same, 1 otherwise.
                                                    
                                                     */
                                                    
                                                    static int cmpData (
                                                        uint8_t data1[44], /*< [in] The first data to be compared */
                                                        uint8_t data2[44]  /*< [in] The second data to be compared */
                                                        )
                                                    {
                                                    return memcmp (data1, data2, 44);
                                                    }
                                                    /* \brief Lookup row
                                                    
                                                     *
                                                    
                                                     *  Lookup a row where we handle hash collision.
                                                    
                                                     *
                                                    
                                                     *  @return Returns sOKAY if the row is found and sNOTFOUND if the row does not exist.
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE lookupRow (RDM_CURSOR cursor, /* [in] The cursor we use to navigate to the row using a row scan */
                                                                                  uint8_t key[44],   /* [in] The key value for the row to be looked up */
                                                    RDM_ROWID_T hash,  /* [in] The hash of the key we want to look up */
                                                                                  SAMPLE *sample     /* [out] The sample date to be returned back to the caller */
                                                        )
                                                    {
                                                    /* Actual hash is always at least one larger than the base hash */
                                                    
                                                    
                                                    
                                                        {
                                                            rc = rdm_cursorMoveToNext (cursor);
                                                        }
                                                    if (rc == sOKAY)
                                                        {
                                                    
                                                    for (uint64_t count = 0; rc == sOKAY && cmpData (sample->c2, key) != 0; count++)
                                                            {
                                                    RDM_ROWID_T currentHash;
                                                    rdm_cursorGetRowId (cursor, ¤tHash);
                                                    if ((currentHash & hash_mask) != hash)
                                                                {
                                                                    rc = sNOTFOUND;
                                                                }
                                                    if (rc == sOKAY)
                                                                {
                                                                    rc = rdm_cursorMoveToNext (cursor);
                                                                }
                                                    if (rc == sOKAY)
                                                                {
                                                                    rc = rdm_cursorReadRow (cursor, sample, sizeof(*sample), NULL);
                                                                }
                                                            }
                                                        }
                                                    
                                                        {
                                                            rc = sNOTFOUND;
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Get the actual hash of a new row
                                                    
                                                     *
                                                    
                                                     *  Get the actual hash of a new row we are about to insert.  If the
                                                    
                                                     *  row already exist we will position the cursor to this row.
                                                    
                                                     *
                                                    
                                                     *  @return Returns sOKAY if the row does not exist and sDUPLICATE if
                                                    
                                                     *  the row already exist. However, if the possible actual hash values
                                                    
                                                     *  is exhausted we will return eNOSPACE.
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE actualHashOfRow (RDM_CURSOR cursor,        /* [in] The cursor we use to navigate to the row using a row scan */
                                                                                        uint8_t key[44],          /* [in] The key value for the row to be looked up */
                                                    RDM_ROWID_T hash,         /* [in] The hash of the key we want to look up */
                                                    RDM_ROWID_T *pActualHash  /* [out] Actual hash to use for an insert */
                                                        )
                                                    {
                                                    RDM_RETCODE rc;
                                                    RDM_ROWID_T actualHashCandidate = hash + 1;
                                                    
                                                        rc = rdm_cursorMoveToRowId (cursor, actualHashCandidate);
                                                    if (rc == sNOTFOUND)
                                                        {
                                                            actualHashCandidateFound = RDM_TRUE;
                                                            rc = rdm_cursorMoveToNext (cursor);
                                                        }
                                                    if (rc == sOKAY)
                                                        {
                                                            SAMPLE sample;
                                                            rc = rdm_cursorReadRow (cursor, &sample, sizeof(sample), NULL);
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = sDUPLICATE;
                                                            }
                                                    while (rc == sDUPLICATE && cmpData (sample.c2, key) != 0)
                                                            {
                                                    RDM_ROWID_T currentHash;
                                                                rc = rdm_cursorGetRowId (cursor, ¤tHash);
                                                    
                                                                {
                                                    if (currentHash > actualHashCandidate)
                                                                    {
                                                                        actualHashCandidateFound = RDM_TRUE;
                                                                    }
                                                                }
                                                    if (rc == sOKAY && ((currentHash & hash_mask) == hash))
                                                                {
                                                                    rc = rdm_cursorMoveToNext (cursor);
                                                    if (actualHashCandidateFound == RDM_FALSE)
                                                                    {
                                                                        actualHashCandidate ++;
                                                                    }
                                                    if (rc == sOKAY)
                                                                    {
                                                                        rc = rdm_cursorReadRow (cursor, &sample, sizeof(sample), NULL);
                                                                    }
                                                    if (rc == sOKAY)
                                                                    {
                                                                        rc = sDUPLICATE;
                                                                    }
                                                                }
                                                    
                                                                {
                                                                    rc = eNOSPACE;
                                                                }
                                                            }
                                                    if (rc == sENDOFCURSOR)
                                                            {
                                                                actualHashCandidateFound = RDM_TRUE;
                                                                rc = sOKAY;
                                                            }
                                                        }
                                                    
                                                        {
                                                            rc = sOKAY;
                                                        }
                                                    if (rc == sOKAY)
                                                        {
                                                            *pActualHash = actualHashCandidate;
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Insert row
                                                    
                                                     *
                                                    
                                                     *  Insert a row where we handle hash collision.
                                                    
                                                     *
                                                    
                                                     *  @return Returns sOKAY for a success insert and sDUPLICATE if the row already exist.
                                                    
                                                     */
                                                    
                                                    
                                                    RDM_CURSOR lookupCursor, /* [in] Temporary cursor to look up for duplicates */
                                                                                  SAMPLE *sample,          /* [in] The sample data to be inserted */
                                                    RDM_ROWID_T hash,        /* [in] The hash of the key we want to look up */
                                                    RDM_CURSOR *pCursor      /* [out] The cursor for newly inserted row we return back to the user. */
                                                        )
                                                    {
                                                    RDM_ROWID_T actualHash;
                                                    RDM_RETCODE rc = actualHashOfRow (lookupCursor, sample->c2, hash, &actualHash);
                                                    if (rc == sOKAY)
                                                        {
                                                    
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Insert or update row
                                                    
                                                     *
                                                    
                                                     *  Insert or update row where we handle hash collision.
                                                    
                                                     *
                                                    
                                                     * @return Returns sOKAY for success
                                                    
                                                     */
                                                    
                                                    
                                                    RDM_CURSOR lookupCursor, /* [in] Cursor will be positioned at the row we inserted or updated */
                                                                                          SAMPLE *sample,          /* [in] The sample data to be inserted */
                                                    RDM_ROWID_T hash         /* [in] The hash of the key we want to look up */
                                                        )
                                                    {
                                                    RDM_ROWID_T actualHash;
                                                    RDM_RETCODE rc = actualHashOfRow (lookupCursor, sample->c2, hash, &actualHash);
                                                    if (rc == sOKAY)
                                                        {
                                                    RDM_CURSOR cursor = NULL;
                                                            rc = rdm_dbReinsertRow (db, TABLE_SAMPLE, actualHash, sample, sizeof (SAMPLE), &cursor);
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = rdm_cursorMoveToPosition (lookupCursor, cursor);
                                                            }
                                                    rdm_cursorFree (cursor);
                                                        }
                                                    
                                                        {
                                                    
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Insert or update row
                                                    
                                                     *
                                                    
                                                     *  Insert or update row where we handle hash collision.
                                                    
                                                     *
                                                    
                                                     * @return Returns sOKAY for success and sNOTFOUND if the row does not exist
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE updateRow (RDM_CURSOR lookupCursor, /* [in] Temporary cursor to look up for duplicates */
                                                                                  SAMPLE *sample,          /* [in] The sample data to be inserted */
                                                    RDM_ROWID_T hash         /* [in] The hash of the key we want to look up */
                                                        )
                                                    {
                                                    RDM_ROWID_T actualHash;
                                                        SAMPLE lookupSample;
                                                    RDM_RETCODE rc = lookupRow (lookupCursor, sample->c2, hash, &lookupSample);
                                                    if (rc == sOKAY)
                                                        {
                                                            rc = rdm_cursorUpdateRow (lookupCursor, sample, sizeof (SAMPLE));
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Delete a row
                                                    
                                                     *
                                                    
                                                     * Delete a row where we handle hash collisions.
                                                    
                                                     *
                                                    
                                                     * @return Returns sOKAY for success and sNOTFOUND if the row does not exist
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE deleteRow (RDM_CURSOR cursor, /* [in] The cursor we use to navigate to the row using a row scan */
                                                                                  uint8_t key[44],   /* [in] The key value for the row to be deleted */
                                                    RDM_ROWID_T hash   /* [in] The hash of the key we want to delete */
                                                        )
                                                    {
                                                        SAMPLE sample;
                                                    RDM_RETCODE rc = lookupRow (cursor, key, hash, &sample);
                                                    if (rc == sOKAY)
                                                        {
                                                            rc = rdm_cursorDeleteRow (cursor);
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Insert data
                                                    
                                                     *
                                                    
                                                     *  Insert data wihout any reporting.
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE insertData (
                                                    RDM_DB db, /*< [in] RDM db handle with the database open */
                                                    RAND &rand /*< [in] The pseudo random number generator to use */
                                                    )
                                                    {
                                                    RDM_CURSOR lookupCursor = NULL;
                                                    
                                                        {
                                                            SAMPLE sample;
                                                    RDM_ROWID_T hash;
                                                            genData (sample, hash, rand);
                                                            rc = insertRow (db, lookupCursor, &sample, hash, NULL);
                                                    if (rc == sDUPLICATE)
                                                            {
                                                    /* Ignore duplicates */
                                                    
                                                                rc = sOKAY;
                                                            }
                                                        }
                                                    rdm_cursorFree (lookupCursor);
                                                    return rc;
                                                    }
                                                    /* \brief Insert all the data
                                                    
                                                     *
                                                    
                                                     *  Inserts the main bulk of the data.  It does this by starting a
                                                    
                                                     *  number of update transactions and for each of these calls
                                                    
                                                     *  insertData().  Performance number are reported for each of its
                                                    
                                                     *  operations.
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE insertAllData (
                                                    RDM_DB db,   /*< [in] RDM db handle with the database open */
                                                    string mode, /*< The durability mode to use. Can be "durable" or "consistent" */
                                                    RAND &rand   /*< [in] The pseudo random number generator to use */
                                                    )
                                                    {
                                                    char sRows_per_transaction[12];
                                                        sprintf (sRows_per_transaction, "%d", rows_per_transaction);
                                                    
                                                    
                                                    SW sws ("Insert data - Start Update");
                                                        {
                                                    RDM_TABLE_ID tables_to_lock[] = {TABLE_SAMPLE};
                                                    RDM_TRANS trans;
                                                            sws.start ();
                                                    
                                                            sws.stop ();
                                                    if (rc == sOKAY)
                                                            {
                                                                swi.start ();
                                                                rc = insertData (db, rand);
                                                    if (rc == sOKAY)
                                                                {
                                                                    swi.stop ();
                                                                    swe.start ();
                                                                    rc = rdm_transEnd (trans);
                                                                    swe.stop ();
                                                                }
                                                    else
                                                    
                                                                {
                                                                    (void) rdm_transEndRollback (trans);
                                                                }
                                                            }
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Read the data
                                                    
                                                     *
                                                    
                                                     *  Read some of the data and report performance numbers.
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE readData (
                                                    RDM_DB db,           /*< [in] RDM db handle with the database open */
                                                    RDM_BOOL_T snapshot, /*< [in] Use a snapshot for the reads */
                                                    RAND &rand           /*< [in] The pseudo random number generator to use */
                                                    )
                                                    {
                                                    RDM_RETCODE rc = sOKAY;
                                                    RDM_CURSOR cursor = NULL;
                                                    RDM_TABLE_ID tables_to_lock[] = {TABLE_SAMPLE};
                                                    RDM_TRANS trans;
                                                    SW swe ("Read data - End");
                                                    SW swr ("Read data - Read 1 row");
                                                    SW sws ("Read data - Start Read");
                                                        {
                                                            sws.start ();
                                                    if (snapshot)
                                                            {
                                                    
                                                            }
                                                    else
                                                    
                                                            {
                                                    
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = rdm_dbGetRows (db, TABLE_SAMPLE, &cursor);
                                                                sws.stop ();
                                                    
                                                                {
                                                                    SAMPLE lookup;
                                                    RDM_ROWID_T hash;
                                                                    genData (lookup, hash, rand);
                                                                    SAMPLE sample;
                                                                    swr.start ();
                                                                    rc = lookupRow (cursor, lookup.c2, hash, &sample);
                                                                    swr.stop ();
                                                                }
                                                    if (rc == sOKAY)
                                                                {
                                                                    swe.start ();
                                                                    rc = rdm_transEnd (trans);
                                                                    swe.stop ();
                                                                }
                                                    else
                                                    
                                                                {
                                                                    (void) rdm_transEnd (trans);
                                                                }
                                                            }
                                                        }
                                                    rdm_cursorFree (cursor);
                                                    return rc;
                                                    }
                                                    /* \brief Read the data where 10% exist
                                                    
                                                     *
                                                    
                                                     *  Read some of the data and report performance numbers.
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE readData9010 (
                                                    RDM_DB db,           /*< [in] RDM db handle with the database open */
                                                    RDM_BOOL_T snapshot, /*< [in] Use a snapshot for the reads */
                                                    RAND &rand90,        /*< [in] The pseudo random number generator to use for data that does not exist */
                                                    RAND &rand10         /*< [in] The pseudo random number generator to use for data that exist */
                                                    )
                                                    {
                                                    RDM_RETCODE rc = sOKAY;
                                                    RDM_CURSOR cursor = NULL;
                                                    RDM_TABLE_ID tables_to_lock[] = {TABLE_SAMPLE};
                                                    RDM_TRANS trans;
                                                    SW swe ("Read data - End");
                                                    SW swr10 ("Read data - Read 1 row that exist");
                                                    SW swr90 ("Read data - Try to read 1 row that does not exist");
                                                    SW sws ("Read data - Start Read");
                                                        {
                                                            sws.start ();
                                                    if (snapshot)
                                                            {
                                                                rc = rdm_dbStartSnapshot (db, tables_to_lock, RDM_LEN (tables_to_lock), &trans);
                                                            }
                                                    else
                                                    
                                                            {
                                                                rc = rdm_dbStartRead (db, tables_to_lock, RDM_LEN (tables_to_lock), &trans);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = rdm_dbGetRows (db, TABLE_SAMPLE, &cursor);
                                                                sws.stop ();
                                                    
                                                                {
                                                                    SAMPLE lookup;
                                                    RDM_ROWID_T hash;
                                                                    genData (lookup, hash, rand);
                                                                    SAMPLE sample;
                                                                    swr.start ();
                                                                    rc = lookupRow (cursor, lookup.c2, hash, &sample);
                                                                    swr.stop ();
                                                                }
                                                                {
                                                                    swe.start ();
                                                                    rc = rdm_transEnd (trans);
                                                                    swe.stop ();
                                                                }
                                                    else
                                                    
                                                                {
                                                                    (void) rdm_transEnd (trans);
                                                                }
                                                            }
                                                        }
                                                    rdm_cursorFree (cursor);
                                                    return rc;
                                                    }
                                                    /* \brief Modify data with inserts
                                                    
                                                     *
                                                    
                                                     *  Update data by inserting some additional rows. Performance number
                                                    
                                                     *  are reported for each of its operations.
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE modifyDataWithInserts (
                                                    RDM_DB db,   /*< [in] RDM db handle with the database open */
                                                    string mode, /*< The durability mode to use. Can be "durable" or "consistent" */
                                                    RAND &rand   /*< [in] The pseudo random number generator to use */
                                                    )
                                                    {
                                                    RDM_TABLE_ID tables_to_lock[] = {TABLE_SAMPLE};
                                                    RDM_TRANS trans;
                                                    
                                                    
                                                    
                                                    RDM_CURSOR lookupCursor = NULL;
                                                    if (rc == sOKAY)
                                                        {
                                                            rc = rdm_dbGetRows (db, TABLE_SAMPLE, &lookupCursor);
                                                        }
                                                        {
                                                            sws.start ();
                                                            rc = rdm_dbStartUpdate (db, tables_to_lock, RDM_LEN (tables_to_lock), NULL, 0, &trans);
                                                            sws.stop ();
                                                    if (rc == sOKAY)
                                                            {
                                                    
                                                                {
                                                                    SAMPLE sample;
                                                    RDM_ROWID_T hash;
                                                                    genData (sample, hash, rand);
                                                                    swi.start ();
                                                                    rc = insertRow (db, lookupCursor, &sample, hash, NULL);
                                                    if (rc == sOKAY)
                                                                    {
                                                                        swi.stop ();
                                                                    }
                                                                }
                                                    if (rc == sOKAY)
                                                                {
                                                                    swe.start ();
                                                                    rc = rdm_transEnd (trans);
                                                                    swe.stop ();
                                                                }
                                                    else
                                                    
                                                                {
                                                                    (void) rdm_transEndRollback (trans);
                                                                }
                                                            }
                                                        }
                                                    rdm_cursorFree (lookupCursor);
                                                    return rc;
                                                    }
                                                    /* \brief Modify data with deletes
                                                    
                                                     *
                                                    
                                                     *  Update data by deleting some rows. Performance number are reported
                                                    
                                                     *  for each of its operations.
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE modifyDataWithDeletes (
                                                    RDM_DB db,     /*< [in] RDM db handle with the database open */
                                                    string mode,   /*< The durability mode to use. Can be "durable" or "consistent" */
                                                    RAND &rand     /*< [in] The pseudo random number generator to use */
                                                    )
                                                    {
                                                    RDM_CURSOR cursor = NULL;
                                                    RDM_TABLE_ID tables_to_lock[] = {TABLE_SAMPLE};
                                                    RDM_TRANS trans;
                                                    
                                                    
                                                    
                                                        {
                                                            sws.start ();
                                                            rc = rdm_dbStartUpdate (db, tables_to_lock, RDM_LEN (tables_to_lock), NULL, 0, &trans);
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = rdm_dbGetRows (db, TABLE_SAMPLE, &cursor);
                                                                sws.stop ();
                                                    
                                                                {
                                                                    SAMPLE lookup;
                                                    RDM_ROWID_T hash;
                                                                    genData (lookup, hash, rand);
                                                                    swi.start ();
                                                                    rc = deleteRow (cursor, lookup.c2, hash);
                                                                    swi.stop ();
                                                                }
                                                    if (rc == sOKAY)
                                                                {
                                                                    swe.start ();
                                                                    rc = rdm_transEnd (trans);
                                                                    swe.stop ();
                                                                }
                                                    else
                                                    
                                                                {
                                                                    (void) rdm_transEndRollback (trans);
                                                                }
                                                            }
                                                        }
                                                    rdm_cursorFree (cursor);
                                                    return rc;
                                                    }
                                                    /* \brief Modify data with updates of existing rows
                                                    
                                                     *
                                                    
                                                     *  Update data by updating some rows. Performance number are reported
                                                    
                                                     *  for each of its operations.
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE modifyDataWithUpdates (
                                                    RDM_DB db,     /*< [in] RDM db handle with the database open */
                                                    string mode,   /*< The durability mode to use. Can be "durable" or "consistent" */
                                                    RAND &rand     /*< [in] The pseudo random number generator to use */
                                                    )
                                                    {
                                                    RDM_CURSOR cursor = NULL;
                                                    RDM_TABLE_ID tables_to_lock[] = {TABLE_SAMPLE};
                                                    RDM_TRANS trans;
                                                    
                                                    
                                                    
                                                        {
                                                            sws.start ();
                                                            rc = rdm_dbStartUpdate (db, tables_to_lock, RDM_LEN (tables_to_lock), NULL, 0, &trans);
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = rdm_dbGetRows (db, TABLE_SAMPLE, &cursor);
                                                                sws.stop ();
                                                    
                                                                {
                                                                    SAMPLE sample;
                                                    RDM_ROWID_T hash;
                                                                    genData (sample, hash, rand);
                                                                    sample.c3 = sample.c3 / 1000000;
                                                                    swi.start ();
                                                                    rc = updateRow (cursor, &sample, hash);
                                                                    swi.stop ();
                                                                }
                                                    if (rc == sOKAY)
                                                                {
                                                                    swe.start ();
                                                                    rc = rdm_transEnd (trans);
                                                                    swe.stop ();
                                                                }
                                                    else
                                                    
                                                                {
                                                                    (void) rdm_transEndRollback (trans);
                                                                }
                                                            }
                                                        }
                                                    rdm_cursorFree (cursor);
                                                    return rc;
                                                    }
                                                    /* \brief Context for the thread's entry point
                                                    
                                                     *
                                                    
                                                     *  The thread is passed an instance of this to its entry point.
                                                    
                                                     */
                                                    
                                                    typedef struct
                                                    {
                                                    RDM_TFS tfs;         /*< The TFS handle to use for allocating a DB handle */
                                                    RDM_BOOL_T snapshot; /*< Use a snapshot for the reads */
                                                    } THREAD_CTX;
                                                    /* \brief Read the data from a different thread
                                                    
                                                     *
                                                    
                                                     *  Read some of the data and report performance numbers.  This is the
                                                    
                                                     *  thread entry point for this operation.
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    {
                                                        THREAD_CTX *threadCtx = (THREAD_CTX *) ctx;
                                                    RDM_DB db;
                                                    
                                                    RAND randMyClone;
                                                    if (rc == sOKAY)
                                                        {
                                                    
                                                    if (rc == sOKAY)
                                                            {
                                                    
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = readData (db, threadCtx->snapshot, randMyClone);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = rdm_dbFree (db);
                                                            }
                                                    else
                                                    
                                                            {
                                                    rdm_dbFree (db);
                                                            }
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Modify data and lookups in parallel
                                                    
                                                     *
                                                    
                                                     *  Update data while at the same time lookup some data from a
                                                    
                                                     *  different thread. Performance number are reported for each of its
                                                    
                                                     *  operations.
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE modifyDataAndLookupsInParallel (
                                                    RDM_TFS tfs,         /*< [in] The TFS handle to use for allocating a DB handle */
                                                    RDM_DB db,           /*< [in] RDM db handle with the database open */
                                                    string mode,         /*< The durability mode to use. Can be "durable" or "consistent" */
                                                    RDM_BOOL_T snapshot, /*< [in] Use a snapshot for the reads */
                                                    RAND &rand,          /*< [in] The pseudo random number generator to use */
                                                    RAND &randClone      /*< [in] A clone of the original pseudo random number generator  */
                                                    )
                                                    {
                                                    RDM_RETCODE rc;
                                                        psp_thread_t thread;
                                                        THREAD_CTX threadCtx = {tfs, snapshot};
                                                    if (snapshot)
                                                        {
                                                            cout << "Updates and reads in parallel with snapshot:" << endl;
                                                        }
                                                    else
                                                    
                                                        {
                                                            cout << "Updates and reads in parallel with read locks:" << endl;
                                                        }
                                                    if (rc == sOKAY)
                                                        {
                                                            rc = modifyDataWithInserts (db, mode, rand);
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = modifyDataWithDeletes (db, mode, randClone);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = psp_threadJoin (&thread);
                                                            }
                                                    else
                                                    
                                                            {
                                                    psp_threadJoin (&thread);
                                                            }
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Open and delete rows
                                                    
                                                     *
                                                    
                                                     *  Open or create database and delete all rows from the database
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE openDatabase (
                                                    RDM_DB db /*< [in] RDM db handle with the database open */
                                                    )
                                                    {
                                                    
                                                    print_error (rc);
                                                    if (rc == sOKAY)
                                                        {
                                                    
                                                        }
                                                    if (rc == sOKAY)
                                                        {
                                                    
                                                        }
                                                    if (rc == sOKAY)
                                                        {
                                                    
                                                        }
                                                    if (rc == sOKAY)
                                                        {
                                                    
                                                        }
                                                    if (rc == sOKAY)
                                                        {
                                                            rc = rdm_dbSetCatalog (db, cpp50_cat);
                                                        }
                                                    if (rc == sOKAY)
                                                        {
                                                    
                                                    print_error (rc);
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Cleanup
                                                    
                                                     *
                                                    
                                                     *  Cleanup by dropping the database.
                                                    
                                                     */
                                                    
                                                    
                                                    )
                                                    {
                                                    
                                                    }
                                                    /* \brief Do the DB operations
                                                    
                                                     *
                                                    
                                                     *  This function sets up a database handle, calls openDatabase()
                                                    
                                                     *  to set up the database to use for this example, calls variouse
                                                    
                                                     *  other functions to do the main part of this performance example.
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    static RDM_RETCODE doDBOperations (
                                                    RDM_TFS tfs  /*< [in] The TFS handle to use for allocating a DB handle */
                                                    )
                                                    {
                                                    RDM_DB db;
                                                        cleanup (tfs);
                                                    RDM_RETCODE rc = rdm_tfsAllocDatabase (tfs, &db);
                                                    print_error (rc);
                                                    if (rc == sOKAY)
                                                        {
                                                    const char *consistent = "consistent";
                                                    const char *durable = "durable";
                                                    RAND rand;
                                                    RAND randClone;
                                                            cout << "All operations from a single thread:" << endl;
                                                            rc = openDatabase (db);
                                                    print_error (rc);
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = insertAllData (db, consistent, rand);
                                                    print_error (rc);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = readData (db, RDM_FALSE, randClone);
                                                    print_error (rc);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = readData9010 (db, RDM_FALSE, rand, randClone);
                                                    print_error (rc);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = modifyDataWithInserts (db, consistent, rand);
                                                    print_error (rc);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = modifyDataWithDeletes (db, consistent, randClone);
                                                    print_error (rc);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = modifyDataWithUpdates (db, consistent, randClone);
                                                    print_error (rc);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = modifyDataWithInserts (db, durable, rand);
                                                    print_error (rc);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = modifyDataWithDeletes (db, durable, randClone);
                                                    print_error (rc);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = modifyDataWithUpdates (db, durable, randClone);
                                                    print_error (rc);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = modifyDataAndLookupsInParallel (tfs, db, consistent, RDM_FALSE, rand, randClone);
                                                    print_error (rc);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = modifyDataAndLookupsInParallel (tfs, db, consistent, RDM_TRUE, rand, randClone);
                                                    print_error (rc);
                                                            }
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = rdm_dbFree (db);
                                                    print_error (rc);
                                                            }
                                                    else
                                                    
                                                            {
                                                    rdm_dbFree (db);
                                                            }
                                                        }
                                                    return rc;
                                                    }
                                                    /* Setup TFS and do the DB operations
                                                    
                                                     *
                                                    
                                                     *  This function sets up the Transactional File Server (TFS) and
                                                    
                                                     *  calls doDBOperations() to do the database operations.
                                                    
                                                     *
                                                    
                                                     *  @return Returns an \c RDM_RETCODE code (\b sOKAY if successful)
                                                    
                                                     */
                                                    
                                                    {
                                                    #define MEGA_SIZE 0X100000
                                                    
                                                    #define MEM_SIZE (35 * MEGA_SIZE)
                                                    
                                                    
                                                    RDM_TFS tfs;
                                                    
                                                    print_error (rc);
                                                    if (rc == sOKAY)
                                                        {
                                                            rc = rdm_tfsInitialize (tfs);
                                                    print_error (rc);
                                                    if (rc == sOKAY)
                                                            {
                                                                rc = doDBOperations (tfs);
                                                            }
                                                    size_t maxMemUsage;
                                                    rdm_tfsGetMemUsage (tfs, NULL, &maxMemUsage);
                                                            cout << fixed << setprecision(1);
                                                            cout << "Maximum memory usage: " << (double) maxMemUsage / MEGA_SIZE + 1 << "M" << endl;
                                                    rdm_tfsFree (tfs);
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Parse the command line
                                                    
                                                     *
                                                    
                                                     * Parse the command line and set the global variables rows_per_transaction and
                                                    
                                                     * total_number_of_rows
                                                    
                                                     */
                                                    
                                                    {
                                                    RDM_CMDLINE cmd;
                                                    
                                                            {"t", "trans-size", "i=#", "Number of rows to insert/update/delete in each transaction"},
                                                            {"r", "rows", "i=#", "Total number of rows to insert initially.  This number will be rounded up to the transaction size and at least 10 times the transaction size"},
                                                            {NULL, NULL, NULL, NULL}
                                                        };
                                                    print_error (rc);
                                                    if (rc == sOKAY)
                                                        {
                                                    const char *optarg;
                                                    char opt;
                                                            total_number_of_rows = 100000;
                                                            rows_per_transaction = 1000;
                                                            {
                                                    switch (opt)
                                                                {
                                                    case 't':
                                                                        rows_per_transaction = atoi (optarg);
                                                    break;
                                                    case 'r':
                                                                        total_number_of_rows = atoi (optarg);
                                                    break;
                                                                }
                                                            }
                                                    if (total_number_of_rows < rows_per_transaction * 10)
                                                            {
                                                                total_number_of_rows = rows_per_transaction * 10;
                                                            }
                                                        }
                                                    return rc;
                                                    }
                                                    /* \brief Main function for a simple performance example
                                                    
                                                     *
                                                    
                                                     *  This function does the command line parsing and calls
                                                    
                                                     *  setupTFSAndDoDBOperations() to do the rest of this example.
                                                    
                                                     *
                                                    
                                                     *  @return Returns 0 on success and 1 on failure.
                                                    
                                                     */
                                                    
                                                    int main_cpp50 (int argc, const char *const *argv)
                                                    {
                                                    RDM_RETCODE rc = parseCommandLine (argc, argv);
                                                    if (rc == sOKAY)
                                                        {
                                                            rc = setupTFSAndDoDBOperations ();
                                                        }
                                                    return rc == sOKAY ? 0 : 1;
                                                    }
                                                    RDM_STARTUP_EXAMPLE (cpp50)
                                                Header for command line parsing API.
                                        Definition: cpp50Example/rand.h:29
                                        const char * rdm_retcodeGetName(RDM_RETCODE retcode)
                                            Get the mnemonic name for an error or status code.
                                        Header for the RDM Cursor APIs.
                                        RDM_RETCODE rdm_rdmAllocTFSWithMemBuf(void *pMemBuf, size_t memSize, RDM_TFS *phTFS)
                                            Allocate a TFS handle with an associated memory buffer.
                                        RDM_RETCODE rdm_tfsGetMemUsage(RDM_TFS tfs, size_t *curr_usage, size_t *max_usage)
                                            Get memory usage associated with the TFS.
                                        RDM_RETCODE rdm_transEndRollback(RDM_TRANS trans)
                                            End a transactional operation with a rollback.
                                        RDM_RETCODE rdm_dbStartRead(RDM_DB db, const RDM_TABLE_ID *tableIds, uint32_t numTableIds, RDM_TRANS *pTrans)
                                            Get read locks.
                                        RDM_RETCODE rdm_cursorReadRow(RDM_CURSOR cursor, void *colValues, size_t bytesIn, size_t *bytesOut)
                                            Read all columns from a row.
                                        RDM_RETCODE rdm_dbReinsertRow(RDM_DB db, RDM_TABLE_ID tableId, RDM_ROWID_T rowId, const void *colValues, size_t bytesIn, RDM_CURSOR *pCursor)
                                            Insert a new row into a table.
                                        The buffer used by the command line parser to hold state information.
                                            Definition: rdmcmdlinetypes.h:85
                                        RDM_RETCODE rdm_dbSetCatalog(RDM_DB db, const char *catalog)
                                            Associate a catalog with an allocated database.
                                        RDM_RETCODE rdm_dbOpen(RDM_DB db, const char *dbNameSpec, RDM_OPEN_MODE mode)
                                            Open an existing RDM database using the specified database handle.
                                        RDM_RETCODE rdm_dbSetOption(RDM_DB db, const char *keyword, const char *strValue)
                                            Set a single RDM option from a string.
                                        RDM_RETCODE rdm_tfsAllocDatabase(RDM_TFS tfs, RDM_DB *pDb)
                                            Allocate memory for a new RDM db.
                                        RDM_EXPORT RDM_RETCODE psp_threadJoin(PSP_THREAD_PTR_T)
                                        Header for the Transactional File Server (TFS) API.
                                        RDM_EXPORT RDM_RETCODE psp_threadBegin(PSP_THREAD_PTR_T pThread, PSP_THREAD_FCN fcn, uint32_t stacksize, void *arg, int32_t priority, const char *name)
                                        RDM_RETCODE rdm_dbStartSnapshot(RDM_DB db, const RDM_TABLE_ID *tableIds, uint32_t numTableIds, RDM_TRANS *pTrans)
                                            Start a snapshot.
                                        RDM_RETCODE rdm_dbGetRows(RDM_DB db, RDM_TABLE_ID tableId, RDM_CURSOR *pCursor)
                                            Associate an RDM_CURSOR with rows based on a table id.
                                        const char * rdm_retcodeGetDescription(RDM_RETCODE retcode)
                                            Invoke RDM error handler.
                                        Definition: cpp50Example/sw.h:35
                                        RDM_RETCODE rdm_tfsDropDatabase(RDM_TFS tfs, const char *dbNameSpec)
                                            Drop the specified database.
                                        RDM_RETCODE rdm_cmdlineInit(RDM_CMDLINE *cmd, int32_t argc, const char *const argv[], const char *description, const RDM_CMDLINE_OPT *opts)
                                            Initialize an RDM_CMDLINE buffer and validate the command line.
                                        RDM_RETCODE rdm_cursorUpdateRow(RDM_CURSOR cursor, const void *colValues, size_t bytesIn)
                                            Update all columns in a row.
                                        Header for the RDM Database APIs.
                                        void print_errorEx(int rc, const char *file, int line)
                                        char rdm_cmdlineNextShortOption(RDM_CMDLINE *cmd, const char **arg)
                                            Get next option or argument.
                                        RDM_RETCODE rdm_dbStartUpdate(RDM_DB db, const RDM_TABLE_ID *writeTableIds, uint32_t numWriteTableIds, const RDM_TABLE_ID *readTableIds, uint32_t numReadTableIds, RDM_TRANS *pTrans)
                                            Get write locks.
                                        Internal RDM Startup API used by startup macros.
                                        RDM_RETCODE rdm_cursorGetRowId(RDM_CURSOR cursor, RDM_ROWID_T *rowid)
                                            Get the rowid for the current row of the cursor.