/* SPDX-License-Identifier: BSD-3-Clause */ /* * Copyright © 2020 rsiddharth */ #include static TSTree *tst; int sscreate(char *key) { check(key != NULL || strlen(key) < 1, "key invalid"); // 1. Check if key is already in the tree. Record *rec = (Record *) TSTree_search(tst, key, strlen(key)); // If it's already there; there's nothing to do. if (rec != NULL && rec->deleted == 0) { return 1; } // If it's already there and deleted, undelete it. if (rec != NULL && rec->deleted == 1) { rec->deleted = 0; // Allocate fresh Stats. rec->st = Stats_create(); check(rec->st != NULL, "stats creation failed"); return 2; } // 2. Create bstring from 'key'. bstring k = bfromcstr(key); check(k != NULL, "key creation failed"); // 3. Allocate fresh Stats. Stats *st = Stats_create(); check(st != NULL, "stats creation failed"); // 4. Create Record. rec = (Record *) calloc(1, sizeof(Record)); check_mem(rec); // 5. Initialize Record. rec->key = k; rec->st = st; rec->deleted = 0; // 6. Add Record to tree. tst = TSTree_insert(tst, key, strlen(key), rec); check(tst != NULL, "tstree insert failed"); return 0; error: return -1; } int ssdelete(char *key) { check(key != NULL || strlen(key) < 1, "key invalid"); check(tst != NULL, "tstree not initialized"); Record *rec = (Record *) TSTree_search(tst, key, strlen(key)); if (rec == NULL) { // key does not exists. return 0; } // Mark as deleted. rec->deleted = 1; // Free Stats. free(rec->st); return 0; error: return -1; } int sssample_parent(char *key, double s) { check(key != NULL || strlen(key) < 1, "key invalid"); check(tst != NULL, "tstree not initialized"); // 1. Try to get Record with key prefix. Record *rec = (Record *) TSTree_search_prefix(tst, key, strlen(key)); if (rec == NULL) { // No record with key prefix. return 0; } check(rec->st != NULL, "record's st invalid"); if (rec->deleted == 1) { // Record was deleted; nop. return 0; } // 2. Sample! Stats_sample(rec->st, s); return 1; error: return -1; } double sssample(char *key, double s) { check(key != NULL || strlen(key) < 1, "key invalid"); check(tst != NULL, "tstree not initialized"); // 1. Try to get Record for key. Record *rec = (Record *) TSTree_search(tst, key, strlen(key)); check(rec != NULL, "record not found"); check(rec->st != NULL, "record's st invalid"); check(rec->deleted != 1, "record was deleted"); // 2. Sample! Stats_sample(rec->st, s); // 3. Sample parent! int rc = sssample_parent(key, s); check(rc >= 0, "sampling parent failed"); // 4. Get mean. double m = Stats_mean(rec->st); return m; error: return -1; } double ssmean(char *key) { check(key != NULL || strlen(key) < 1, "key invalid"); check(tst != NULL, "tstree not initialized"); // 1. Try to get Record for key. Record *rec = (Record *) TSTree_search(tst, key, strlen(key)); check(rec != NULL, "record not found"); check(rec->deleted != 1, "record was deleted"); check(rec->st != NULL, "record's st invalid"); // 2. Get mean. double m = Stats_mean(rec->st); return m; error: return -1; } char *ssdump(char *key) { check(key != NULL && strlen(key) > 0, "key invalid"); check(tst != NULL, "tstree not initialized"); // 1. create bstring from 'key'. Record *rec = (Record *) TSTree_search(tst, key, strlen(key)); check(rec != NULL, "record not found"); check(rec->st != NULL, "stats not found for key"); check(rec->deleted != 1, "record was deleted"); // 2. get dump. char *dstr = Stats_dump(rec->st); check(dstr != NULL, "dump failed for key"); return dstr; error: return NULL; } // meant to be used by sslist. void traverse_tree(void *value, void *data) { Record *rec = (Record *) value; bstring bstr = (bstring) data; check(rec != NULL, "Record is NULL"); check(rec->deleted != 1, "Record was deleted"); check(bstr != NULL, "bstr is NULL"); check(rec->key != NULL, "Record's key is NULL"); check(blength(rec->key) > 0, "Record's key is an empty string"); int rc = bconcat(bstr, rec->key); check(rc == BSTR_OK, "bstr key concat failed"); rc = bconchar(bstr, '\n'); check(rc == BSTR_OK, "bstr newline concat failed"); error: return; } char *sslist() { char *list = NULL, *tmp = NULL; bstring ks_str = NULL; if (tst == NULL) { list = (char *) calloc(7 + 1, sizeof(char)); check_mem(list); list = strncpy(list, "EMPTY\n\r", 7); return list; } // 1. Create "accumulator" string. ks_str = bfromcstr(""); check(ks_str != NULL, "error creating keys_str"); // 2. Accumulate keys into "accumulator" string. TSTree_traverse(tst, traverse_tree, ks_str); // 3. Make result. tmp = bstr2cstr(ks_str, ' '); list = (char *) calloc(strlen(tmp) + 1, sizeof(char)); check_mem(list); list = strncpy(list, tmp, strlen(tmp)); // 4. Clean up. bdestroy(ks_str); bcstrfree(tmp); // 3. Return result. return list; error: if (ks_str) { bdestroy(ks_str); } if (tmp) { bcstrfree(tmp); } return NULL; } int ssstore(char *key) { char *st_str = NULL; check(key != NULL && strlen(key) > 0, "key invalid"); check(tst != NULL, "tstree not initialized"); // 1. create bstring from 'key'. Record *rec = (Record *) TSTree_search(tst, key, strlen(key)); check(rec != NULL, "record not found"); check(rec->st != NULL, "stats not found for key"); check(rec->deleted != 1, "record was deleted"); // 2. stringify the stats. st_str = Stats_stringify(rec->st); check(st_str != NULL, "stats stringify failed"); // 3. store stats in db. int rc = db_store(key, st_str); check(rc == 0, "db store failed"); // 4. cleanup. free(st_str); return 0; error: if (st_str) { free(st_str); } return -1; } int ssload(char *from, char *to) { check(from != NULL && strlen(from) > 0, "from invalid"); check(to != NULL && strlen(to) > 0, "to invalid"); check(tst != NULL, "tstree not initialized"); // 1. Check if 'to' key already exists. Record *rec = (Record *) TSTree_search(tst, to, strlen(to)); // 2. if 'to' key exists return immediately with -2. if (rec != NULL && rec->deleted == 0) { return -2; } // 3. read 'from' key from database. char *st_str = db_load(from); check(st_str != NULL, "db load failed"); // 4. construct stats from string. Stats *st = Stats_unstringify(st_str); check(st != NULL, "stats unstringify failed"); // clean up st_str. free(st_str); // 5. create Record if needed. int rec_created = 0; if (rec == NULL) { rec = (Record *) calloc(1, sizeof(Record)); check_mem(rec); rec_created = 1; } // 6. get things ready for insertiion bstring tk = bfromcstr(to); check(tk != NULL, "key creation failed"); rec->key = tk; rec->st = st; rec->deleted = 0; // 7. insert Record into 'to' key in the TSTree if needed. if (rec_created == 1) { tst = TSTree_insert(tst, to, strlen(to), rec); check(tst != NULL, "tstree insert failed"); } return 0; error: return -1; }