int store_clk(struct clk *clk) { int pos, hash; int k = 1, n = 1, s = 1; int count = 0; hash = get_hash_val(clk->name); clk_dbg("%s:pos=%d\n", clk->name, hash); pos = hash; while(1){ count ++; if(hash_tab[pos] < 0) break; k++; n = k>>1; s = -s; pos = hash + s*n; if(pos < 0) pos += HASH_TAB_LEN; if(pos >= HASH_TAB_LEN) pos -= HASH_TAB_LEN; if(pos == hash) return -1; } clk_dbg("count = %d\n", count); hash_tab[pos] = clk->id; return pos; }
void keydb_unlock(int64_t pos) { char key[1024] = ""; int hash_number; sprintf(key, "%llu", pos); // turn pos into a string. hash_number = get_hash_val(10, key); // 2^10 = 1024. See SHM_KEYDB_BITMAP. sem_wait(KEYDB_LOCK); bit_array_clear(SHM_KEYDB_BITMAP, hash_number); sem_post(KEYDB_LOCK); }
void keydb_lock(int64_t pos) { char key[1024] = ""; int hash_number; sprintf(key, "%llu", pos); // turn pos into a string. hash_number = get_hash_val(10, key); // 2^10 = 1024. See SHM_KEYDB_BITMAP. while (1) { sem_wait(KEYDB_LOCK); if ((bit_array_test(SHM_KEYDB_BITMAP, hash_number)) == 0) { bit_array_set(SHM_KEYDB_BITMAP, hash_number); sem_post(KEYDB_LOCK); break; } sem_post(KEYDB_LOCK); } }
struct clk *search_clk(const char *name) { struct clk *clk; int hash, pos; int id; int k = 1, n = 1, s = 1; hash = get_hash_val(name); pos = hash; while(1){ id = hash_tab[pos]; if(id >= 0){ clk = &sep0611_clk[id]; if(!strcmp(name, clk->name)){ return clk; } } k++; n = k>>1; s = -s; pos = hash + s*n; if(pos < 0) pos += HASH_TAB_LEN; if(pos >= HASH_TAB_LEN) pos -= HASH_TAB_LEN; if(pos == hash) break; } return NULL; }
int write_record(char* key, char* value) { int len = strlen(value); div_t qnr = div(len, BLOCK_SIZE); int blocks = qnr.quot; void* buffer; int byte_count = 0; int block_offset; int64_t byte_offset; int index_result; int hash_id = get_hash_val(HASH_BITS, key); int find_result; // lock this part of the key-space to make the write atomic. hash_write_lock(hash_id); if (find(key) > 0) { // Bail if we've got a same-key collision. hash_write_unlock(hash_id); return -2; } // Figure out how many blocks we need and then requisition // them from the block bitmap table. if (qnr.rem > 0) blocks++; // round up to the next whole block. if ((block_offset = create_block_reservation(blocks)) == -1) { fprintf(stderr, "Failed to reserve space in the block bitmap.\n"); hash_write_unlock(hash_id); return(-1); } byte_count = blocks * BLOCK_SIZE; byte_offset = block_offset * BLOCK_SIZE; // Make a temporary buffer that is at least as big as the // data payload that we need to write. The buffer will be // zero-padded on the end. if ((buffer = malloc(byte_count)) == NULL) { perror("malloc failed in write_record()"); release_block_reservation(block_offset, blocks); hash_write_unlock(hash_id); return(-1); } bzero(buffer, byte_count); memcpy(buffer, value, len); // write to the appropriate location in our file if ((pwrite(DB_FD, buffer, byte_count, byte_offset)) == -1) { perror("pwrite failed in write_record"); release_block_reservation(block_offset, blocks); hash_write_unlock(hash_id); free(buffer); return(-1); } free(buffer); // Pass the key and the block offset to the index. index_result = write_index(key, block_offset, blocks); hash_write_unlock(hash_id); if (index_result < 0) { fprintf(stderr, "write_index failed in write_record with %d.\n", index_result); release_block_reservation(block_offset, blocks); return(-1); } return 0; }
int delete_record(char* key) { void* buffer; int byte_count = 0; int block_offset; int64_t byte_offset; int64_t pos = 0; int result; struct idx index_rec; int hash_id = get_hash_val(HASH_BITS, key); // lock this part of the key-space to make the delete atomic. // No one can be creating this key while we are deleting it. hash_write_lock(hash_id); pos = find(key); if (pos == -1) { fprintf(stderr, "Call to find() failed with %lld.\n", pos); hash_write_unlock(hash_id); return(-1); } if (pos == -2) { hash_write_unlock(hash_id); return(-2); // Not in the index } // Fetch the index record so we can find the blocks to delete result = pread(IDX_FD, (void*)&index_rec, IDX_ENTRY_SIZE, pos); if (result == 0) { fprintf(stderr, "EOF encoutered unexpectedly.\n"); hash_write_unlock(hash_id); return(-1); } if (result < IDX_ENTRY_SIZE) { // Somehow the read failed. perror("index read failed in function delete_record"); hash_write_unlock(hash_id); return(-1); } index_rec.key[0] = '\0'; // NULL at the beginning of the key means it is free. result = pwrite(IDX_FD, (void*)&index_rec, IDX_ENTRY_SIZE, pos); // zap the key. hash_write_unlock(hash_id); // key is now deleted. byte_count = index_rec.length * BLOCK_SIZE; byte_offset = index_rec.block_offset * BLOCK_SIZE; // Make a temporary, zero-padded buffer that is at least as big as the // data payload that we need to erase. if ((buffer = malloc(byte_count)) == NULL) { perror("malloc failed in delete_record()"); return(-1); } bzero(buffer, byte_count); // write the zeros to the appropriate location in our file. if ((pwrite(DB_FD, buffer, byte_count, byte_offset)) == -1) { perror("pwrite failed in delete_record"); free(buffer); return(-1); } free(buffer); // Mark these blocks as usable again. release_block_reservation(index_rec.block_offset, index_rec.length); return(0); }
int write_index(char* key, int block_offset, int length) { int hash_id = get_hash_val(HASH_BITS, key); struct idx index_rec = {}; struct idx* index_rec_ptr; int result; int64_t pos = hash_id * IDX_ENTRY_SIZE; int find_results = find(key); index_rec_ptr = &index_rec; if (find_results == -1) { fprintf(stderr, "find() failed when called from write_index. Don't know why.\n"); return -1; } if (find_results > 0) { return -2; // record with this key already exists. } while (1) { result = pread(IDX_FD, (void*)index_rec_ptr, IDX_ENTRY_SIZE, pos); if (result == 0) { fprintf(stderr, "EOF encoutered unexpectedly.\n"); return -1; } if (result < IDX_ENTRY_SIZE) { // Somehow the read failed. perror("index read failed in function write_index"); return -1; } // Determine if we can write on this index record, or do we need // to start looking down the chain. if (index_rec.key[0] == '\0') { // There is space here. // Don't change the 'next' field as it may point to addnl records in the chain. index_rec.block_offset = block_offset; index_rec.length = length; strncpy(index_rec_ptr->key, key, KEY_LEN - 1); pwrite(IDX_FD, (void*)index_rec_ptr, IDX_ENTRY_SIZE, pos); // write our key here. return 0; } // Since we are here, the test above failed. The current index record is in use. // If the 'next' pointer is 0, we can just create a new index record for ourself. if (index_rec.next == 0) { // no next index record in the chain. create one. // Lock the index file. // we don't want to compete with someone else for appending to the index file. if (sem_wait(IDX_APPEND_LOCK) == -1) { perror("call to sem_wait in write_index failed.\n"); return(-1); } index_rec.next = lseek(IDX_FD, 0, SEEK_END); pwrite(IDX_FD, (void*)index_rec_ptr, IDX_ENTRY_SIZE, pos); // update current rec with pointer to next. pos = index_rec.next; index_rec.next = 0; index_rec.block_offset = block_offset; index_rec.length = length; strncpy(index_rec_ptr->key, key, KEY_LEN - 1); pwrite(IDX_FD, (void*)index_rec_ptr, IDX_ENTRY_SIZE, pos); // add a new index entry. sem_post(IDX_APPEND_LOCK); return 0; } // Since we are here, we need to keep moving down the chain til we find a blank spot or the end. pos = index_rec.next; // move on to next record. } }
struct db_ptr find_db_ptr(char* key) { // Attempts to find the key in the hash table and return a structure // that points to the record in the db file. int hash_id = get_hash_val(HASH_BITS, key); struct idx index_rec = {}; struct db_ptr db_rec = {.block_offset = -1, .blocks = -1}; int result; int64_t pos = hash_id * IDX_ENTRY_SIZE; while (1) { result = pread(IDX_FD, (void*)&index_rec, IDX_ENTRY_SIZE, pos); if (result == 0) { fprintf(stderr, "EOF encoutered unexpectedly.\n"); return db_rec; } if (result < IDX_ENTRY_SIZE) { // Somehow the read failed. perror("index read failed in function find_db_ptr"); return db_rec; } if ((memcmp(key, index_rec.key, KEY_LEN)) == 0) {// found a match db_rec.block_offset = index_rec.block_offset; db_rec.blocks = index_rec.length; return db_rec; } if ((pos = index_rec.next) == 0) return db_rec; // return if no next record. Otherwise, keep looping. } } int find(char* key) { // returns an offset in the index for the given key. int hash_id = get_hash_val(HASH_BITS, key); struct idx index_rec = {}; int result; int64_t pos = hash_id * IDX_ENTRY_SIZE; while (1) { result = pread(IDX_FD, (void*)&index_rec, IDX_ENTRY_SIZE, pos); if (result == 0) { fprintf(stderr, "EOF encoutered unexpectedly.\n"); return -1; } if (result < IDX_ENTRY_SIZE) { // Somehow the read failed. perror("index read failed in function find"); return -1; } if ((memcmp(key, index_rec.key, KEY_LEN)) == 0) return pos; // found if ((pos = index_rec.next) == 0) return -2; // no next record. } }