/** * Copyright (C) 2008 Happy Fish / YuQing * * FastDFS may be copied only under the terms of the GNU General * Public License V3, which may be found in the FastDFS source kit. * Please visit the FastDFS Home Page http://www.fastken.com/ for more detail. **/ //trunk_free_block_checker.c #include #include #include #include #include #include #include #include #include #include #include #include #include "fdfs_define.h" #include "fastcommon/logger.h" #include "fastcommon/shared_func.h" #include "fastcommon/avl_tree.h" #include "tracker_types.h" #include "storage_global.h" #include "trunk_free_block_checker.h" #define TRUNK_FREE_BLOCK_ARRAY_INIT_SIZE 32 static AVLTreeInfo tree_info_by_id = {NULL, NULL, NULL}; //for unique block nodes static int storage_trunk_node_compare_entry(void *p1, void *p2) { return memcmp(&(((FDFSTrunksById *)p1)->trunk_file_id), \ &(((FDFSTrunksById *)p2)->trunk_file_id), \ sizeof(FDFSTrunkFileIdentifier)); } int trunk_free_block_checker_init() { int result; if ((result=avl_tree_init(&tree_info_by_id, free, \ storage_trunk_node_compare_entry)) != 0) { logError("file: "__FILE__", line: %d, " \ "avl_tree_init fail, " \ "errno: %d, error info: %s", \ __LINE__, result, STRERROR(result)); return result; } return 0; } void trunk_free_block_checker_destroy() { avl_tree_destroy(&tree_info_by_id); } int trunk_free_block_tree_node_count() { return avl_tree_count(&tree_info_by_id); } static int block_tree_count_walk_callback(void *data, void *args) { int *pcount; pcount = (int *)args; *pcount += ((FDFSTrunksById *)data)->block_array.count; return 0; } int trunk_free_block_total_count() { int count; count = 0; avl_tree_walk(&tree_info_by_id, block_tree_count_walk_callback, &count); return count; } #define FILL_FILE_IDENTIFIER(target, pTrunkInfo) \ memset(&target, 0, sizeof(target)); \ memcpy(&(target.path), &(pTrunkInfo->path), sizeof(FDFSTrunkPathInfo));\ target.id = pTrunkInfo->file.id; int trunk_free_block_check_duplicate(FDFSTrunkFullInfo *pTrunkInfo) { FDFSTrunkFileIdentifier target; FDFSTrunksById *pFound; FDFSTrunkFullInfo **blocks; int end_offset; int left; int right; int mid; int result; /* char buff[256]; logWarning("file: "__FILE__", line: %d, " \ "trunk entry: %s", __LINE__, \ trunk_info_dump(pTrunkInfo, buff, sizeof(buff))); */ FILL_FILE_IDENTIFIER(target, pTrunkInfo); pFound = (FDFSTrunksById *)avl_tree_find(&tree_info_by_id, &target); if (pFound == NULL) { return 0; } /* { logWarning("file: "__FILE__", line: %d, " \ "ARRAY COUNT: %d, trunk entry: %s", \ __LINE__, pFound->block_array.count, \ trunk_info_dump(pTrunkInfo, buff, sizeof(buff))); } */ if (pFound->block_array.count == 0) { return 0; } blocks = pFound->block_array.blocks; end_offset = pTrunkInfo->file.offset + pTrunkInfo->file.size; if (end_offset <= blocks[0]->file.offset) { return 0; } right = pFound->block_array.count - 1; if (pTrunkInfo->file.offset >= blocks[right]->file.offset + \ blocks[right]->file.size) { return 0; } result = 0; mid = 0; left = 0; while (left <= right) { mid = (left + right) / 2; if (pTrunkInfo->file.offset < blocks[mid]->file.offset) { if (blocks[mid]->file.offset < end_offset) { result = EEXIST; break; } right = mid - 1; } else if (pTrunkInfo->file.offset == blocks[mid]->file.offset) { if (pTrunkInfo->file.size == blocks[mid]->file.size) { char buff[256]; logWarning("file: "__FILE__", line: %d, " \ "node already exist, trunk entry: %s", \ __LINE__, trunk_info_dump(pTrunkInfo, \ buff, sizeof(buff))); return EEXIST; } result = EEXIST; break; } else { if (pTrunkInfo->file.offset < (blocks[mid]->file.offset + \ blocks[mid]->file.size)) { result = EEXIST; break; } left = mid + 1; } } if (result != 0) { char buff1[256]; char buff2[256]; logWarning("file: "__FILE__", line: %d, " \ "node overlap, current trunk entry: %s, " \ "existed trunk entry: %s", __LINE__, \ trunk_info_dump(pTrunkInfo, buff1, sizeof(buff1)), \ trunk_info_dump(blocks[mid], buff2, sizeof(buff2))); } return result; } static int trunk_free_block_realloc(FDFSBlockArray *pArray, const int new_alloc) { FDFSTrunkFullInfo **blocks; int result; blocks = (FDFSTrunkFullInfo **)realloc(pArray->blocks, \ new_alloc * sizeof(FDFSTrunkFullInfo *)); if (blocks == NULL) { result = errno != 0 ? errno : ENOMEM; logError("file: "__FILE__", line: %d, " \ "malloc %d bytes fail, " \ "errno: %d, error info: %s", __LINE__, \ (int)(new_alloc * sizeof(FDFSTrunkFullInfo *)), result, STRERROR(result)); return result; } pArray->alloc = new_alloc; pArray->blocks = blocks; return 0; } static int trunk_free_block_do_insert(FDFSTrunkFullInfo *pTrunkInfo, \ FDFSBlockArray *pArray) { int left; int right; int mid; int pos; int result; if (pArray->count >= pArray->alloc) { if ((result=trunk_free_block_realloc(pArray, \ pArray->alloc == 0 ? TRUNK_FREE_BLOCK_ARRAY_INIT_SIZE \ : 2 * pArray->alloc)) != 0) { return result; } } if (pArray->count == 0) { pArray->blocks[pArray->count++] = pTrunkInfo; return 0; } if (pTrunkInfo->file.offset < pArray->blocks[0]->file.offset) { memmove(&(pArray->blocks[1]), &(pArray->blocks[0]), \ pArray->count * sizeof(FDFSTrunkFullInfo *)); pArray->blocks[0] = pTrunkInfo; pArray->count++; return 0; } right = pArray->count - 1; if (pTrunkInfo->file.offset > pArray->blocks[right]->file.offset) { pArray->blocks[pArray->count++] = pTrunkInfo; return 0; } left = 0; mid = 0; while (left <= right) { mid = (left + right) / 2; if (pArray->blocks[mid]->file.offset > pTrunkInfo->file.offset) { right = mid - 1; } else if (pArray->blocks[mid]->file.offset == \ pTrunkInfo->file.offset) { char buff[256]; logWarning("file: "__FILE__", line: %d, " \ "node already exist, trunk entry: %s", \ __LINE__, trunk_info_dump(pTrunkInfo, \ buff, sizeof(buff))); return EEXIST; } else { left = mid + 1; } } if (pTrunkInfo->file.offset < pArray->blocks[mid]->file.offset) { pos = mid; } else { pos = mid + 1; } memmove(&(pArray->blocks[pos + 1]), &(pArray->blocks[pos]), \ (pArray->count - pos) * sizeof(FDFSTrunkFullInfo *)); pArray->blocks[pos] = pTrunkInfo; pArray->count++; return 0; } int trunk_free_block_insert(FDFSTrunkFullInfo *pTrunkInfo) { int result; FDFSTrunkFileIdentifier target; FDFSTrunksById *pTrunksById; FILL_FILE_IDENTIFIER(target, pTrunkInfo); pTrunksById = (FDFSTrunksById *)avl_tree_find(&tree_info_by_id, &target); if (pTrunksById == NULL) { pTrunksById = (FDFSTrunksById *)malloc(sizeof(FDFSTrunksById)); if (pTrunksById == NULL) { result = errno != 0 ? errno : ENOMEM; logError("file: "__FILE__", line: %d, " \ "malloc %d bytes fail, " \ "errno: %d, error info: %s", \ __LINE__, (int)sizeof(FDFSTrunksById), \ result, STRERROR(result)); return result; } memset(pTrunksById, 0, sizeof(FDFSTrunksById)); memcpy(&(pTrunksById->trunk_file_id), &target, \ sizeof(FDFSTrunkFileIdentifier)); if (avl_tree_insert(&tree_info_by_id, pTrunksById) != 1) { result = errno != 0 ? errno : ENOMEM; logError("file: "__FILE__", line: %d, " \ "avl_tree_insert fail, " \ "errno: %d, error info: %s", \ __LINE__, result, STRERROR(result)); return result; } } return trunk_free_block_do_insert(pTrunkInfo, \ &(pTrunksById->block_array)); } int trunk_free_block_delete(FDFSTrunkFullInfo *pTrunkInfo) { int result; int left; int right; int mid; int move_count; FDFSTrunkFileIdentifier target; FDFSTrunksById *pTrunksById; char buff[256]; FILL_FILE_IDENTIFIER(target, pTrunkInfo); pTrunksById = (FDFSTrunksById *)avl_tree_find(&tree_info_by_id, &target); if (pTrunksById == NULL) { logWarning("file: "__FILE__", line: %d, " \ "node NOT exist, trunk entry: %s", \ __LINE__, trunk_info_dump(pTrunkInfo, \ buff, sizeof(buff))); return ENOENT; } result = ENOENT; mid = 0; left = 0; right = pTrunksById->block_array.count - 1; while (left <= right) { mid = (left + right) / 2; if (pTrunksById->block_array.blocks[mid]->file.offset > \ pTrunkInfo->file.offset) { right = mid - 1; } else if (pTrunksById->block_array.blocks[mid]->file.offset == \ pTrunkInfo->file.offset) { result = 0; break; } else { left = mid + 1; } } if (result == ENOENT) { logWarning("file: "__FILE__", line: %d, " \ "trunk node NOT exist, trunk entry: %s", \ __LINE__, trunk_info_dump(pTrunkInfo, \ buff, sizeof(buff))); return result; } move_count = pTrunksById->block_array.count - (mid + 1); if (move_count > 0) { memmove(&(pTrunksById->block_array.blocks[mid]), \ &(pTrunksById->block_array.blocks[mid + 1]), \ move_count * sizeof(FDFSTrunkFullInfo *)); } pTrunksById->block_array.count--; if (pTrunksById->block_array.count == 0) { free(pTrunksById->block_array.blocks); if (avl_tree_delete(&tree_info_by_id, pTrunksById) != 1) { memset(&(pTrunksById->block_array), 0, \ sizeof(FDFSBlockArray)); logWarning("file: "__FILE__", line: %d, " \ "can't delete block node, trunk info: %s", \ __LINE__, trunk_info_dump(pTrunkInfo, buff, \ sizeof(buff))); return ENOENT; } } else { if ((pTrunksById->block_array.count < \ pTrunksById->block_array.alloc / 2) && \ (pTrunksById->block_array.count > \ TRUNK_FREE_BLOCK_ARRAY_INIT_SIZE / 2)) //small the array { if ((result=trunk_free_block_realloc( \ &(pTrunksById->block_array), \ pTrunksById->block_array.alloc / 2)) != 0) { return result; } } } return 0; } static int block_tree_print_walk_callback(void *data, void *args) { FILE *fp; FDFSBlockArray *pArray; FDFSTrunkFullInfo **pp; FDFSTrunkFullInfo **ppEnd; fp = (FILE *)args; pArray = &(((FDFSTrunksById *)data)->block_array); /* { FDFSTrunkFileIdentifier *pFileIdentifier; pFileIdentifier = &(((FDFSTrunksById *)data)->trunk_file_id); fprintf(fp, "%d %d %d %d %d", \ pFileIdentifier->path.store_path_index, \ pFileIdentifier->path.sub_path_high, \ pFileIdentifier->path.sub_path_low, \ pFileIdentifier->id, pArray->count); if (pArray->count > 0) { fprintf(fp, " %d", pArray->blocks[0]->file.offset); if (pArray->count > 1) { fprintf(fp, " %d", pArray->blocks[pArray->count-1]-> \ file.offset + pArray->blocks[pArray->count-1]->\ file.size); } } fprintf(fp, "\n"); return 0; } */ /* { FDFSTrunkFullInfo **ppPrevious; if (pArray->count <= 1) { return 0; } ppPrevious = pArray->blocks; ppEnd = pArray->blocks + pArray->count; for (pp=pArray->blocks + 1; ppfile.offset >= (*pp)->file.offset) { fprintf(fp, "%d %d %d %d %d %d\n", \ (*ppPrevious)->path.store_path_index, \ (*ppPrevious)->path.sub_path_high, (*ppPrevious)->path.sub_path_low, \ (*ppPrevious)->file.id, (*ppPrevious)->file.offset, (*ppPrevious)->file.size); fprintf(fp, "%d %d %d %d %d %d\n", \ (*pp)->path.store_path_index, \ (*pp)->path.sub_path_high, (*pp)->path.sub_path_low, \ (*pp)->file.id, (*pp)->file.offset, (*pp)->file.size); } ppPrevious = pp; } return 0; } */ ppEnd = pArray->blocks + pArray->count; for (pp=pArray->blocks; pppath.store_path_index, \ (*pp)->path.sub_path_high, (*pp)->path.sub_path_low, \ (*pp)->file.id, (*pp)->file.offset, (*pp)->file.size); } return 0; } int trunk_free_block_tree_print(const char *filename) { FILE *fp; int result; fp = fopen(filename, "w"); if (fp == NULL) { result = errno != 0 ? errno : EIO; logError("file: "__FILE__", line: %d, " \ "open file %s fail, " \ "errno: %d, error info: %s", __LINE__, \ filename, result, STRERROR(result)); return result; } avl_tree_walk(&tree_info_by_id, block_tree_print_walk_callback, fp); fclose(fp); return 0; }