fastdfs/storage/trunk_mgr/trunk_free_block_checker.c

546 lines
12 KiB
C

/**
* 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.csource.org/ for more detail.
**/
//trunk_free_block_checker.c
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#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; pp<ppEnd; pp++)
{
if ((*ppPrevious)->file.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; pp<ppEnd; pp++)
{
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);
}
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;
}