c-core/30_core/core30Example_main.c
/*
 * Raima Database Manager
 *
 * Copyright (c) 2019 Raima Inc.,  All rights reserved.
 *
 * Use of this software, whether in source code format, or in executable,
 * binary object code form, is governed by the Raima LICENSE which
 * is fully described in the LICENSE.TXT file, included within this
 * distribution of files.
 */
 
#include <stdio.h>
#include <stdlib.h>
#include "example_fcns.h"
#include "rdm.h"
#include "rdmstartupapi.h"
 
/* Generated \c struct and \c typedef definitions to be used with the RDM APIs
 */
#include "core30_structs.h"
 
/* Generated catalog definition to be used with the RDM rdm_dbSetCatalog() API
 */
#include "core30_cat.h"
 
#define RAMPUPTIME 15
#define TPS 5
#define NUM_BRANCHES 1
#define NUM_TELLERS 10
#define NUM_ACCOUNTS 100000L
#define STEADYSTATE 60
 
const char *const description = "Performance Test using TPC-B test "
                                "specifications. Compares durability settings.";
const RDM_CMDLINE_OPT opts[] = {{NULL, NULL, NULL, NULL}};
 
RDM_RETCODE populateDatabase (
    RDM_DB hDB) 
{
    RDM_RETCODE rc;
    perfTimer_t timer;
    BRANCHES brnRec;
 
    rdm_dbSetOption (hDB, "durability""consistent");
 
    printf ("Populate database with %d TPS configuration:\t", TPS);
    timeMeasureBegin (&timer);
 
    for (brnRec.bid = 0; brnRec.bid < TPS; brnRec.bid++)
    {
        int ii;
 
        rc = rdm_dbStartUpdate (hDB, RDM_LOCK_ALL, 0, NULL, 0, NULL);
        print_error (rc);
        if (rc == sOKAY)
        {
            brnRec.bbalance = 0.0;
            brnRec._filler_has_value = RDM_FALSE;
            rc = rdm_dbInsertRow (
                hDB, TABLE_BRANCHES, &brnRec, sizeof (brnRec), NULL);
            print_error (rc);
 
            /* insert associated Tellers */
            for (ii = 0; rc == sOKAY && ii < NUM_TELLERS; ii++)
            {
                TELLERS telRec;
                telRec.bid = brnRec.bid;
                telRec.tbalance = 0.0;
                telRec.tid = (NUM_TELLERS * brnRec.bid) + ii;
                telRec._filler_has_value = RDM_FALSE;
                rc = rdm_dbInsertRow (
                    hDB, TABLE_TELLERS, &telRec, sizeof (telRec), NULL);
                print_error (rc);
            }
 
            /* insert associated Accounts */
            for (ii = 0; rc == sOKAY && ii < NUM_ACCOUNTS; ii++)
            {
                ACCOUNTS accRec;
                accRec.bid = brnRec.bid;
                accRec.abalance = 0.0;
                accRec.aid = (NUM_ACCOUNTS * brnRec.bid) + ii;
                accRec._filler_has_value = RDM_FALSE;
                rc = rdm_dbInsertRow (
                    hDB, TABLE_ACCOUNTS, &accRec, sizeof (accRec), NULL);
                print_error (rc);
            }
            rdm_dbEnd (hDB);
        }
    }
 
    timeMeasureEnd (&timer);
    printf ("%u milliseconds\n", timeMeasureDiff (&timer));
    return rc;
}
 
RDM_RETCODE do_trans (
    RDM_DB hDB, 
    unsigned int *elapsedTime)
{
    RDM_RETCODE rc;
    perfTimer_t timer;
 
    double bal;
    RDM_TRANS hTrans;
    RDM_CURSOR cursor = NULL;
    RDM_CURSOR brnCursor = NULL;
    HISTORY historyRow;
    TELLERS_TELLERS_PK_KEY tellerKey;
    ACCOUNTS_ACCOUNTS_PK_KEY acctKey;
 
    /* Selct Delta value in the range of +/- 999999 */
    historyRow.delta = (double) (rand () / (65536.0 * 65536.0));
 
    historyRow.tid = (int) ((rand () % (TPS * NUM_TELLERS)));
 
    historyRow.bid = historyRow.tid / NUM_TELLERS;
 
    historyRow.aid = (unsigned int) rand () % NUM_ACCOUNTS;
 
    rdm_timestampNow (0, &historyRow.tim);
 
    timeMeasureBegin (&timer);
 
    do
    {
        rc = rdm_dbStartUpdate (hDB, RDM_LOCK_ALL, 0, NULL, 0, &hTrans);
    } while (rc == eUNAVAIL);
    print_error (rc);
 
    /* Update Account where Account_ID = Aid: */
    acctKey.aid = historyRow.aid;
    rc = rdm_dbGetRowsByKeyAtKey (
        hDB, COL_ACCOUNTS_AID, &acctKey, sizeof (acctKey), &cursor);
    print_error (rc);
    rc = rdm_cursorReadColumn (
        cursor, COL_ACCOUNTS_ABALANCE, &bal, sizeof (bal), NULL);
    print_error (rc);
    bal += historyRow.delta;
    rc = rdm_cursorUpdateColumn (
        cursor, COL_ACCOUNTS_ABALANCE, &bal, sizeof (bal));
    print_error (rc);
 
    /* Write to History */
    rc = rdm_dbInsertRow (
        hDB, TABLE_HISTORY, &historyRow, sizeof (historyRow), NULL);
    print_error (rc);
 
    /* Update Teller where Teller_ID = Tid */
    tellerKey.tid = historyRow.tid;
    rc = rdm_dbGetRowsByKeyAtKey (
        hDB, COL_TELLERS_TID, &tellerKey, sizeof (tellerKey), &cursor);
    print_error (rc);
    rc = rdm_cursorReadColumn (
        cursor, COL_TELLERS_TBALANCE, &bal, sizeof (bal), NULL);
    print_error (rc);
    bal += historyRow.delta;
    rc = rdm_cursorUpdateColumn (
        cursor, COL_TELLERS_TBALANCE, &bal, sizeof (bal));
    print_error (rc);
 
    /* Update Branch where Branch_ID = Bid: */
    rc = rdm_cursorGetOwnerRow (cursor, REF_TELLERS_FK, &brnCursor);
    print_error (rc);
    rc = rdm_cursorReadColumn (
        brnCursor, COL_BRANCHES_BBALANCE, &bal, sizeof (bal), NULL);
    print_error (rc);
    bal += historyRow.delta;
    rc = rdm_cursorUpdateColumn (
        brnCursor, COL_BRANCHES_BBALANCE, &bal, sizeof (bal));
    print_error (rc);
 
    rc = rdm_transEnd (hTrans);
    print_error (rc);
 
    timeMeasureEnd (&timer);
 
    if (cursor)
        rdm_cursorFree (cursor);
    if (brnCursor)
        rdm_cursorFree (brnCursor);
 
    if (elapsedTime)
        *elapsedTime = timeMeasureDiff (&timer);
 
    return rc;
}
 
int main_core30 (int argc, const char *const *argv)
{
    RDM_DB hDB;
    RDM_TFS hTFS;
    RDM_RETCODE rc;
 
    srand (100);
 
    rc = rdm_cmdlineInit (&cmd, argc, argv, description, opts);
    if (rc != sCMD_USAGE)
        print_error (rc);
 
    if (rc == sOKAY)
    {
        /* Initialize the TFS, task, and open/initialize the database */
        rc = exampleOpenEmptyDatabase (&hTFS, &hDB, "core30", core30_cat);
        if (rc == sOKAY)
        {
            rc = populateDatabase (hDB);
            if (rc == sOKAY)
            {
                perfTimer_t timer;
                int ii;
 
                /* RAMP-UP transactions */
                printf ("Perform RAMP-UP for %d seconds\n", RAMPUPTIME);
                timeMeasureBegin (&timer);
                while (rc == sOKAY)
                {
                    timeMeasureEnd (&timer);
                    if (timeMeasureDiff (&timer) > (RAMPUPTIME * 1000))
                        break;
                    rc = do_trans (hDB, NULL);
                }
 
                /* Run through the durability settings */
                for (ii = 0; ii < 3; ii++)
                {
                    const char *durability[3] = {"durability=durable",
                                                 "durability=consistent",
                                                 "durability=unsafe"};
 
                    rc = rdm_dbSetOptions (hDB, durability[ii]);
                    print_error (rc);
 
                    unsigned int minTrans = (unsigned int) -1;
                    unsigned int maxTrans = 0;
                    unsigned int numTrans = 0;
                    unsigned int totTrans = 0;
                    unsigned int thisTrans;
 
                    /* TPC-B measurement */
                    printf (
                        "\nPerform TPC-B test for %d seconds (%s)\n",
                        STEADYSTATE, durability[ii]);
 
                    timeMeasureBegin (&timer);
                    while (rc == sOKAY)
                    {
                        timeMeasureEnd (&timer);
                        if (timeMeasureDiff (&timer) > (STEADYSTATE * 1000))
                            break;
 
                        rc = do_trans (hDB, &thisTrans);
 
                        /* update the statistics */
                        minTrans = RDM_MIN (minTrans, thisTrans);
                        maxTrans = RDM_MAX (maxTrans, thisTrans);
                        totTrans += thisTrans;
                        numTrans++;
                    }
                    /* prevent divide by 0 incase totTrans is 0 */
                    if (totTrans != 0)
                    {
                        printf (
                            "Steady state results: %.2f TPS-B\n\n",
                            (double) numTrans / (double) totTrans * 1000.0);
                    }
 
                    printf (
                        "\tMinimum transaction time: %u milliseconds\n",
                        minTrans);
                    printf (
                        "\tMaximum transaction time: %u milliseconds\n",
                        maxTrans);
                    printf (
                        "\tTotal number of transactions measured: %u\n",
                        numTrans);
                }
            }
 
            exampleCleanup (hTFS, hDB);
        }
    }
    return (int) rc;
}
 
RDM_RETCODE rdm_transEnd(RDM_TRANS trans)
End a transactional operation.
RDM_RETCODE rdm_dbSetOptions(RDM_DB db, const char *optString)
Set RDM options.
Header for the native RDM Runtime API.
@ RDM_FALSE
Definition: psptypes.h:59
#define RDM_MAX(a, b)
Definition: psptypes.h:83
RDM_RETCODE rdm_dbEnd(RDM_DB db)
End a transactional operation.
@ sCMD_USAGE
Definition: rdmretcodetypes.h:71
RDM_RETCODE rdm_timestampNow(int16_t time_zone, RDM_PACKED_TIMESTAMP_T *ts)
Get the current local timestamp.
struct RDM_CURSOR_S * RDM_CURSOR
Definition: rdmtypes.h:304
@ eUNAVAIL
Definition: rdmretcodetypes.h:191
The buffer used by the command line parser to hold state information.
Definition: rdmcmdlinetypes.h:85
#define RDM_MIN(a, b)
Definition: psptypes.h:81
RDM_RETCODE rdm_cursorUpdateColumn(RDM_CURSOR cursor, RDM_COLUMN_ID columnId, const void *columnValue, size_t bytesIn)
Update a single column in a row.
@ sOKAY
Definition: rdmretcodetypes.h:95
RDM_RETCODE rdm_dbGetRowsByKeyAtKey(RDM_DB db, RDM_KEY_ID keyId, const void *keyValue, size_t len, RDM_CURSOR *pCursor)
Associate an RDM_CURSOR with a row set that is ordered by key value and is initially positioned at th...
struct RDM_TRANS_S * RDM_TRANS
Definition: rdmtypes.h:305
Generic usage function option record.
Definition: rdmcmdlinetypes.h:32
RDM_RETCODE rdm_cursorFree(RDM_CURSOR cursor)
Free an RDM_CURSOR.
RDM_RETCODE rdm_dbSetOption(RDM_DB db, const char *keyword, const char *strValue)
Set a single RDM option from a string.
#define RDM_STARTUP_EXAMPLE(name)
Definition: rdmstartuptypes.h:73
RDM_RETCODE rdm_dbInsertRow(RDM_DB db, RDM_TABLE_ID tableId, const void *colValues, size_t bytesIn, RDM_CURSOR *pCursor)
Insert a new row into a table at the specified rowId.
RDM_RETCODE rdm_cursorReadColumn(RDM_CURSOR cursor, RDM_COLUMN_ID columnId, void *columnValue, size_t bytesIn, size_t *bytesOut)
Read a single column from a table row.
struct RDM_TFS_S * RDM_TFS
RDM TFS Handle.
Definition: rdmtfstypes.h:21
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.
struct RDM_DB_S * RDM_DB
Definition: rdmtypes.h:303
RDM_RETCODE rdm_cursorGetOwnerRow(RDM_CURSOR memberCursor, RDM_REF_ID refId, RDM_CURSOR *pCursor)
Associate an RDM_CURSOR with a set owner.
#define RDM_LOCK_ALL
Definition: rdmtypes.h:170
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 status and error return codes.
Definition: rdmretcodetypes.h:43