summaryrefslogblamecommitdiffstats
path: root/src/protocol.c
blob: 292a8d9e2474ca7ab2793723d594a49de9096fde (plain) (tree)
1
2
3
4
5
6
7
8
9




                                                    

                     
                   
 
                       
 
                                                         
 

                                                                  
 
                                                    
                                           




                                                      
 



                                                        

                 
 
                                    


                                            
                               


                                               











                                                    
 



              
 

                       

                                                        
 
                                                                 



                              
 

                      
 


                 
            
       
             

 
                                        












                                                                         




                                   







                             
                                    
 

                                                         
 

                                                                  
 

                                                  
                                                   
 

                             
 
                        
                                     


                                             
                                   

             



              

                        

                                                         
 

                                                                  
 
                                           
                                                   
                                                  
 

                                   





              

                       
                                                         
                                                 

                                    
                                                                  
 

                                                      
                                                   
 

                                     





                                               
 

                                           
 

                                    
 
                                         
                                                   


                                                                    
 

                                                   
 

                                                       
 


           
 
 

              
                                   
                          








                                                    

                                      
                           
                                                     
 

                                                    
 








                                                          
                     

                   
                        
                
       


                         


                       


                

                      

                        










                                                                  
                                      





                                                    


                  

             


                     

              






















                                                                


                       
                                  
                         


                                                   
                        









                                             




                                                              




              
/* SPDX-License-Identifier: BSD-3-Clause */
/*
 * Copyright © 2020 rsiddharth <s@ricketyspace.net>
 */

#include <protocol.h>

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;
}