Generating Timestamp Data

generateEspressoRecords.c

This program takes these command line arguments:

  1. Store Id of the coffee store the machine belongs to
  2. The model number of the coffee machine
  3. The percentage that an coffee machine shot fails
  4. The number of shots (on average) the coffee machine makes per hour
  5. The deviation between the shot rate
  6. The clean rate of the machine (in fractions of an hour)

The clean rate determines the amount of time it takes for a coffee machine to start a clean cycle in fractions of an hour. So 0.2 means 0.2 * 60 = 12. This means there will be roughly 12 minutes between the clean cycles on a coffee machine.

To begin, a Timeseries is created and inserted into GridDB
GSTimeseries* coffeeMachine = makeEspressoMachine(gridstore, argv[2]);

// Setup Timestamp Column Schema
columnInfo.name = "timestamp"; // Timestamp column
columnInfo.type = GS_TYPE_TIMESTAMP;
….
columnInfo.name = "event_type"; 
// An espresso shot is classified 3 ways: as a SUCCESS, as a FAILURE, or CLEAN cycle 
columnInfo.type = GS_TYPE_INTEGER;
….
columnInfo.name = "temperature"; // Water temperature of the espresso shot
columnInfo.type = GS_TYPE_FLOAT;
….
columnInfo.name = "pressure"; // Water pressure of the current espresso shot
columnInfo.type = GS_TYPE_FLOAT;
….
containerInfo.type = GS_CONTAINER_TIME_SERIES; 

The schema creation and insertion into GridDB is similar to the other containers in Container creation.
The coffee store container that belongs to will also need to be fetched as well. This will be used for updating the cycle counts.
gsGetCollectionGeneral(gridstore,argv[1],&coffeeStore);

From there the machine setting arguments are retrieved and parsed and an infinite cycle espresso cycle begins.

espressoCycle(coffeeMachine,coffeeStore,argv[2],shotsPerHour,standard_deviation, \
DEFAULT_TEMPERATURE,DEFAULT_PRESSURE,failure_rate,clean_rate);
srand((unsigned) time(&timer));
direction = rand();
	pressure_direction = rand();
	offset = rand() % (MAX_OFFSET + 1);
	pressure_offset = (float) (rand() % (PRESSURE_OFFSET + 1)) / 100.0; 
	
if (direction % 2 == 1)
			offset = offset * -1;
	
if (pressure_direction % 2 == 1)
			pressure_offset = pressure_offset * -1.0;
	pressure = average_pressure + pressure_offset;
	temperature = average_temperature + offset;
	
if(currentCycle % secondsToCleanCycle == 0 && currentCycle > 0)
		makeEspressoRecord(basetime,espressoMachine,coffeeStore, \
		serial_num,temperature,pressure,failure_rate,seed,true); 
	
else
		makeEspressoRecord(basetime,espressoMachine,coffeeStore, \ 
		serial_num,temperature,pressure,failure_rate,seed,false); 
	
basetime = gsAddTime(basetime,secondsPerShot, GS_TIME_UNIT_SECOND);
seed += secondsPerShot;
currentCycle++; // Move to next cycle
	
newShotRate = (int) adjustedShotsperHour(shotRate,standard_deviation, seed);
secondsPerShot = calculateSecondsPerShot(newShotRate,standard_deviation, \
seed);
	
sleep(secondsPerShot); // Wait the waiting time between shots 

The shot rate determine the relative wait time in seconds between an espresso shot, as seen with the sleep function use. The clean rate determines the amount of seconds between clean cycles. The makeEspressoRecord function which makes timestamp record marked with the current time. This functions generates random data to insert as timestamp records GridDB. The temperature and pressure use random number generators to determine a random number to determine how much to offset a temperature (positive or negative) by a set constant mean. The method for determining the amount of seconds between shots is the same as in preload.c

float recorded_temperature = (float) gaussian_number(average_temperature,SIGMA,seed); 
float recorded_pressure = (float) \ gaussian_number(average_pressure,PRESSURE_SIGMA,seed);
int eventState; // Determine which cycle the current cycle

if(isCleanCycle)
	eventState = CLEAN; 
else 
	eventState = determineEspressoSuccess(failure_rate,seed); 
….
gsSetRowFieldByTimestamp(espressoShotRecord,0,timestamp); // Set the timestamp
gsSetRowFieldByInteger(espressoShotRecord,1,eventState); // Set the eventType
gsSetRowFieldByFloat(espressoShotRecord,2,recorded_temperature); 
gsSetRowFieldByFloat(espressoShotRecord,3,recorded_pressure); 

gsPutRow(espressoMachine,NULL,espressoShotRecord,NULL); // Insert row into TimeSeries
gsCloseRow(&espressoShotRecord); 

updateMachineCycles(coffeeStore,serialNumber,isCleanCycle);

The record generation begins by generating a random temperature and a random pressure using the gsl library and if it is not time for a clean cycle, using a another random call to determine if the espresso shot was a successful shot or a failure. From there all the row fields can be set and the row is inserted into GridDB. Also since a shot has been made the coffee machine record in the coffee store must be updated as well.

gsGetRowFieldAsInteger(machineRecord,3,&new_cycles); 
gsGetRowFieldAsInteger(machineRecord,4,&clean_cycles); 

gsSetRowFieldByInteger(machineRecord,3,++new_cycles); 

if(resetCleanCycle) // If the last cycle was a clean cycle
	gsSetRowFieldByInteger(machineRecord,4,0); // Reset clean cycle count to zero
else
	gsSetRowFieldByInteger(machineRecord,4,++clean_cycles); // Update clean cycles 

gsPutRow(coffeeStore,NULL,machineRecord,NULL); // Update row

This method uses the serial number of the coffee machine as the row key. From there row’s can be fetched by there row key’s a string-type in gsGetRowByString. The new and clean cycles can be fetched and set by incrementing them. Once those row fields are set the new and updated row can be put back into GridDB with gsPutRow.

preloadRecords.c

This programs takes the same command line arguments as generateEspressoRecords.c with addition to one more argument: days to preload.

Days to preload determines how many days before the current time the program will generate records for. If you specify five days, with the machine settings that were provided, the program will generate 5 days worth of records for a coffee machine and insert them all into GridDB.
The records are generated the same way with the makeEspressoRecord function with the exception of the timestamp recording being a time in the past rather than a current time.

GSTimestamp timeToInsert = gsAddTime(gsCurrentTime(),-1 * days, GS_TIME_UNIT_DAY);
GSTimestamp timeToStopAt = gsCurrentTime();

while(timeToInsert < timeToStopAt){
	if(currentSeconds % secondsToCleanCycle == 0 && currentSeconds > 0)
		makeEspressoRecord(timeToInsert,espressoMachine,coffeeStore,serial_num, \
		average_temperature,average_pressure,failure_rate,currentSeconds,true);

	else
		makeEspressoRecord(timeToInsert,espressoMachine,coffeeStore,serial_num,\ 
		average_temperature,average_pressure,failure_rate,currentSeconds,false);
…..
	timeToInsert = gsAddTime(timeToInsert,secondsPerShot, GS_TIME_UNIT_SECOND);

The starting time uses the gsAddTime to offset the current time by a day. The stopping time will be the current time. The shot rate determines the amount of records to be generated and the time difference between them. After a record is created and inserted into GridDB, the timestamp for the next record adds a certain amount of seconds of the past record. This process will repeat until the next timestamp to insert reaches or is greater than the current time.

reset.sh / reset.c

The reset program is for removing all the data from a coffee chain. This extends to all the coffee stores, the coffee machine containers and all the timestamp records they contain. The process begins by finding the coffee chain container. From there it locates all the coffee store id’s of all the coffee stores in the coffee chain. From there all the coffee machines in each coffee store are dropped from GridDB. After that the coffee stores then the coffee chain can be dropped as well.

gsGetCollectionGeneral(gridstore,argv[1],&coffee_chain); // Get chain
	….
	while(gsHasNextRow(rowSet)){ // Get all coffee stores in chain
	….
		gsGetNextRow(rowSet,row); // Get coffee store
		gsGetRowFieldAsString(row,0,&container_name); // Obtain store id
		gsGetCollectionGeneral(gridstore,container_name,&coffee_store); // Get store
	…
		while(gsHasNextRow(innerRs)){ // Get all coffee machines in store
			gsGetRowFieldAsString(storeEntry,0,&serial_num); // Obtain serial number		  
			gsDropTimeSeries(gridstore,serial_num); // Drop the corresponding TimeSeries
	….
		gsDropCollection(gridstore,container_name);// Drop coffee store
	….
gsDropCollection(gridstore,argv[1]); // Drop coffee chain

Source Code

You can download the application and its source code for the data generating client and data visualisation component from the link below:

Download: datavisualisation_application.tar.gz