From 5dd0d7700fa98197cdadaa2369d789e092cc0f49 Mon Sep 17 00:00:00 2001 From: Soikk <76824648+Soikk@users.noreply.github.com> Date: Sun, 7 Aug 2022 15:41:19 +0200 Subject: [PATCH] Added removing things from db. Ref counts update when removing things. Added changelog. --- CHANGELOG | 5 ++ TODO | 15 +++-- include/database.h | 12 ++-- include/storage.h | 14 +++-- src/database.c | 148 +++++++++++++++++++++++++++++---------------- src/db.db | Bin 0 -> 715 bytes src/main.c | 10 ++- src/main.exe | Bin 0 -> 73988 bytes src/storage.c | 67 ++++++++++++++++++-- 9 files changed, 198 insertions(+), 73 deletions(-) create mode 100644 CHANGELOG create mode 100644 src/db.db create mode 100644 src/main.exe diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..9565fa1 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,5 @@ +1659879571 (Sun Aug 07 2022 15:39:31 GMT+0200 (Central European Summer Time)) +Added removing things from db. Ref counts update when removing things. Added changelog. + +1659832822 (Sun Aug 07 2022 02:40:22 GMT+0200 (Central European Summer Time)) +Created changelog diff --git a/TODO b/TODO index 3ffe276..e7a6030 100644 --- a/TODO +++ b/TODO @@ -1,12 +1,17 @@ -TODO Use inttypes.h add, divide and multiply functions - -TODO Consider refactoring tables to B-Trees (better performance?) - -TODO Add remove* functions, restructure tables functions +TODO Standarize function names TODO Get rid of old functionalities (strnatcmp, BM) ---------------------------------------------------------------- +DONE Make it so count of other files/tags gets updated when deleting files/tags + +DONE Add remove* functions, restructure tables functions + +DONE Add changelog files + +DONE Consider refactoring tables to B-Trees (better performance?) + NOTE: Ended up using AVL trees instead, only needed for hashes + DONE Change DB model from struct row typedef struct{ char path[MAXPATH]; diff --git a/include/database.h b/include/database.h index 5f2d99d..1ae65b6 100644 --- a/include/database.h +++ b/include/database.h @@ -15,10 +15,6 @@ typedef struct database{ database *newDatabase(char *name); -database *loadDatabase(const char* path); - -int storeDatabase(database *db, const char *path); - uint64_t addFile(database *db, char *file); uint64_t addTag(database *db, char *tag); @@ -27,10 +23,18 @@ int addFileTag(database *db, char *file, char *tag); int addFileTags(database *db, char *file, int ntags, ...); +int removeFile(database *db, char *file); + +int removeTag(database *db, char *tag); + int searchFile(database *db, char *file, uint64_t n, uint64_t **r, uint64_t *rl); int searchTag(database *db, char *tag, uint64_t n, uint64_t **r, uint64_t *rl); +int storeDatabase(database *db, const char *path); + +database *loadDatabase(const char* path); + void printDatabase(database *db); void debugAVLtree(node *n); diff --git a/include/storage.h b/include/storage.h index 8bfc751..dccfa5f 100644 --- a/include/storage.h +++ b/include/storage.h @@ -60,7 +60,7 @@ typedef struct lookupTable{ char **table; // They cant be longer than MAXPATH } ltable; -// Stores a number (used as the count for files and tags in the mapping table) +// Stores a number in the index that references the ltable (used as the count for files and tags in the mapping table) typedef struct countTable{ uint64_t size; uint64_t *table; @@ -94,6 +94,8 @@ ltable *newLtable(uint64_t size); int ltableAdd(ltable *lt, char *str); +int ltableRemove(ltable *lt, char *str); + uint64_t ltableSearch(ltable *lt, char *str); int storeLtable(const ltable *lt, FILE *fp); @@ -106,7 +108,7 @@ ctable *newCtable(uint64_t size); int ctableAdd(ctable *ct, uint64_t n); -int ctableDelete(ctable *ct, uint64_t n); +int ctableRemove(ctable *ct, uint64_t n); uint64_t ctableSearch(ctable *ct, uint64_t n); @@ -120,6 +122,12 @@ mtable *newMtable(uint64_t size); int mtableAdd(mtable *mt, relation r); +int mtableRemove(mtable *mt, relation r); + +int mtableRemoveFile(mtable *mt, uint64_t file); + +int mtableRemoveTag(mtable *mt, uint64_t tag); + uint64_t mtableSearch(mtable *mt, relation r); uint64_t mtableSearchFile(mtable *mt, uint64_t file); @@ -132,8 +140,6 @@ mtable *loadMtable(FILE *fp); // AVL TREE -uint64_t height(node *n); - node *newNode(uint64_t h, uint64_t i); node *insertNode(node *r, uint64_t h, uint64_t i); diff --git a/src/database.c b/src/database.c index a6a9dfa..5b6249b 100644 --- a/src/database.c +++ b/src/database.c @@ -14,60 +14,14 @@ database *newDatabase(char *name){ return db; } -database *loadDatabase(const char* path){ - FILE *fp = fopen(path, "rb"); - char *header = calloc(2, sizeof(char)); - fread(header, sizeof(char), 2, fp); - if(!sameStr(header, "DB")){ - fprintf(stderr, "Header is '%s' not 'DB'\n", header); - } - - char name[32]; - fread(&name, sizeof(char), 32, fp); - database *db = newDatabase(name); - db->lfiles = loadLtable(fp); - db->ltags = loadLtable(fp); - db->cfiles = loadCtable(fp); - db->ctags = loadCtable(fp); - db->hfiles = loadAVLTree(fp); - db->htags = loadAVLTree(fp); - db->map = loadMtable(fp); - - char *end = calloc(3, sizeof(char)); - fread(end, sizeof(char), 3, fp); - if(!sameStr(end, "END")){ - fprintf(stderr, "End is '%s' not 'END'\n", end); - } - fclose(fp); - return db; -} - -int storeDatabase(database *db, const char *path){ - FILE *fp = fopen(path, "wb"); - - char header[2] = "DB"; - fwrite(header, sizeof(char), 2, fp); - fwrite(db->name, sizeof(char), 32, fp); - - storeLtable(db->lfiles, fp); - storeLtable(db->ltags, fp); - storeCtable(db->cfiles, fp); - storeCtable(db->ctags, fp); - storeAVLTree(db->hfiles, fp); - storeAVLTree(db->htags, fp); - storeMtable(db->map, fp); - - char end[3] = "END"; - fwrite(end, sizeof(char), 3, fp); - - fclose(fp); - return 0; -} - static void increaseCount(ctable *ct, uint64_t i){ ct->table[i]++; } +static void decreaseCount(ctable *ct, uint64_t i){ + ct->table[i]--; +} + uint64_t addFile(database *db, char *file){ uint32_t l; file = normalizeStrLimit(file, &l, MAXPATH-1); @@ -131,6 +85,46 @@ int addFileTags(database *db, char *file, int ntags, ...){ return 0; } +int removeFile(database *db, char *file){ + uint32_t l; + file = normalizeStrLimit(file, &l, MAXPATH-1); + uint64_t i = ltableSearch(db->lfiles, file); + if(i == -1){ + return -1; + } + uint64_t *r, rl; + searchFile(db, file, 0, &r, &rl); + for(uint64_t j = 0; j < rl; ++j){ + decreaseCount(db->ctags, r[j]); + } + uint64_t h = crc64(0, file, l); + ltableRemove(db->lfiles, file); + ctableRemove(db->cfiles, i); + deleteNode(db->hfiles, h); + mtableRemoveFile(db->map, i); + return 0; +} + +int removeTag(database *db, char *tag){ + uint32_t l; + tag = normalizeStrLimit(tag, &l, MAXPATH-1); + uint64_t i = ltableSearch(db->ltags, tag); + if(i == -1){ + return -1; + } + uint64_t *r, rl; + searchTag(db, tag, 0, &r, &rl); + for(uint64_t j = 0; j < rl; ++j){ + decreaseCount(db->cfiles, r[j]); + } + uint64_t h = crc64(0, tag, l); + ltableRemove(db->ltags, tag); + ctableRemove(db->ctags, i); + deleteNode(db->htags, h); + mtableRemoveTag(db->map, i); + return 0; +} + // Stores in r a list with the indexes of the first n tags that this file has // If n is 0 or lower, it returns all of them. Stores in rl the length of r int searchFile(database *db, char *file, uint64_t n, uint64_t **r, uint64_t *rl){ @@ -191,6 +185,56 @@ int searchTag(database *db, char *tag, uint64_t n, uint64_t **r, uint64_t *rl){ return 0; } +int storeDatabase(database *db, const char *path){ + FILE *fp = fopen(path, "wb"); + + char header[2] = "DB"; + fwrite(header, sizeof(char), 2, fp); + fwrite(db->name, sizeof(char), 32, fp); + + storeLtable(db->lfiles, fp); + storeLtable(db->ltags, fp); + storeCtable(db->cfiles, fp); + storeCtable(db->ctags, fp); + storeAVLTree(db->hfiles, fp); + storeAVLTree(db->htags, fp); + storeMtable(db->map, fp); + + char end[3] = "END"; + fwrite(end, sizeof(char), 3, fp); + + fclose(fp); + return 0; +} + +database *loadDatabase(const char* path){ + FILE *fp = fopen(path, "rb"); + char *header = calloc(2, sizeof(char)); + fread(header, sizeof(char), 2, fp); + if(!sameStr(header, "DB")){ + fprintf(stderr, "Header is '%s' not 'DB'\n", header); + } + + char name[32]; + fread(&name, sizeof(char), 32, fp); + database *db = newDatabase(name); + db->lfiles = loadLtable(fp); + db->ltags = loadLtable(fp); + db->cfiles = loadCtable(fp); + db->ctags = loadCtable(fp); + db->hfiles = loadAVLTree(fp); + db->htags = loadAVLTree(fp); + db->map = loadMtable(fp); + + char *end = calloc(3, sizeof(char)); + fread(end, sizeof(char), 3, fp); + if(!sameStr(end, "END")){ + fprintf(stderr, "End is '%s' not 'END'\n", end); + } + fclose(fp); + return db; +} + void printDatabase(database *db){ for(uint64_t i = 0; i < db->map->size; ++i){ printf("%s -> %s\n", db->lfiles->table[db->map->table[i].file], db->ltags->table[db->map->table[i].tag]); @@ -217,9 +261,9 @@ void debugDatabase(database *db){ for(uint64_t i = 0; i < db->ltags->size; ++i){ printf("\t\t+%s (%" PRIu64 ")\n", db->ltags->table[i], db->ctags->table[i]); } - printf("\t-hfiles: %d\n", height(db->hfiles)); + printf("\t-hfiles: %d\n", db->lfiles->size); debugAVLtree(db->hfiles); - printf("\t-htags: %d\n", height(db->htags)); + printf("\t-htags: %d\n", db->ltags->size); debugAVLtree(db->htags); printf("\t-map: %d\n", db->map->size); for(uint64_t i = 0; i < db->map->size; ++i){ diff --git a/src/db.db b/src/db.db new file mode 100644 index 0000000000000000000000000000000000000000..1c122106f46deed811477a6ded6a18f0934e66ee GIT binary patch literal 715 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
  • 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 literal 0 HcmV?d00001 diff --git a/src/storage.c b/src/storage.c index 8ad938d..3e45b2e 100644 --- a/src/storage.c +++ b/src/storage.c @@ -37,6 +37,18 @@ int ltableAdd(ltable *lt, char *str){ return 0; } +int ltableRemove(ltable *lt, char *str){ + uint64_t i = ltableSearch(lt, str); + if(i == -1){ + return -1; + } + lt->size--; + for(uint64_t j = i; j < lt->size-1; ++j){ + lt->table[j] = lt->table[j+1]; + } + return 0; +} + uint64_t ltableSearch(ltable *lt, char *str){ uint32_t l; str = normalizeStrLimit(str, &l, MAXPATH-1); @@ -114,9 +126,8 @@ int ctableAdd(ctable *ct, uint64_t n){ return 0; } -int ctableDelete(ctable *ct, uint64_t n){ - uint64_t i = ctableSearch(ct, n); - if(i == -1){ +int ctableRemove(ctable *ct, uint64_t i){ + if(i >= ct->size){ return -1; } ct->size--; @@ -194,6 +205,52 @@ int mtableAdd(mtable *mt, relation r){ return 0; } +int mtableRemove(mtable *mt, relation r){ + uint64_t i = mtableSearch(mt, r); + if(i == -1){ + return -1; + } + mt->size--; + for(uint64_t j = i; j < mt->size-1; ++j){ + mt->table[j] = mt->table[j+1]; + } + return 0; +} + +int mtableRemoveFile(mtable *mt, uint64_t file){ + relation *nmt = malloc(mt->size*sizeof(relation)); + uint64_t ni = 0; + for(uint64_t i = 0; i < mt->size; ++i){ + if(file != mt->table[i].file){ + nmt[ni] = mt->table[i]; + ++ni; + } + } + mt->size = ni; + mt->table = malloc(mt->size*sizeof(relation)); + for(uint64_t i = 0; i < mt->size; ++i){ + mt->table[i] = nmt[i]; + } + return 0; +} + +int mtableRemoveTag(mtable *mt, uint64_t tag){ + relation *nmt = malloc(mt->size*sizeof(relation)); + uint64_t ni = 0; + for(uint64_t i = 0; i < mt->size; ++i){ + if(tag != mt->table[i].tag){ + nmt[ni] = mt->table[i]; + ++ni; + } + } + mt->size = ni; + mt->table = malloc(mt->size*sizeof(relation)); + for(uint64_t i = 0; i < mt->size; ++i){ + mt->table[i] = nmt[i]; + } + return 0; +} + uint64_t mtableSearch(mtable *mt, relation r){ for(uint64_t i = 0; i < mt->size; ++i){ if(r.file == mt->table[i].file && r.tag == mt->table[i].tag){ @@ -261,7 +318,7 @@ static inline uint64_t max(uint64_t a, uint64_t b){ return ((a > b) ? a : b); } -uint64_t height(node *n){ +static uint64_t height(node *n){ if(n != NULL){ return 1 + max(height(n->left), height(n->right)); } @@ -367,7 +424,7 @@ node *deleteNode(node *r, uint64_t h){ return r; } - uint64_t b = balance(r), bl = balance(r->left), br = balance(r->right); + int64_t b = balance(r), bl = balance(r->left), br = balance(r->right); if(b > 1 && bl >= 0){ // Left left return rotateNodeRight(r); } -- 2.39.5