static int tree_delete_block(tree_t *tree, unsigned int block_vid){ // {{{ ssize_t ret; hash_t req_move[] = { { HK(action), DATA_UINT32T( ACTION_MOVE ) }, { HK(offset_from), DATA_OFFT ( (block_vid + 1) * sizeof(block_info) ) }, { HK(offset_to), DATA_OFFT ( (block_vid ) * sizeof(block_info) ) }, hash_end }; if( (ret = chain_next_query(tree->chain, req_move)) != 0) return ret; hash_t req_delete[] = { { HK(action), DATA_UINT32T( ACTION_DELETE ) }, { HK(offset), DATA_OFFT ( (tree->blocks_count - 1) * sizeof(block_info) ) }, { HK(size), DATA_SIZET( sizeof(block_info) ) }, hash_end }; if( (ret = chain_next_query(tree->chain, req_delete)) != 0) return ret; if(tree_reinit(tree) != 0) return -1; // TODO replace recalc with faster procedure which recalc only changed items instead of all if(tree_recalc(tree) != 0) return -1; return 0; } // }}}
static int tree_resize_block(tree_t *tree, unsigned int block_vid, unsigned int new_size){ // {{{ unsigned int delta; ssize_t ret; block_info block; int j; buffer_t req_buffer; buffer_init_from_bare(&req_buffer, &block, sizeof(block)); /* read block_info */ hash_t req_read[] = { { HK(action), DATA_UINT32T( ACTION_READ ) }, { HK(offset), DATA_OFFT ( block_vid * sizeof(block_info) ) }, { HK(size), DATA_SIZET( sizeof(block_info) ) }, { HK(buffer), DATA_BUFFERT(&req_buffer) }, hash_end }; if( (ret = chain_next_query(tree->chain, req_read)) <= 0){ buffer_destroy(&req_buffer); return -1; } /* fix block_info */ delta = new_size - block.size; block.size = new_size; /* write block info */ hash_t req_write[] = { { HK(action), DATA_UINT32T( ACTION_WRITE ) }, { HK(offset), DATA_OFFT ( block_vid * sizeof(block_info) ) }, { HK(size), DATA_SIZET( sizeof(block_info) ) }, { HK(buffer), DATA_BUFFERT(&req_buffer) }, hash_end }; chain_next_query(tree->chain, req_write); // TODO lock for(j=0; j < tree->nlevels; j++){ tree->table[ tree->tof[j] + (block_vid / tree->lss[j]) ] += delta; } // TODO unlock buffer_destroy(&req_buffer); return 0; } // }}}
static int tree_insert(tree_t *tree, unsigned int block_vid, unsigned int block_off, unsigned int size){ // {{{ block_info block; ssize_t ret; buffer_t req_buffer; buffer_init_from_bare(&req_buffer, &block, sizeof(block)); block.real_block_off = block_off; block.size = size; hash_t req_move[] = { { HK(action), DATA_UINT32T(ACTION_MOVE) }, { HK(offset_from), DATA_OFFT ((block_vid ) * sizeof(block_info)) }, { HK(offset_to), DATA_OFFT ((block_vid + 1) * sizeof(block_info)) }, hash_end }; ret = chain_next_query(tree->chain, req_move); hash_t req_write[] = { { HK(action), DATA_UINT32T( ACTION_WRITE ) }, { HK(offset), DATA_OFFT ( block_vid * sizeof(block_info) ) }, { HK(size), DATA_SIZET( sizeof(block_info) ) }, { HK(buffer), DATA_BUFFERT(&req_buffer) }, hash_end }; if( (ret = chain_next_query(tree->chain, req_write)) <= 0) goto cleanup; ret = -1; if(tree_reinit(tree) != 0) goto cleanup; // TODO replace recalc with faster procedure which recalc only changed items instead of all if(tree_recalc(tree) != 0) goto cleanup; ret = 0; cleanup: buffer_destroy(&req_buffer); return ret; } // }}}
static int tree_get_block(tree_t *tree, unsigned int block_vid, block_info *block){ // {{{ buffer_t req_buffer; buffer_init_from_bare(&req_buffer, block, sizeof(block_info)); hash_t req_read[] = { { HK(action), DATA_UINT32T( ACTION_READ ) }, { HK(offset), DATA_OFFT ( block_vid * sizeof(block_info) ) }, { HK(size), DATA_SIZET( sizeof(block_info) ) }, { HK(buffer), DATA_BUFFERT(&req_buffer) }, hash_end }; if(chain_next_query(tree->chain, req_read) <= 0) return -1; buffer_destroy(&req_buffer); return 0; } // }}}
static int tree_get(tree_t *tree, off_t offset, unsigned int *block_vid, off_t *real_offset){ // {{{ unsigned int i,j,ret; off_t level_off; unsigned int ptr; size_t chunk_size; block_info block; if(offset >= tree->table[0]) // out of range return -1; ret = -1; level_off = 0; ptr = 0; // TODO lock for(i=1; i < tree->nlevels; i++){ for(j=0; j < tree->elements_per_level; j++, ptr++){ chunk_size = tree->table[ tree->tof[i] + ptr]; /*printf("lev: %x el: %x ptr: %x (%x < %x + %x)\n", i, j, (unsigned int)ptr, (unsigned int)offset, (unsigned int)level_off, (unsigned int)chunk_size );*/ if(offset < level_off + chunk_size) break; level_off += chunk_size; } ptr *= tree->elements_per_level; } // last level buffer_t req_buffer; buffer_init_from_bare(&req_buffer, &block, sizeof(block)); /* read block_info */ for(j=0; j < tree->elements_per_level; j++, ptr++){ hash_t req_read[] = { { HK(action), DATA_UINT32T( ACTION_READ ) }, { HK(offset), DATA_OFFT ( ptr * sizeof(block_info) ) }, { HK(size), DATA_SIZET( sizeof(block_info) ) }, { HK(buffer), DATA_BUFFERT(&req_buffer) }, hash_end }; if(chain_next_query(tree->chain, req_read) <= 0) break; /*printf("el: %x ptr: %x (%x < %x + %x)\n", j, (unsigned int)ptr, (unsigned int)offset, (unsigned int)level_off, (unsigned int)block.size );*/ if(offset < level_off + block.size){ *block_vid = ptr; *real_offset = block.real_block_off + (offset - level_off); ret = 0; break; } level_off += block.size; } buffer_destroy(&req_buffer); // TODO unlock return ret; } // }}}
static int tree_recalc(tree_t *tree){ // {{{ int i,j; ssize_t ret_size; unsigned int block_size; unsigned int read_size; buffer_t *buffer; size_t *calcs; size_t blocks_left; unsigned int ptr = 0; unsigned int nlevels = tree->nlevels; if( (blocks_left = tree->blocks_count) == 0) return 0; calcs = calloc(sizeof(size_t), tree->nlevels); buffer = buffer_alloc(); while(blocks_left > 0){ read_size = ( (blocks_left > tree->read_per_calc) ? tree->read_per_calc : blocks_left ); hash_t req_read[] = { { HK(action), DATA_UINT32T(ACTION_READ) }, { HK(offset), DATA_OFFT (ptr * sizeof(block_info)) }, { HK(size), DATA_SIZET(read_size * sizeof(block_info)) }, { HK(buffer), DATA_BUFFERT(buffer) }, hash_end }; if( (ret_size = chain_next_query(tree->chain, req_read)) <= 0) break; buffer_process(buffer, ret_size, 0, do { for(i=0; i < size; i += sizeof(block_info), ptr += 1){ block_size = ((block_info *)(chunk + i))->size; //printf("block: %x size: %x\n", (unsigned int)ptr, (unsigned int)block_size); for(j=0; j < nlevels; j++){ calcs[j] += block_size; //printf("block: [%x/%x] calcs[%x] = %x (ptr: %x)\n", // (unsigned int)ptr, (unsigned int)tree->blocks_count, // (unsigned int)j, (unsigned int)calcs[j], // (unsigned int)( ptr / tree->lss[j] ) //); if( (ptr % tree->lss[j]) == tree->lss[j] - 1){ tree->table[ tree->tof[j] + (ptr / tree->lss[j]) ] = calcs[j]; calcs[j] = 0; } } } }while(0) ); blocks_left -= ret_size / sizeof(block_info); } // flush for(j=0; j < nlevels; j++){ /* printf("dumping j %x ptr: %x lss: %x [%x]=%x\n", j, (unsigned int)ptr, (unsigned int)tree->lss[j], (unsigned int)(tree->tof[j] + (ptr / tree->lss[j])), (unsigned int)calcs[j] );*/ tree->table[ tree->tof[j] + (ptr / tree->lss[j]) ] = calcs[j]; } buffer_free(buffer); free(calcs); return (blocks_left == 0) ? 0 : -1; } // }}}
START_TEST (test_structs){ hash_t structure[] = { { HK(key1), DATA_HASHT(hash_end) }, { HK(key2), DATA_HASHT(hash_end) }, { HK(key3), DATA_HASHT( { HK(default), DATA_UINT32T(0) }, hash_end )}, { HK(key4), DATA_HASHT(hash_end) }, hash_end }; request_t values[] = { { HK(key4), DATA_STRING("hello") }, { HK(key1), DATA_UINT32T(100) }, { HK(key2), DATA_OFFT(10) }, { HK(key3), DATA_UINT32T(0) }, hash_end }; ssize_t ret; char test[100] = {0}; char orig[] = "\x64\x00\x00\x00" "\x0A\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00" "hello\x00"; data_t test_data = DATA_RAW(test, 100); ret = struct_pack(structure, values, &test_data); fail_unless(ret > 0, "struct_pack failed");