/** * @author Mislav Čakarić * @brief Function that fetches nth main bucket * @param indexName name of index * @param n number of main bucket * @return address structure with data where the bucket is stored */ struct_add* Ak_get_nth_main_bucket_add(char *indexName, int n) { int i = 0, j = 0, k = 0, counter = 0, end = 0; AK_PRO; struct_add *add = (struct_add*) AK_malloc(sizeof (struct_add)); add->addBlock = 301; add->indexTd = 2; table_addresses *addresses = (table_addresses*) AK_get_index_addresses(indexName); while (addresses->address_from[i]) { for (j = addresses->address_from[i]; j < addresses->address_to[i]; j++) { AK_block *temp = (AK_block*) AK_read_block(j); for (k = 0; k < DATA_BLOCK_SIZE; k++) { if (temp->tuple_dict[k].type == FREE_INT) break; if (temp->tuple_dict[k].type == MAIN_BUCKET) { if (n == counter) { add->addBlock = j; add->indexTd = k; end = 1; break; } counter++; } } if (end) break; } i++; } AK_EPI; return add; AK_free(add); }
/** * @author Matija Novak, updated by Dino Laktašić * @brief Temporary function that creates table, and inserts an entry to the system_relation catalog * @param table table name * @param header AK_header of the new table * @param type_segment type of the new segment * @return No return value */ void AK_temp_create_table(char *table, AK_header *header, int type_segment) { AK_PRO; /* do we really need this??? Edited by Elvis Popovic*/ /* AK_block *sys_block = (AK_block *) AK_malloc(sizeof (AK_block)); */ AK_block *sys_block; sys_block = (AK_block *) AK_read_block(1); int startAddress = AK_initialize_new_segment(table, type_segment, header); int num = 8; //insert object_id AK_insert_entry(sys_block, TYPE_INT, &num, 8); //insert table name AK_insert_entry(sys_block, TYPE_VARCHAR, table, 9); //insert start address num = startAddress; AK_insert_entry(sys_block, TYPE_INT, &num, 10); //insert end address num = startAddress + 19; AK_insert_entry(sys_block, TYPE_INT, &num, 11); AK_write_block(sys_block); AK_free(sys_block); AK_EPI; }
/** * @author Mislav Čakarić * @brief Function that updates a bucket in block * @param add address of where the bucket is stored * @param data content of bucket stored in char array * @return No return value */ void Ak_update_bucket_in_block(struct_add *add, char *data) { AK_PRO; AK_block *block = (AK_block*) AK_read_block(add->addBlock); int address = block->tuple_dict[add->indexTd].address; int size = block->tuple_dict[add->indexTd].size; memcpy(&block->data[address], data, size); AK_write_block(block); AK_EPI; }
/** * @author Mislav Čakarić * @brief Function that fetches the info for hash index * @param indexName name of index * @return info bucket with info data for hash index */ hash_info* AK_get_hash_info(char *indexName) { AK_PRO; table_addresses *hash_addresses = (table_addresses*) AK_get_index_addresses(indexName); int block_add = hash_addresses->address_from[ 0 ]; hash_info *info = (hash_info*) AK_malloc(sizeof (hash_info)); memset(info, 0, sizeof (hash_info)); if (block_add == 0) { printf("Hash index does not exist!\n"); AK_EPI; return info; } AK_block *block = (AK_block*) AK_read_block(block_add); memcpy(info, block->data, sizeof (hash_info)); AK_EPI; return info; }
/** * @author Matija Šestak. * @brief Function re-read all the blocks from disk * @result EXIT_SUCCESS */ int AK_refresh_cache() { int i; AK_block *new_block; AK_block *old_block; AK_PRO; for (i = 0; i < MAX_CACHE_MEMORY; i++) { new_block = AK_read_block(db_cache->cache[i]->block->address); old_block = db_cache->cache[i]->block; db_cache->cache[i]->block = new_block; AK_free(old_block); } AK_EPI; return EXIT_SUCCESS; }
int AK_cache_block(int num, AK_mem_block *mem_block) { unsigned long timestamp; AK_block *block_cache; AK_block *block_cache_old; AK_PRO; /// read the block from the given address block_cache = AK_read_block(num); block_cache_old = mem_block->block; mem_block->block = block_cache; mem_block->dirty = BLOCK_CLEAN; /// set dirty bit in mem_block struct timestamp = clock(); /// get the timestamp mem_block->timestamp_read = timestamp; /// set timestamp_read mem_block->timestamp_last_change = timestamp; /// set timestamp_last_change AK_free(block_cache_old); AK_EPI; return EXIT_SUCCESS; }
/** * @author Mislav Čakarić * @brief Function that changes a info of hash index * @param indexName name of index * @param modulo value for modulo hash function * @param main_bucket_num number of main buckets * @param hash_bucket_num number of hash buckets * @return No return value */ void AK_change_hash_info(char *indexName, int modulo, int main_bucket_num, int hash_bucket_num) { AK_PRO; table_addresses *hash_addresses = (table_addresses*) AK_get_index_addresses(indexName); int block_add = hash_addresses->address_from[ 0 ]; if (block_add == 0) { printf("Hash index does not exist!\n"); } AK_block *block = (AK_block*) AK_read_block(block_add); hash_info *info = (hash_info*) AK_malloc(sizeof (hash_info)); info->modulo = modulo; info->main_bucket_num = main_bucket_num; info->hash_bucket_num = hash_bucket_num; memcpy(block->data, info, sizeof (hash_info)); block->tuple_dict[0].address = 0; block->tuple_dict[0].type = INFO_BUCKET; block->tuple_dict[0].size = sizeof (hash_info); AK_write_block(block); AK_EPI; }
/** * @author Mislav Čakarić * @brief Function that inserts a bucket to block * @param indexName name of index * @param data content of bucket stored in char array * @param type type of bucket (MAIN_BUCKET or HASH_BUCKET) * @return address structure with data where the bucket is stored */ struct_add* Ak_insert_bucket_to_block(char *indexName, char *data, int type) { int size, id; AK_PRO; struct_add *add = (struct_add*) AK_malloc(sizeof (struct_add)); add->addBlock = 0; add->indexTd = 0; int adr_to_write = (int) AK_find_AK_free_space(AK_get_index_addresses(indexName)); if (adr_to_write == -1) adr_to_write = (int) AK_init_new_extent(indexName, SEGMENT_TYPE_INDEX); if (adr_to_write == 0){ AK_EPI; return add; } AK_block *block = (AK_block*) AK_read_block(adr_to_write); Ak_dbg_messg(HIGH, INDICES, "insert_bucket_to_block: Position to write (tuple_dict_index) %d\n", adr_to_write); switch (type) { case MAIN_BUCKET: size = sizeof (main_bucket); break; case HASH_BUCKET: size = sizeof (hash_bucket); break; } id = block->last_tuple_dict_id + 1; memcpy(&block->data[block->AK_free_space], data, size); block->tuple_dict[id].address = block->AK_free_space; block->AK_free_space += size; block->tuple_dict[id].type = type; block->tuple_dict[id].size = size; block->last_tuple_dict_id = id; AK_write_block(block); add->addBlock = adr_to_write; add->indexTd = id; AK_EPI; return add; }
search_result AK_search_unsorted(char *szRelation, search_params *aspParams, int iNum_search_params) { AK_PRO; AK_flush_cache(); int iBlock; AK_mem_block *mem_block = NULL, tmp; int i, j, k; int iTupleMatches; search_result srResult; table_addresses *taAddresses; srResult.aiTuple_addresses = NULL; srResult.iNum_tuple_addresses = 0; srResult.aiSearch_attributes = NULL; srResult.aiBlocks = NULL; if (aspParams == NULL || iNum_search_params == 0){ AK_EPI; return srResult; } taAddresses = AK_get_table_addresses(szRelation); /// iterate through all the blocks for (k = 0; k < MAX_EXTENTS_IN_SEGMENT && taAddresses->address_from[k] > 0; k++) { // 200 == Novak's magic number :) for (iBlock = taAddresses->address_from[k]; iBlock <= taAddresses->address_to[k]; iBlock++) { //mem_block = AK_get_block(iBlock); mem_block = &tmp; mem_block->block = AK_read_block(iBlock); /// count number of attributes in segment/relation srResult.iNum_tuple_attributes = 0; for (i = 0; i < MAX_ATTRIBUTES; i++) { if (mem_block->block->header[i].att_name[0] == FREE_CHAR) break; srResult.iNum_tuple_attributes++; } srResult.aiSearch_attributes = (int *) AK_malloc(iNum_search_params * sizeof (int)); if (srResult.aiSearch_attributes == NULL) { printf("AK_search_unsorted: ERROR. Cannot allocate srResult.aiAttributes_searched.\n"); AK_EPI; exit(EXIT_ERROR); } srResult.iNum_search_attributes = 0; /// determine index of attributes on which search will be performed for (j = 0; j < iNum_search_params; j++) { for (i = 0; i < MAX_ATTRIBUTES; i++) { if (!strcmp(mem_block->block->header[i].att_name, aspParams[j].szAttribute)) { srResult.aiSearch_attributes[j] = i; srResult.iNum_search_attributes++; break; } } } /// if any of the provided attributes are not found in the relation, return empty result if (srResult.iNum_search_attributes != iNum_search_params) return srResult; /// in every tuple, for all required attributes, compare attribute value with searched-for value and store matched tuple addresses for (i = 0; i < DATA_BLOCK_SIZE && mem_block->block->tuple_dict[i].type != FREE_INT; i += srResult.iNum_tuple_attributes) { iTupleMatches = 1; for (j = 0; j < iNum_search_params && iTupleMatches; j++) { switch (aspParams[j].iSearchType) { case SEARCH_PARTICULAR: { size_t iSearchAttributeValueSize = AK_type_size(mem_block->block->header[srResult.aiSearch_attributes[j]].type, (char *) aspParams[j].pData_lower); if (mem_block->block->tuple_dict[i + srResult.aiSearch_attributes[j]].size != iSearchAttributeValueSize || memcmp(mem_block->block->data + mem_block->block->tuple_dict[i + srResult.aiSearch_attributes[j]].address, aspParams[j].pData_lower, iSearchAttributeValueSize)) { iTupleMatches = 0; } } break; case SEARCH_RANGE: { switch (mem_block->block->tuple_dict[i + srResult.aiSearch_attributes[j]].type) { case TYPE_INT: case TYPE_DATE: case TYPE_DATETIME: case TYPE_TIME: { int iAttributeValue = *((int *) (mem_block->block->data + mem_block->block->tuple_dict[i + srResult.aiSearch_attributes[j]].address)); if (iAttributeValue < *((int *) aspParams[j].pData_lower) || iAttributeValue > *((int *) aspParams[j].pData_upper)) { iTupleMatches = 0; } } break; case TYPE_FLOAT: case TYPE_NUMBER: if (*((double *) (mem_block->block->data + mem_block->block->tuple_dict[i + srResult.aiSearch_attributes[j]].address)) < *((double *) aspParams[j].pData_lower) || *((double *) (mem_block->block->data + mem_block->block->tuple_dict[i + srResult.aiSearch_attributes[j]].address)) > *((double *) aspParams[j].pData_upper)) { iTupleMatches = 0; } break; default: // other types unsupported iTupleMatches = 0; } } break; case SEARCH_ALL: // iTupleMatches is already == 1, no action needed break; case SEARCH_NULL: { size_t iSearchAttributeValueSize = AK_type_size(mem_block->block->header[srResult.aiSearch_attributes[j]].type, (char *) aspParams[j].pData_lower); if (mem_block->block->tuple_dict[i + srResult.aiSearch_attributes[j]].type != TYPE_VARCHAR || iSearchAttributeValueSize != strlen("NULL") || memcmp(mem_block->block->data + mem_block->block->tuple_dict[i + srResult.aiSearch_attributes[j]].address, "NULL", strlen("NULL"))) iTupleMatches = 0; } break; default: iTupleMatches = 0; } } if (iTupleMatches) { /*if(DEBUG) { printf("AK_realloc(srResult.aiTuple_addresses = %p, srResult.iNum_tuple_addresses++ * sizeof(int) = %d)\n", srResult.aiTuple_addresses, (srResult.iNum_tuple_addresses + 1) * sizeof(int)); if(srResult.iNum_tuple_addresses == 7) puts("8"); }*/ srResult.iNum_tuple_addresses++; srResult.aiTuple_addresses = (int *) AK_realloc(srResult.aiTuple_addresses, srResult.iNum_tuple_addresses * sizeof (int)); if (srResult.aiTuple_addresses == NULL) { printf("AK_search_unsorted: ERROR. Cannot AK_reallocate srResult.aiTuple_addresses, iteration %d.\n", i); AK_EPI; exit(EXIT_ERROR); } /*if(DEBUG) puts("AK_realloc srResult.aiBlocks");*/ srResult.aiBlocks = (int *) AK_realloc(srResult.aiBlocks, srResult.iNum_tuple_addresses * sizeof (int)); if (srResult.aiBlocks == NULL) { printf("AK_search_unsorted: ERROR. Cannot AK_reallocate srResult.aiBlocks, iteration %d.\n", i); AK_EPI; exit(EXIT_ERROR); } srResult.aiTuple_addresses[srResult.iNum_tuple_addresses - 1] = i; srResult.aiBlocks[srResult.iNum_tuple_addresses - 1] = iBlock; } } } } AK_EPI; return srResult; }
/** * @author Miroslav Policki * @brief Function for testing file search * @return No return value */ void Ak_filesearch_test() { int i; double f; AK_mem_block *mem_block, tmp; AK_header hBroj_int[4], *hTmp; struct list_node *row_root; AK_PRO; // create table and fill it for testing purposes hTmp = (AK_header *) AK_create_header("Number int", TYPE_INT, FREE_INT, FREE_CHAR, FREE_CHAR); hBroj_int[0] = *hTmp; hTmp = (AK_header *) AK_create_header("Number float", TYPE_FLOAT, FREE_INT, FREE_CHAR, FREE_CHAR); hBroj_int[1] = *hTmp; hTmp = (AK_header *) AK_create_header("Varchar column", TYPE_VARCHAR, FREE_INT, FREE_CHAR, FREE_CHAR); hBroj_int[2] = *hTmp; memset(&hBroj_int[3], 0, sizeof (AK_header)); if (EXIT_ERROR == AK_initialize_new_segment("filesearch test table", SEGMENT_TYPE_TABLE, hBroj_int)) { printf("filesearch_test: ERROR. Unable to create \"filesearch test table \"\n"); AK_EPI; exit(EXIT_ERROR); } row_root = AK_malloc(sizeof (struct list_node)); if (row_root == NULL) { printf("filesearch_test: ERROR. Cannot allocate row_root.\n"); AK_EPI; exit(EXIT_ERROR); } for (i = -10, f = -i; i < 10; i++, f = -i) { Ak_Init_L3(&row_root); Ak_Insert_New_Element(TYPE_INT, &i, "filesearch test table", "Number int", row_root); Ak_Insert_New_Element(TYPE_FLOAT, &f, "filesearch test table", "Number float", row_root); Ak_Insert_New_Element(TYPE_VARCHAR, "test text", "filesearch test table", "Varchar column", row_root); Ak_insert_row(row_root); Ak_DeleteAll_L3(&row_root); } AK_free(row_root); // filesearch usage example starts here { char *szTmp; search_params sp[3]; search_result sr; int iLower, iUpper; double dTmp; sp[0].szAttribute = "Varchar column"; sp[0].iSearchType = SEARCH_ALL; sp[1].szAttribute = "Number int"; sp[1].iSearchType = SEARCH_RANGE; iLower = -5; iUpper = 5; sp[1].pData_lower = &iLower; sp[1].pData_upper = &iUpper; sp[2].szAttribute = "Number float"; sp[2].iSearchType = SEARCH_PARTICULAR; dTmp = 2; sp[2].pData_lower = &dTmp; Ak_dbg_messg(LOW, FILE_MAN, "Calling AK_search_unsorted"); sr = AK_search_unsorted("filesearch test table", sp, 3); for (i = 0; i < sr.iNum_tuple_addresses; i++) { //mem_block = AK_get_block (sr.aiBlocks[i]); // caching should be used when available mem_block = &tmp; mem_block->block = (AK_block *) AK_read_block(sr.aiBlocks[i]); printf("Found:%d\n", *((int *) (mem_block->block->data + mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 0].address))); printf("Found:%f\n", *((double *) (mem_block->block->data + mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 1].address))); szTmp = AK_malloc(mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 2].size + 1); memcpy(szTmp, mem_block->block->data + mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 2].address, mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 2].size); szTmp[mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 2].size] = '\0'; printf("Found:%s\n", szTmp); AK_free(szTmp); } AK_deallocate_search_result(sr); } AK_EPI; }
/** * @author Mislav Čakarić * @brief Function that inserts a record in hash bucket * @param indexName name of index * @param hashValue hash value of record that is being inserted * @param add address structure with data where the hash bucket is stored * @return No return value */ void AK_insert_in_hash_index(char *indexName, int hashValue, struct_add *add) { int i, address, size, hash_AK_free_space = 0; AK_PRO; struct_add *main_add = (struct_add*) AK_malloc(sizeof (struct_add)); struct_add *hash_add = (struct_add*) AK_malloc(sizeof (struct_add)); main_bucket *temp_main_bucket = (main_bucket*) AK_malloc(sizeof (main_bucket)); hash_bucket *temp_hash_bucket = (hash_bucket*) AK_malloc(sizeof (hash_bucket)); table_addresses *addresses = (table_addresses*) AK_get_index_addresses(indexName); if (addresses->address_from[0] == 0) printf("Hash index does not exist!\n"); else { char data[255]; memset(data, 0, 255); hash_info *info = (hash_info*) AK_malloc(sizeof (hash_info)); info = AK_get_hash_info(indexName); if (info->main_bucket_num == 0) { for (i = 0; i < MAIN_BUCKET_SIZE; i++) { temp_main_bucket->element[i].value = i; memset(&temp_main_bucket->element[i].add, 0, sizeof (struct_add)); } memcpy(&data, temp_main_bucket, sizeof (main_bucket)); main_add = Ak_insert_bucket_to_block(indexName, data, MAIN_BUCKET); temp_hash_bucket->bucket_level = MAIN_BUCKET_SIZE; for (i = 0; i < HASH_BUCKET_SIZE; i++) { temp_hash_bucket->element[i].value = -1; } memcpy(&data, temp_hash_bucket, sizeof (hash_bucket)); for (i = 0; i < MAIN_BUCKET_SIZE; i++) { hash_add = Ak_insert_bucket_to_block(indexName, data, HASH_BUCKET); memcpy(&temp_main_bucket->element[i].add, hash_add, sizeof (struct_add)); } memcpy(&data, temp_main_bucket, sizeof (main_bucket)); Ak_update_bucket_in_block(main_add, data); AK_change_hash_info(indexName, MAIN_BUCKET_SIZE, 1, MAIN_BUCKET_SIZE); } int hash_bucket_id = hashValue % info->modulo; int main_bucket_id = (int) (hash_bucket_id / MAIN_BUCKET_SIZE); main_add = Ak_get_nth_main_bucket_add(indexName, main_bucket_id); AK_block *temp_block = (AK_block*) AK_read_block(main_add->addBlock); address = temp_block->tuple_dict[main_add->indexTd].address; size = temp_block->tuple_dict[main_add->indexTd].size; memcpy(temp_main_bucket, &temp_block->data[address], size); memcpy(hash_add, &temp_main_bucket->element[hash_bucket_id % MAIN_BUCKET_SIZE].add, sizeof (struct_add)); temp_block = (AK_block*) AK_read_block(hash_add->addBlock); address = temp_block->tuple_dict[hash_add->indexTd].address; size = temp_block->tuple_dict[hash_add->indexTd].size; memcpy(temp_hash_bucket, &temp_block->data[address], size); for (i = 0; i < HASH_BUCKET_SIZE; i++) { if (temp_hash_bucket->element[i].value == -1) { hash_AK_free_space = 1; temp_hash_bucket->element[i].value = hashValue; memcpy(&temp_hash_bucket->element[i].add, add, sizeof (struct_add)); memcpy(&data, temp_hash_bucket, sizeof (hash_bucket)); Ak_update_bucket_in_block(hash_add, data); break; } } if (hash_AK_free_space == 0) { if (temp_hash_bucket->bucket_level == info->modulo) { //adding new main buckets for (i = 0; i < info->main_bucket_num; i++) { main_add = Ak_get_nth_main_bucket_add(indexName, i); AK_block *temp_block = (AK_block*) AK_read_block(main_add->addBlock); address = temp_block->tuple_dict[main_add->indexTd].address; size = temp_block->tuple_dict[main_add->indexTd].size; memcpy(data, &temp_block->data[address], size); Ak_insert_bucket_to_block(indexName, data, MAIN_BUCKET); } AK_change_hash_info(indexName, info->modulo * 2, info->main_bucket_num * 2, info->hash_bucket_num); info = AK_get_hash_info(indexName); } int hash_bucket_id2 = (hash_bucket_id + info->modulo / 2) % info->modulo; int main_bucket_id2 = (int) (hash_bucket_id2 / MAIN_BUCKET_SIZE); //swapping hash bucket id's if (hash_bucket_id2 < hash_bucket_id) { int temp = hash_bucket_id; hash_bucket_id = hash_bucket_id2; hash_bucket_id2 = temp; temp = main_bucket_id; main_bucket_id = main_bucket_id2; main_bucket_id2 = temp; } hash_bucket *temp_hash_bucket2 = (hash_bucket*) AK_malloc(sizeof (hash_bucket)); temp_hash_bucket2->bucket_level = temp_hash_bucket->bucket_level * 2; for (i = 0; i < HASH_BUCKET_SIZE; i++) { temp_hash_bucket2->element[i].value = -1; memset(&temp_hash_bucket2->element[i].add, 0, sizeof (struct_add)); } memcpy(data, temp_hash_bucket2, sizeof (hash_bucket)); Ak_update_bucket_in_block(hash_add, data); main_add = Ak_get_nth_main_bucket_add(indexName, main_bucket_id2); temp_block = (AK_block*) AK_read_block(main_add->addBlock); address = temp_block->tuple_dict[main_add->indexTd].address; size = temp_block->tuple_dict[main_add->indexTd].size; memcpy(temp_main_bucket, &temp_block->data[address], size); hash_add = Ak_insert_bucket_to_block(indexName, data, HASH_BUCKET); memcpy(&temp_main_bucket->element[hash_bucket_id2 % MAIN_BUCKET_SIZE].add, hash_add, sizeof (struct_add)); memcpy(data, temp_main_bucket, sizeof (main_bucket)); Ak_update_bucket_in_block(main_add, data); AK_change_hash_info(indexName, info->modulo, info->main_bucket_num, info->hash_bucket_num + 1); for (i = 0; i < HASH_BUCKET_SIZE; i++) { int value = temp_hash_bucket->element[i].value; memcpy(main_add, &temp_hash_bucket->element[i].add, sizeof (struct_add)); AK_insert_in_hash_index(indexName, value, main_add); } AK_insert_in_hash_index(indexName, hashValue, add); } } AK_EPI; }