内存数据表和内存索引通用结构(基于C++) --Memory Table Interface Embed In Your Application

很多都会把数据存放到内存中时候,以便查询和访问快速,但是每次编写都需要重新编写查询、存储、索引建立的模块会非常麻烦,本文中提供了一个类似内存数据库的内存表通用模式,内存数据存放、查找等提供通用的接口,大大提高了开发效率和索引访问的效率。


采用面向对象的思想  提供一个公用的类,cMTIData,提供类似于数据  建表结构、建索引、插入数据、hash 索引查找、打印表全部内容、  按照索引查找结果、预解析索引模式查找  等方法,提高后续编码的扩展性和便捷性。针对上面的结构我个人定义为:Memory Table Interface Embed In Your Application。


有什么想法和意见都可以发送邮件到yijiyong100@163.com 进行交流。


具体的代码实现和定义:

cMTIData.h


/*<! 计费依据获取从内存表获取数据存储,查找优化 added by yijy 2013.03.27 end */
/*<! (Memory Table Interface Embed In Your Application) begin */

#define MTI_R_INIT_FLAG             'Y'     //单条记录被初始化的标志
#define MTI_Y_FLAG                  'Y'     //有效或者已经被初始化的标志

#define MTI_CONFICT_Y_FLAG            'Y'     //索引键值区存在冲突
#define MTI_CONFICT_N_FLAG            'N'     //索引键值区不存在冲突

#define MTI_MAX_VALUE_LEN           50     //单个字段值 最长不超过 此数值,动态申请空间时使用,只适合加载小字段数据,不能加载备注等字段数据
#define MTI_MAX_VALUE_RLEN          MTI_MAX_VALUE_LEN+1 //定义数组的长度          
#define MTI_MAX_FIELD               60      //最大的字段的个数
#define MTI_MAX_FIELDNAME_LEN       30      //字段名最大的长度
#define MTI_H1_INDEX_NUM            999     //高三位存储数值
#define MTI_H2_INDEX_NUM            9999    //中三位存储数值      
#define MTI_H3_INDEX_NUM            9999    //低三位存储数值   
#define MTI_HAHS_NUM                10000   //定义一个hash_num ,数组的下标可以是 0-9999

#define MTI_ERRCODE_NOTABLENAME            1000 //没有指定表名
#define MTI_ERRCODE_FILEDLEN               1001 //表字段相关信息错误
#define MTI_ERRCODE_CREATEIDX              1002 //创建表的索引失败
#define MTI_ERRCODE_NOFIELD                1003 //没有此字段
#define MTI_ERRCODE_FILEDOUTRANGE          1004 //设置的字段的位置越界
#define MTI_ERRCODE_RECORDNOTINITALED      1005 //数据存储记录没有被初始化,存储数据的内存空间还没有被申请
#define MTI_ERRCODE_CREATERECORD           1006 //创建表的数据记录失败
#define MTI_ERRCODE_NOTALLINITRECORD       1008 //记录中的字段没有都被填充,此条记录的字段值不完整。
#define MTI_ERRCODE_INDEXNOTINITALED       1009 //数据索引指针没有被初始化
#define MTI_ERRCODE_INDEXNOTFOUND          1010 //根据字段名,没有找到对应的索引
#define MTI_ERRCODE_REPEATFIELD            1011 //表中有重复字段
#define MTI_ERRCODE_CREATEINDEXRECORD      1012 //创建表的数据记录失败
#define MTI_ERRCODE_PREMEMNEWNUMERR        1014 //一次性将数据量大预申请的记录数不能为0
#define MTI_ERRCODE_PREMEMNEWNULL          1015 //一次性将数据量大的预申请失败
#define MTI_ERRCODE_CREATEPREDATAOUT       1016 //在预先申请的内存区数据越界
#define MTT_ERRCODE_FILEDVALUEEXCEED       1017 //字段长度超长,字段的长度不能超过 MTI_MAX_VALUE_LEN


#define MTI_PRINT_LINE_INFO "------------------------------"

typedef char ** MTI_ROW;            //一条结果集各个字段指针
struct MTI_RECORD
{
    char * row_detail[MTI_MAX_FIELD+1];    //一条结果集各个字段指针
    //动态申请根据字段数量动态一条记录的申请空间,但是存储空间连续的
    char *rowContent;
    
    int  num;                        //一条结果集中存储字段的个数
    char flag;                       //该条记录的是否被初始化            'Y'
    char filedFlag[MTI_MAX_FIELD+1]; //记录中的某个值是否被填充值        'Y'
    MTI_RECORD * next;
    void clear();//新增置空 函数
};
typedef MTI_RECORD * MTI_RD; //一行记录数据

struct MTI_FILED_BUF
{
    char buf[MTI_MAX_VALUE_LEN+1];
};

//每个字段名称的定义,字段的最小元素
struct MTI_FIELD_ELM
{
    char name[MTI_MAX_FIELDNAME_LEN+1];
    int  type; //目前在数据库中存储都按照 字符串来存储 此字段未启用
    int  pos;  //字段存储的位置
};

//所有字段的定义集合
struct MTI_FIELD
{
    MTI_FIELD_ELM field[MTI_MAX_FIELD];
    int num;
    char flag;
};  

//字段的节点的排序比较函数
int MTI_FIELD_Comp(const void *p1,const void *p2);


//索引记录的最小单元
struct MTI_INDEX_ITEM
{
  MTI_RECORD  * _t;          // 指向数据真实存储区指针
    MTI_INDEX_ITEM * next;     // 下一个索引记录的指针地址
    char key[MTI_MAX_VALUE_LEN+1]; //索引的键值
    char flag;  //索引记录是否有效 'Y' 有效
    void clear();//新增置空 函数
};
typedef MTI_INDEX_ITEM * MTI_RESULT;

//索引记录的节点
struct MTI_INDEX_NODE
{
    //冲突的判断,其中是否需要判断冲突,如果是第一次插入,将插入记录的键值拷贝到key0 中,并将 confict_flag 的值置为 'N'
    //其他同样键值的插入的时候,需要判断其中的key0和key值是否相同,如果不同,则将confict_flag = 'Y'(存在冲突)
    char key0[MTI_MAX_VALUE_LEN+1]; //第一个插入到此地址的键值
    char conflict_flag; //索引节点是否有冲突的标志,此键值的数据是否存在冲突的标志,其中可以插入数据节点时
  MTI_INDEX_ITEM * index_item;
  char flag;//是否被初始化
  MTI_INDEX_ITEM * tail;
  void clear();//新增置空 函数
};
typedef MTI_INDEX_NODE * MTI_INODE; //定义其中的节点



/*<!记录 哪些索引节点被用到,方便后续释放内存用 */
struct MTI_INDEX_RECORD
{
    MTI_INDEX_NODE   *   _t;
    MTI_INDEX_RECORD * next;
    void clear();//新增置空 函数
};


//外部接口查询获取结果使用索引中间记录。
struct MTI_IR
{
    MTI_IR();//构造函数
    MTI_RESULT pMR;
    char conflict_flag;
    MTI_INODE pID;
    char key[MTI_MAX_VALUE_LEN+1]; //其中的查询的键值
};

struct MTI_INDEX
{
    MTI_INDEX();
    MTI_INDEX_NODE hash0[MTI_HAHS_NUM];  //索引数组 索引下标 0 ~ 9999
    char idx_filed_name[MTI_MAX_FIELDNAME_LEN+1]; //索引字段名
    char table_name[MTI_MAX_FIELDNAME_LEN+1]; //表名
    char flag; //标志
    MTI_INDEX_RECORD * top;//记录 哪些索引节点被用到,方便后续释放内存用,采用链式栈的结构
    MTI_INDEX * next;
    MTI_INDEX_ITEM * preI;  //索引预先申请的首地址
    void clear();//新增置空 函数
};
typedef MTI_INDEX * MTI_INDEX_HANDLE; //直接指向索引存储区地址,预解析查找使用

//(Memory Table Interface Embed In Your Application) class define 公用类定义,暂时只支持单字段 索引字段
class cMTIData
{
public:
    //把索引区、存储区的构造都要做好初始化
    cMTIData();
    cMTIData(char * tableName);
    void setTableName(char * tableName);
    char * getTableName();//返回表名
    virtual ~cMTIData();
    
    char table_name[MTI_MAX_FIELDNAME_LEN+1]; //存储的相关的表名,仅作备注标识。
    
private:
    MTI_INDEX  * index; //索引存储区首指针
    MTI_RECORD * data;  //数据存储区首指针
    MTI_RECORD * tail;  //当前数据区的尾指针
    MTI_FIELD  F;       //表字段的相关信息
    
    int  errCode;
    char errInfo[1024+1];
    char preDataFalg; //数据存储区一次性预先申请
    int  preDataNum;  //数据预先申请的条数
    char *       preDataX;  //一个超级大数组的地址首地址,一次性预先申请的首地址
    MTI_RECORD * preDataR;  //记录预先申请的首地址
    
public:    
    
    //1.1、把字段的名字和位置存储到,把字段名放在一个字符串中 按照逗号分割或者其他分隔符进行分
    //类似于构建表结构:
    int initFieldInfo(char *fieldNameStr,char);
    //1.2获取表字段的个数
    int getFieldNum();
    
    //2.1、创建索引,一定要先创建索引指定索引名称,插入数据的时候,对应索引区的初始化
    //后续需要支持多个索引时可以使用多态函数,如果想用索引,必须先建立索引名称,暂不支持表记录插入完后,再建立索引
    //类似于创建索引
    int createIndex(char *fieldName);
    
    //2.2、对索引字段查找进行预解析,索引查找句柄直接指向索引字段的索引数据首地址
    int prepareIndex(char *fieldName,MTI_INDEX_HANDLE * pH);
    
    //3、初始化构造 MTI_RECORD
    //构造生成一条记录,并将各个字段进行初始化并申请空间
    int newRecord(MTI_RECORD ** pR,int iRec = 0);
    //数据量较大情况下,需要进行预先一次性分配申请,其中r_num为记录数
    int preDataAllNew(int r_num);
    
    //4、记录的MTI_RECORD各个值方法
    //给记录的各个字段赋值
    int setRecordFiled(MTI_RECORD * pR,int pos,char * value);
    int setRecordFiled(MTI_RECORD * pR,char * fieldName,char * fieldValue);
    
    //5、将数据放入到数据存储区,并在索引区建立索引,插入数据时,需要检查数据的完整性(是否被填充)
    //如果其中有一个字段没有被填充,则其中的顺序则认为是无效的记录。
    int insertRecord(MTI_RECORD * pR,int iRec = 0);
    
    //6.1、查找的函数(使用索引查找):根据索引名和键值,来查找对应记录,利用hash 函数的 三级索引区来查找,硬解析查找
    int doIndexSearch(char * filedName,char * key,MTI_INODE* mR);
    
    //7.1、从根据索引查找的索引结果区中获取数据真实的一条记录,记得使用索引后,一定要传入参数    
    //从里面获取数据遍历进行获取数据,key值一定要和查找句柄 的键值保持一致(函数内部需要检测hash冲突的key)
    int execIndexHandleSearch(MTI_IR * pIR,MTI_INDEX_HANDLE pH,char * key);
    MTI_ROW fetchGetIndexRow(MTI_IR * pIR);
    
    
    //7.2、全表扫描,直接全表扫描,直接从数据存储区进行遍历
    void initGetAllRow(MTI_RECORD ** pMR); //先要找到数据存储区的首指针
    MTI_ROW fetchGetAllRow(MTI_RECORD ** pMR); //根据数据存储区的首指针来进行遍历,两个函数动作联合起来用
    
    //8.1、清空数据区和索引区 并释放对应的存储空间
    void truncate();
    
    //8.2、清空数据区和索引区 并释放对应的存储空间,并删除索引结构,表结构等相关信息,相当于drop table
    void drop();
    
    //9、辅助类函数:
    //9.1、打印当前记录的值所有字段值,测试用
    int printRecord(MTI_RECORD * pR);
    
    //9.1、打印当前表的所有数据内容
    int printAllInfo();
    
    //9.1、打印根据索引超找到的数据内容
    int printResult(MTI_INODE pMR,char *key);
    
    //9.1、根据索引句柄查找键值并打印出相关的内容
    void printIndexHandleSearch(MTI_INDEX_HANDLE pH,char * key);
    
    //9.1、打印错误信息
    char * getErrInfo();
    
    //9.1、打印错误代码
    int getErrCode();
    
private:    
    //hash数值函数
    unsigned long ELFHash(char *str);
    
    //按照字段名获取其中的字段值
    int getRecordFiled(MTI_RECORD * pR,char * fieldName,char * fieldValue);
    
    //利用elfhash的函数,返回的 unsigned long , 返回值长度不足 10 位时,自动补齐11位。
    //来构造生成三级索引的值idx1 idx2 idx3 三者的值
    void getH1H2H3Index(char *str,int &idx1,int & idx2,int &idx3);
    
    //将字符串中的数值,解析到 idx1 idx2 idx3 三者的值,其中 str 是纯字符串数值,调用前注意
    void parseH1H2H3(char *str,int &idx1,int & idx2,int &idx3);
    
    //查找的函数(使用预解析句柄查找):需要对预先查找的字段进行预解析,利用hash 函数的 三级索引区来查找。
    MTI_INODE doIndexHandleSearch(MTI_INDEX_HANDLE pH,char * key);
    
    //查找其中对应字段的索引存储区的地址
    int findIndexHandle(char * filedName,MTI_INDEX_HANDLE * pH);
    
    //检查MTI_RECORD 中的字段是否都被填充
    int checkField(char *);
    //获取其中的 filedName 对应的字段存储内容
    MTI_FIELD_ELM * getField(char *filedName);
    
    //从MTI_Index_Hanlde中查找数据
    MTI_INODE findFromIndexHandle(MTI_INDEX_HANDLE pH,char * key);
    
    //把表字段以及头部分打印出来
    void printHeadInfo();
    
    //打印结尾部分信息
    void printTailInfo();
    
    //打印信息返回条数
    void printRecordNum(unsigned int num);
    
    //冲突检测函数 0 没有冲突,非0 有冲突,入参为需要检测的键值
    int conflict_check(MTI_RESULT pMR,char * key);
    
    //检查MTI_RECORD 中的字段是否都被填充
    int checkRecord(MTI_RECORD * pR);
    
    //根据数据记录,根据表中索引的个数,建立对应的索引,并插入数据索引记录
    int insertIndexItem(MTI_RECORD * pR,int iRec = 0);

    //把哪些索引节点使用了,放入到一个栈的结构中
    int pushIndexNodeRecord(MTI_INDEX_RECORD ** top,MTI_INDEX_NODE * _t);
    
    //删除释放索引区
    void freeIndex();
    
    //删除释放数据区
    void freeData();
    
    //辅助类 清表时使用 函数:去掉索引和表结构相关信息
    void clearTableStruct();
    
    void setErrInfo( int errCode,char * format, ... );
    
};
/*<! (Memory Table Interface Embed In Your Application) end */



cMTIData.cpp


/*<! (Memory Table Interface Embed In Your Application) begin */
/*<! C++中 delete 操作后,地址中内容可能没有被置空或者默认,可能后续重新申请空间时会继续使用此块空间*/
/*<! 释放相关内存delete之前,务必将其部分成员变量置空或设置为默认值,防止后续重新使用到此块空间时出现异常,或者 coredown的情况*/
//组织调用clear函数的关系时索引区、数据区、存储区的先后顺序一定要慎重组织
//新增置空 函数(一定在delete此变量之前调用clear函数)
void MTI_RECORD::clear()
{
    int i =0;
    for(i = 0;i<num;i++)
    {
        row_detail[i]=NULL; //初始化为空
        filedFlag[i]='0';   //初始化为0
    }
    rowContent = NULL;
    next =NULL;
    flag = '0';
    num=0; //最后将num置为0
    return;
}

//新增置空 函数(一定在delete此变量之前调用clear函数)
void MTI_INDEX_ITEM::clear()
{
    flag='0';
    memset(key,0,sizeof(key));
    _t=NULL;
    next=NULL;
    return;
}

//新增置空 函数(一定在delete此变量之前调用clear函数)
void MTI_INDEX_NODE::clear()
{
    memset(key0,0,sizeof(key0));
    conflict_flag = '0';
  index_item=NULL;
  flag='0';//是否被初始化
  tail=NULL;
 
    return;
}

//新增置空 函数(一定在delete此变量之前调用clear函数)
void MTI_INDEX_RECORD::clear()
{
    
    _t=NULL;
    next=NULL;
    
    return;
}

//构造函数处理,新增。
MTI_INDEX::MTI_INDEX()
{
    top = NULL;//记录 哪些索引节点被用到,方便后续释放内存用,采用链式栈的结构
    next = NULL;
    
    //释放索引存储区
    preI = NULL;  //索引预先申请的首地址

    //基本变量初始化区
    memset(idx_filed_name,0,sizeof(idx_filed_name)); //索引字段名
    memset(table_name,0,sizeof(table_name)); //表名
    flag = '0'; //标志
    
    //将索引进行清空
    int i = 0;
    for(i=0;i<MTI_HAHS_NUM;i++)
    {
        hash0[i].clear();
    }
}

//新增置空 函数(一定在delete此变量之前调用clear函数)
void MTI_INDEX::clear()
{
    top = NULL;//记录 哪些索引节点被用到,方便后续释放内存用,采用链式栈的结构
    next = NULL;
    
    //释放索引存储区
    preI = NULL;  //索引预先申请的首地址

    //基本变量初始化区
    memset(idx_filed_name,0,sizeof(idx_filed_name)); //索引字段名
    memset(table_name,0,sizeof(table_name)); //表名
    flag = '0'; //标志
    
    //将索引进行清空
    int i = 0;
    for(i=0;i<MTI_HAHS_NUM;i++)
    {
        hash0[i].clear();
    }
    
    return;
}


//构造函数
cMTIData::cMTIData()
{
    index=NULL;
    data=NULL;
    tail=NULL;
    memset(&F,0,sizeof(MTI_FIELD));
    memset(table_name,0,sizeof(table_name));
    preDataFalg='0'; //数据存储区一次性预先申请
    preDataNum=0;  //数据预先申请的条数
    preDataX=NULL;
    preDataR=NULL;
    errCode=0;
    memset(errInfo,0,sizeof(errInfo));
}

cMTIData::cMTIData(char * tableName)
{
    tail=NULL;
    index=NULL;
    data=NULL;
    errCode=0;
    memset(errInfo,0,sizeof(errInfo));
    memset(&F,0,sizeof(MTI_FIELD));
    memset(table_name,0,sizeof(table_name));
    if(strlen(tableName)> MTI_MAX_FIELDNAME_LEN )
    {
        strncpy(table_name,tableName,MTI_MAX_FIELDNAME_LEN);
        table_name[MTI_MAX_FIELDNAME_LEN]='\0';
    }
    else
    {
        strcpy(table_name,tableName);
    }
    preDataFalg='0'; //数据存储区一次性预先申请
    preDataNum=0;  //数据预先申请的条数
    preDataX=NULL;
    preDataR=NULL;
}

//设置表名
void cMTIData::setTableName(char * tableName)
{
    memset(table_name,0,sizeof(table_name));
    if(strlen(tableName)> MTI_MAX_FIELDNAME_LEN )
    {
        strncpy(table_name,tableName,MTI_MAX_FIELDNAME_LEN);
        table_name[MTI_MAX_FIELDNAME_LEN]='\0';
    }
    else
    {
        strcpy(table_name,tableName);
    }
    return;
}

//获取表名
char * cMTIData::getTableName()
{
    return table_name;
}

//析构函数
cMTIData::~cMTIData()
{
}

//打印错误信息
char * cMTIData::getErrInfo()
{
    return errInfo;
}

//打印错误代码
int cMTIData::getErrCode()
{
    return errCode;
}

void cMTIData::setErrInfo( int iCode,char * format, ... )
{    
    //设置错误代码
    errCode = iCode;
        
    //设置错误信息
  memset(errInfo,0,sizeof(errInfo));
  va_list args;
  va_start(args, format);
  vsprintf(errInfo,format,args);
  va_end(args);
        
        
  #ifdef DEBUG
  printf("ErrCode[%d],ErrInfo[%s]\n",errCode,errInfo);
  #endif
 
  writeRunlog( 4, "cMTIData:ErrCode[%d],ErrInfo[%s]!\n",errCode,errInfo);
 
  return;
}

//字段的节点的排序比较函数
int MTI_FIELD_Comp(const void *p1,const void *p2)
{
    return strcmp((*(MTI_FIELD_ELM *)p1).name,(*(MTI_FIELD_ELM *)p2).name);
}

//1.1、把字段的名字和位置存储到,把字段名放在一个字符串中 按照逗号分割或者其他分隔符进行分
//类似于构建表结构:
int cMTIData::initFieldInfo(char *fieldNameStr,char split)
{
    memset(&F,0,sizeof(MTI_FIELD));
    if(strlen(table_name) == 0)
    {
        setErrInfo(MTI_ERRCODE_NOTABLENAME,"[%s][%d] table_name is not set.",__FILE__,__LINE__);
        return MTI_ERRCODE_NOTABLENAME;
    }
    if(strlen(fieldNameStr) < 1)
    {
        setErrInfo(MTI_ERRCODE_FILEDLEN,"[%s][%d] fieldNameStr[%s] is invalid.",__FILE__,__LINE__,fieldNameStr);
        return MTI_ERRCODE_FILEDLEN;
    }
    
    int FiledNum = charpos_num(fieldNameStr,split);
    FiledNum = FiledNum + 1; //分隔符的个数+1 等于总字段数
    
    if(FiledNum > MTI_MAX_FIELD)
    {
        setErrInfo(MTI_ERRCODE_FILEDLEN,"[%s][%d] fieldNameStr [%s] FiledNum [%d] can not exceed max num [%d].",__FILE__,__LINE__,fieldNameStr,FiledNum,MTI_MAX_FIELD);
        return MTI_ERRCODE_FILEDLEN;
    }
    char tmpFiledName[256];
    for(int i=0;i<FiledNum;i++)
    {
        memset(tmpFiledName,0,sizeof(tmpFiledName));
        getTextField(tmpFiledName,fieldNameStr,split,i+1);
        if(strlen(tmpFiledName) > MTI_MAX_FIELDNAME_LEN )
        {
            setErrInfo(MTI_ERRCODE_FILEDLEN,"[%s][%d] tmpFiledName[%s] len can not exceed [%d].",__FILE__,__LINE__,tmpFiledName,MTI_MAX_FIELDNAME_LEN);
            return MTI_ERRCODE_FILEDLEN;
        }
        //字段需要去空格
        strtrim(F.field[i].name,tmpFiledName);
        strupper(F.field[i].name); //转大写
        F.field[i].pos = i;
        
        F.num++;
    }
    
    
    MTI_FIELD  tmp; //声明一个临时变量
    memset(&tmp,0,sizeof(MTI_FIELD));
    memcpy(&tmp,&F,sizeof(MTI_FIELD));
    //对临时变量 tmp进行排序:
    qsort(tmp.field,tmp.num,sizeof(tmp.field[0]),MTI_FIELD_Comp);
    char lastFiledName[256];
    lastFiledName[0]=0;
    for(int j=0;j<tmp.num;j++)
    {
        if(strcmp(tmp.field[j].name,lastFiledName)!=0)
        {
            strcpy(lastFiledName,tmp.field[j].name);
        }
        else
        {
            setErrInfo(MTI_ERRCODE_REPEATFIELD,"[%s][%d] exist repeate FiledName [%s] .",__FILE__,__LINE__,lastFiledName);
            return MTI_ERRCODE_REPEATFIELD;
        }
    }
    
    
    //最后对F打上有效被初始化的标记
    F.flag= MTI_Y_FLAG;
    #ifdef DEBUG    
    printf("\n%s initFieldInfo sucess on table [%s],table field num [%d]\n",DEBUG_DICT_TAG_INFO,table_name,F.num);
    #endif
    
    return 0;
}

//1.2获取字段的个数
int cMTIData::getFieldNum()
{
    return F.num;
}


//查看字段是否是有效的字段
int cMTIData::checkField(char *filedName)
{
    if(filedName == NULL)
        return -1;
    char tmpfiledName[MTI_MAX_FIELDNAME_LEN+1];
    
    if(strlen(filedName) > MTI_MAX_FIELDNAME_LEN )
    {
            return -1;
    }
    memset(tmpfiledName,0,sizeof(tmpfiledName));
    strcpy(tmpfiledName,filedName);
    strupper(tmpfiledName); //转大写
    
    int iRet=-1;
    for(int i=0;i<F.num;i++)
    {
        if (strcmp(F.field[i].name,tmpfiledName) == 0)
        {
            iRet=0;
            break;
        }
    }
    return iRet;
}

MTI_FIELD_ELM * cMTIData::getField(char *filedName)
{
    if(filedName == NULL)
        return NULL;
    char tmpfiledName[MTI_MAX_FIELDNAME_LEN+1];
    
    if(strlen(filedName) > MTI_MAX_FIELDNAME_LEN )
    {
            return NULL;
    }
    memset(tmpfiledName,0,sizeof(tmpfiledName));
    strcpy(tmpfiledName,filedName);
    strupper(tmpfiledName); //转大写
    
    MTI_FIELD_ELM * itmp = NULL;
    for(int i=0;i<F.num;i++)
    {
        if (strcmp(F.field[i].name,tmpfiledName) == 0)
        {
            itmp = &(F.field[i]);
            break;
        }
    }
    return itmp;
}

//把哪些索引节点使用了,放入到一个栈的结构中,top 位栈首指针
int cMTIData::pushIndexNodeRecord(MTI_INDEX_RECORD ** top,MTI_INDEX_NODE * _t)
{
    MTI_INDEX_RECORD * s = new MTI_INDEX_RECORD;
    if(s == NULL)
    {
        setErrInfo(MTI_ERRCODE_CREATEINDEXRECORD,"[%s][%d] crate MTI_INDEX_RECORD is null.",__FILE__,__LINE__);
        return MTI_ERRCODE_CREATEINDEXRECORD;
    }
    s->_t   = _t;
    s->next = (*top);
    (*top)=s;
    return 0;
}
    
//2.1、创建索引,一定要先创建索引指定索引名称,插入数据的时候,对应索引区的初始化
//后续需要支持多个索引时可以使用多态函数
//类似于创建索引
int cMTIData::createIndex(char *fieldName)
{
    MTI_INDEX * tmpIndex = NULL;
    MTI_INDEX * iIndex= NULL;

    if(strlen(table_name) == 0)
    {
        setErrInfo(MTI_ERRCODE_NOTABLENAME,"[%s][%d] table_name is not set.",__FILE__,__LINE__);
        return MTI_ERRCODE_NOTABLENAME;
    }

    if(strlen(fieldName) > MTI_MAX_FIELDNAME_LEN )
    {
            setErrInfo(MTI_ERRCODE_FILEDLEN,"[%s][%d] createIndex fieldName[%s] len can not exceed [%d].",__FILE__,__LINE__,fieldName,MTI_MAX_FIELDNAME_LEN);
            return MTI_ERRCODE_FILEDLEN;
    }
    if(F.flag != MTI_Y_FLAG)
    {
            setErrInfo(MTI_ERRCODE_CREATEIDX,"[%s][%d] filed info is not initialed.",__FILE__,__LINE__);
            return MTI_ERRCODE_CREATEIDX;
    }
    if(checkField(fieldName))
    {
            setErrInfo(MTI_ERRCODE_NOFIELD,"[%s][%d] filed name [%s] can not be found.",__FILE__,__LINE__,fieldName);
            return MTI_ERRCODE_NOFIELD;
    }
    //printf("--yijy[%s][%d]\n",__FILE__,__LINE__);
    
    /*<! 创建索引 动态申请内存空间*/
    tmpIndex = new MTI_INDEX;
    if(tmpIndex == NULL)
    {
        setErrInfo(MTI_ERRCODE_CREATEIDX,"[%s][%d] new MTI_INDEX is null.",__FILE__,__LINE__);
        return MTI_ERRCODE_CREATEIDX;
    }

    
    //索引区的数据 初始化
    tmpIndex->next=NULL;
    tmpIndex->flag='0'; // 初始化
    memset(tmpIndex->idx_filed_name,0,sizeof(tmpIndex->idx_filed_name));
    memset(tmpIndex->table_name,0,sizeof(tmpIndex->table_name));

    //索引区的数据 赋值
    tmpIndex->flag = MTI_Y_FLAG;
    tmpIndex->next = NULL;
    strcpy(tmpIndex->idx_filed_name,fieldName);
    strupper(tmpIndex->idx_filed_name); //转大写
    strcpy(tmpIndex->table_name,table_name); //拷贝大写
    tmpIndex->top = NULL;//存储区哪些索引节点被使用,初始化为 空
    
    if(index == NULL)
    {
        index=tmpIndex;
    }
    else
    {
        iIndex=index;
        while((iIndex->next)!=NULL)
        {
            iIndex=iIndex->next;
        }
        iIndex->next = tmpIndex; //插入到队列尾部
    }
    
    #ifdef DEBUG
    printf("%s Create index field [%s] on table [%s] sucess ... \n",DEBUG_DICT_TAG_INFO,fieldName,table_name);
    #endif
    
    
    return 0;
}

//2.2、对索引字段查找进行预解析,索引查找句柄直接指向索引字段的索引数据首地址
int cMTIData::prepareIndex(char *fieldName,MTI_INDEX_HANDLE *pH)
{
    int iRet = findIndexHandle(fieldName,pH);
    
    #ifdef DEBUG
    if(iRet == 0)
    {
        printf("%s PrepareIndex field [%s] on table [%s] sucess ... \n",DEBUG_DICT_TAG_INFO,fieldName,table_name);
    }
    #endif
        
    return iRet;
}

//数据量较大情况下,需要进行预先一次性分配申请,其中r_num为记录数
int cMTIData::preDataAllNew(int r_num)
{
    if (r_num <=0)
    {
        return 0;    
    }
    
    //实际数据存储内容区一次性申请内存
    preDataX = new char[r_num*F.num*(MTI_MAX_VALUE_RLEN)];
    if(preDataX == NULL)
    {
        setErrInfo(MTI_ERRCODE_PREMEMNEWNULL,"[%s][%d] preDataX  is not allow null",__FILE__,__LINE__);
        return MTI_ERRCODE_PREMEMNEWNULL;
    }
    #ifdef DEBUG
    //printf("F.num[%d],r_num[%d]",F.num,r_num);
    #endif
    
    //为数据记录区建立一次性申请内存
    preDataR = new MTI_RECORD[r_num];
    if(preDataR == NULL)
    {
        setErrInfo(MTI_ERRCODE_PREMEMNEWNULL,"[%s][%d] preDataR is not allow null ,",__FILE__,__LINE__);
        return MTI_ERRCODE_PREMEMNEWNULL;
    }
    //为索引区节点一次性申请内存,如果存在索引区
    MTI_INDEX * iTmp=NULL;
    iTmp = index;    
    
    //遍历这个表上的索引区,把所有的索引记录生成
    while(iTmp!=NULL)
    {
        iTmp->preI = new MTI_INDEX_ITEM[r_num];
        if (iTmp->preI == NULL)
        {
            setErrInfo(MTI_ERRCODE_PREMEMNEWNULL,"[%s][%d] iTmp->preI is not allow null",__FILE__,__LINE__);
            return MTI_ERRCODE_PREMEMNEWNULL;
        }    
        iTmp=iTmp->next;
    }
    

    //实际存储区分配完毕,记录相关只并打上标志
    preDataNum = r_num;
    preDataFalg = MTI_Y_FLAG;
    
    return 0;
}
    
//3、初始化构造 MTI_RECORD
//构造生成一条记录,并将各个字段进行初始化并申请空间,iRec = 0 默认值
int cMTIData::newRecord(MTI_RECORD ** pR,int iRec)
{
    if(F.flag != MTI_Y_FLAG)
    {
            setErrInfo(MTI_ERRCODE_CREATERECORD,"[%s][%d] filed info is not initialed.",__FILE__,__LINE__);
            return MTI_ERRCODE_CREATERECORD;
    }
    //printf("[%s][%d]preDataNum[%d][%d]iRec[%d]\n",__FILE__,__LINE__,preDataNum,F.num,iRec);
    
    
    int i = 0;
    char * curPos =NULL;
    MTI_RECORD * tmppR = NULL;
    //如果数据量大的时候,此时需要将其中的数据,改为动态分配
    //如果iRec是0,每次都动态申请,如果是预先内存分配好的,则从其中
    if(preDataFalg !=MTI_Y_FLAG)
    {
        (*pR) = new MTI_RECORD;
        if((*pR) == NULL)
        {
            setErrInfo(MTI_ERRCODE_CREATERECORD,"[%s][%d] crate MTI_RECORD is null.",__FILE__,__LINE__);
            return MTI_ERRCODE_CREATERECORD;
        }
        
        tmppR = (*pR);
        
        tmppR->rowContent = new char[F.num*(MTI_MAX_VALUE_RLEN)];
        curPos= tmppR->rowContent;
        if(tmppR->rowContent == NULL)
        {
            setErrInfo(MTI_ERRCODE_CREATERECORD,"[%s][%d] create data record space tmppR->rowContent is null.",__FILE__,__LINE__);
            return MTI_ERRCODE_CREATERECORD;
        }
        memset(tmppR->rowContent,0,sizeof(tmppR->rowContent[0])*F.num);
        //为数据存储指针数组的内容赋值,同时初始化内部变量
        for(i=0;i<F.num;i++)
        {
            tmppR->row_detail[i]    = curPos; //指针数组地址赋值
            tmppR->row_detail[i][0] =0;
            tmppR->filedFlag[i] = '0'; //赋初值
            curPos=curPos+MTI_MAX_VALUE_RLEN;
        }
    }
    else
    {
        if(iRec > 0 && iRec <= preDataNum)
        {
            (*pR) = &(preDataR[iRec-1]);
            tmppR = (*pR);
            if(preDataFalg != MTI_Y_FLAG)
            {
                setErrInfo(MTI_ERRCODE_PREMEMNEWNULL,"[%s][%d] preDataX not initaled ,",__FILE__,__LINE__);
                return MTI_ERRCODE_PREMEMNEWNULL;
            }
            //为数据存储指针数组的内容赋值,同时初始化内部变量
            curPos = preDataX+(iRec-1)*(MTI_MAX_VALUE_RLEN)*F.num;
            for(i=0;i<F.num;i++)
            {
                tmppR->row_detail[i]    = curPos; //指针数组地址赋值
                tmppR->row_detail[i][0] =0;
                tmppR->filedFlag[i] = '0'; //赋初值
                curPos=curPos+MTI_MAX_VALUE_RLEN;
            }
        }
        else
        {
            setErrInfo(MTI_ERRCODE_CREATEPREDATAOUT,"[%s][%d] iRec[%d] out of range...",__FILE__,__LINE__,iRec);
            return MTI_ERRCODE_CREATEPREDATAOUT;
        }
    }
    
    tmppR->num=F.num; //记录字段数
    tmppR->flag = MTI_Y_FLAG; //初始化成功
    tmppR->next = NULL;
    
    return 0;
}
    
//4、记录的MTI_RECORD各个值方法
//给记录的各个字段赋值,按照字段位置
int cMTIData::setRecordFiled(MTI_RECORD * pR,int pos,char * value)
{
    //printf("[%s][%d]\n",__FILE__,__LINE__);
    if(pR == NULL || value == NULL)
    {
        setErrInfo(MTI_ERRCODE_RECORDNOTINITALED,"[%s][%d] record is not initaled, pR == NULL",__FILE__,__LINE__);
        return MTI_ERRCODE_RECORDNOTINITALED;
    }
  if(pR->flag != MTI_Y_FLAG)
    {
        setErrInfo(MTI_ERRCODE_RECORDNOTINITALED,"[%s][%d] record is not initaled, data memroy may not initaled",__FILE__,__LINE__);
        return MTI_ERRCODE_RECORDNOTINITALED;
    }
    if(pos < 0 || pos > F.num-1)
    {
        setErrInfo(MTI_ERRCODE_FILEDOUTRANGE,"[%s][%d] field pos[%d] is invalid.",__FILE__,__LINE__,pos);
        return MTI_ERRCODE_FILEDOUTRANGE;
    }
    if(strlen(value) > MTI_MAX_VALUE_LEN) //当字符串长度超出 MTI_MAX_VALUE_LEN 需要报错返回,字段插入失败
    {
        setErrInfo(MTT_ERRCODE_FILEDVALUEEXCEED,"[%s][%d] field value [%s] len can not exceed MTI_MAX_VALUE_LEN=[%d] ..",__FILE__,__LINE__,value,MTI_MAX_VALUE_LEN);
        return MTT_ERRCODE_FILEDVALUEEXCEED;
    }
    else
    {
        strcpy(pR->row_detail[pos],value);
    }
    pR->filedFlag[pos]=MTI_Y_FLAG; //打上被填充的标志
    //printf("[%s][%d]\n",__FILE__,__LINE__);
    return 0;
}
//给记录的各个字段赋值,按照字段名称
int cMTIData::setRecordFiled(MTI_RECORD * pR,char * fieldName,char * fieldValue)
{
    int iRet = 0;
    
    if(pR == NULL)
    {
        setErrInfo(MTI_ERRCODE_RECORDNOTINITALED,"[%s][%d] record is not initaled, pR == NULL",__FILE__,__LINE__);
        return MTI_ERRCODE_RECORDNOTINITALED;
    }
    
    MTI_FIELD_ELM * iTmp = NULL;
    if ( (iTmp = getField(fieldName)) == NULL)
    {
        setErrInfo(MTI_ERRCODE_NOFIELD,"[%s][%d] filed name [%s] can not be found.",__FILE__,__LINE__,fieldName);
        return MTI_ERRCODE_NOFIELD;
    }
    
    iRet=setRecordFiled(pR,iTmp->pos,fieldValue);
    
    return iRet;
}
//根据字段名称获取字段中的值
int cMTIData::getRecordFiled(MTI_RECORD * pR,char * fieldName,char * fieldValue)
{
    int iRet = 0;
    
    if(pR == NULL)
    {
        setErrInfo(MTI_ERRCODE_RECORDNOTINITALED,"[%s][%d] record is not initaled, pR == NULL",__FILE__,__LINE__);
        return MTI_ERRCODE_RECORDNOTINITALED;
    }
    
    MTI_FIELD_ELM * iTmp = NULL;
    if ( (iTmp = getField(fieldName)) == NULL)
    {
        setErrInfo(MTI_ERRCODE_NOFIELD,"[%s][%d] filed name [%s] can not be found.",__FILE__,__LINE__,fieldName);
        return MTI_ERRCODE_NOFIELD;
    }
    
    strcpy(fieldValue,pR->row_detail[iTmp->pos]);
    
    return iRet;
}

//检查MTI_RECORD 中的字段是否都被填充,都被填充此条记录才是有效的记录
int cMTIData::checkRecord(MTI_RECORD * pR)
{
    if(pR == NULL)
    {
        setErrInfo(MTI_ERRCODE_RECORDNOTINITALED,"[%s][%d] record is not initaled, pR == NULL",__FILE__,__LINE__);
        return MTI_ERRCODE_RECORDNOTINITALED;
    }
    if(pR->flag != MTI_Y_FLAG)
    {
        setErrInfo(MTI_ERRCODE_RECORDNOTINITALED,"[%s][%d] record is not initaled, data memroy may not initaled",__FILE__,__LINE__);
        return MTI_ERRCODE_RECORDNOTINITALED;
    }
    int i = 0;
    for(i=0;i<F.num;i++)
    {
        if(pR->filedFlag[i] != MTI_Y_FLAG)
        {
            setErrInfo(MTI_ERRCODE_NOTALLINITRECORD,"[%s][%d] the record field[%d] is not filled",__FILE__,__LINE__,i);
            return MTI_ERRCODE_NOTALLINITRECORD;
        }
    }
    return 0;
}
    
//根据数据记录,根据表中索引的个数,建立对应的索引,并插入数据索引记录
int cMTIData::insertIndexItem(MTI_RECORD * pR,int iRec)
{
    if(pR == NULL)
    {
        setErrInfo(MTI_ERRCODE_RECORDNOTINITALED,"[%s][%d] record is not initaled, pR == NULL",__FILE__,__LINE__);
        return MTI_ERRCODE_RECORDNOTINITALED;
    }
    if(pR->flag != MTI_Y_FLAG)
    {
        setErrInfo(MTI_ERRCODE_RECORDNOTINITALED,"[%s][%d] record is not initaled, pR.flag != Y",__FILE__,__LINE__);
        return MTI_ERRCODE_RECORDNOTINITALED;
    }
    
    //索引为空 或者 标志没有初始化 直接返回, 不插入索引
    if(index == NULL )
    {
        return 0;
    }
    if(index->flag!=MTI_Y_FLAG )
    {
        return 0;
    }

    MTI_INDEX * iTmp=NULL;
    int iRet = 0;
    MTI_INDEX_ITEM * tmpIdxItem= NULL;
    MTI_INDEX_ITEM * iIdxItem = NULL;
    MTI_INDEX_NODE * iIdxNodeTmp = NULL;
    
    //三级索引hash数值
    int idx1 = 0,idx2 = 0,idx3 = 0;
    
    char tmpIdxValue[MTI_MAX_VALUE_RLEN];
    
    memset(tmpIdxValue,0,sizeof(tmpIdxValue));
    
    iTmp = index;
    
    //遍历这个表上的索引区,把所有的索引记录生成
    while(iTmp!=NULL)
    {
        //取出记录中的对应的 索引字段的值
        memset(tmpIdxValue,0,sizeof(tmpIdxValue));
        if ( (iRet = getRecordFiled(pR,iTmp->idx_filed_name,tmpIdxValue)))
            return iRet;
            
        //建立此条数据索引记录
        //动态生成最小的索引记录元素
        tmpIdxItem = NULL;
        if(preDataFalg !=MTI_Y_FLAG)
        {
            tmpIdxItem = new MTI_INDEX_ITEM;
        }
        else
        {
            if(iRec > 0 && iRec <= preDataNum)
            {
                tmpIdxItem = &(iTmp->preI[iRec-1]);
            }
            else
                return -1;
        }
        if(tmpIdxItem == NULL)
        {
            setErrInfo(MTI_ERRCODE_CREATEIDX,"[%s][%d] createIndex new MTI_INDEX_ITEM is null.",__FILE__,__LINE__);
            return MTI_ERRCODE_CREATEIDX;
        }
        //索引区的最小记录的单元
        tmpIdxItem->next=NULL;
        tmpIdxItem->flag=MTI_Y_FLAG; // 初始化
        tmpIdxItem->_t=pR; //指向记录存储区的指针
        tmpIdxItem->key[0]=0;
        //拷贝键值
        strcpy(tmpIdxItem->key,tmpIdxValue); //很重要,索引最小记录单元中保存键值
        
        
        //获取三重hash索引的键值
        getH1H2H3Index(tmpIdxValue,idx1,idx2,idx3);
        
        
        iIdxNodeTmp = &(iTmp->hash0[idx3]);
        iIdxItem = iIdxNodeTmp->index_item;
        if(iIdxNodeTmp->flag != MTI_Y_FLAG)//若未有节点插入进去,此节点是初始化节点
        {
            iIdxNodeTmp->index_item = tmpIdxItem;
            iIdxNodeTmp->tail = tmpIdxItem;
            
            //记录插入的第一个键值时,将此键值保存下来
            iIdxNodeTmp->key0[0] = 0;
            strcpy(iIdxNodeTmp->key0,tmpIdxItem->key);
            
            //第一条记录时把冲突标志置为 N,没有冲突
            iIdxNodeTmp->conflict_flag=MTI_CONFICT_N_FLAG;
            
            //iIdxItem 当为空的时候,把索引记录插入.
            if ( iRet = (pushIndexNodeRecord(&(iTmp->top),iIdxNodeTmp)) )
                return iRet;
                
            iIdxNodeTmp->flag = MTI_Y_FLAG;
            
        }
        else
        {
            //当标志为 非冲突状态下时,检查新插入的数据和第一个键值是否相同,如果不同,则将conflict_flag 置为产生了冲突
            if(iIdxNodeTmp->conflict_flag==MTI_CONFICT_N_FLAG)
            {
                if(strcmp(iIdxNodeTmp->key0,tmpIdxItem->key) !=0)
                {
                    iIdxNodeTmp->conflict_flag=MTI_CONFICT_Y_FLAG;
                }
            }
            
            //把索引项插入到链表的最末尾
            iIdxNodeTmp->tail->next= tmpIdxItem;
            iIdxNodeTmp->tail = tmpIdxItem;
            
        }
        
        
        //printf("h1[%d],h2[%d],h3[%d]:tmpIdxItem->key[%s],h1h2h3 key0[%s],conflict_flag[%c]\n",idx1,idx2,idx3,tmpIdxItem->key,iTmp->hash1[idx1].hash2[idx2].hash3[idx3].key0,iTmp->hash1[idx1].hash2[idx2].hash3[idx3].conflict_flag);
        
        iTmp=iTmp->next;
        
    }
    
    return 0;
}
    
//5、将数据放入到数据存储区,并在索引区建立索引,插入数据时,需要检查数据的完整性(是否被填充)
//如果其中有一个字段没有被填充,则其中的顺序则认为是无效的记录。
int cMTIData::insertRecord(MTI_RECORD * pR,int iRec)
{
    int iRet=0;
    MTI_RECORD *iTmp = NULL;
    if(pR == NULL)
    {
        setErrInfo(MTI_ERRCODE_RECORDNOTINITALED,"[%s][%d] record is not initaled, pR == NULL",__FILE__,__LINE__);
        return MTI_ERRCODE_RECORDNOTINITALED;
    }
    if(pR->flag != MTI_Y_FLAG)
    {
        setErrInfo(MTI_ERRCODE_RECORDNOTINITALED,"[%s][%d] record is not initaled, pR.flag != Y",__FILE__,__LINE__);
        return MTI_ERRCODE_RECORDNOTINITALED;
    }
    
    //检查数据记录数据是否都被填充
    if(iRet = (checkRecord(pR)))
        return iRet;

    //建立索引并插入索引,如果没有索引直接返回值0,向下继续
    if(iRet = insertIndexItem(pR,iRec))
        return iRet;
    
    //将数据记录指针,插入到 数据存储区:
    if(data == NULL)
    {
        data = pR;
        tail = pR;
    }
    else
    {
        //当前尾巴的tail 下一个指向 新的pR
        tail->next= pR;
        tail=pR;
    }
    
    return 0;
}
//查找其中对应字段的索引存储区的地址
int cMTIData::findIndexHandle(char * filedName,MTI_INDEX_HANDLE * pH)    
{
    if(index == NULL)
    {
        setErrInfo(MTI_ERRCODE_INDEXNOTINITALED,"[%s][%d] index is not initaled, index == NULL",__FILE__,__LINE__);
        return MTI_ERRCODE_INDEXNOTINITALED;
    }
    if(index->flag != MTI_Y_FLAG)
    {
        setErrInfo(MTI_ERRCODE_INDEXNOTINITALED,"[%s][%d] index is not initaled. ",__FILE__,__LINE__);
        return MTI_ERRCODE_INDEXNOTINITALED;
    }
    
    if(filedName == NULL)
    {
        setErrInfo(MTI_ERRCODE_FILEDLEN,"[%s][%d] filedName is null. ",__FILE__,__LINE__);
        return MTI_ERRCODE_FILEDLEN;
    }
        
    char tmpfiledName[MTI_MAX_FIELDNAME_LEN+1];
    
    if(strlen(filedName) > MTI_MAX_FIELDNAME_LEN )
    {
            setErrInfo(MTI_ERRCODE_FILEDLEN,"[%s][%d] filedName[%s] len not allow  > [%d] ",__FILE__,__LINE__,filedName,MTI_MAX_FIELDNAME_LEN);
          return MTI_ERRCODE_FILEDLEN;
    }
    memset(tmpfiledName,0,sizeof(tmpfiledName));
    strcpy(tmpfiledName,filedName);
    strupper(tmpfiledName); //转大写
    
    
    MTI_INDEX * iTmp=NULL;
    
    iTmp = index;
    (*pH) = NULL; //初始化 为空
    while(iTmp !=NULL)
    {
        if(strcmp(iTmp->idx_filed_name,tmpfiledName) == 0) //找到对应索引字段的索引区
        {
            (*pH) = iTmp;
            break;
        }
        
        iTmp = iTmp->next;
    }
    
    if((*pH) != NULL)
    {
        return 0;
    }
    else
    {
        setErrInfo(MTI_ERRCODE_INDEXNOTFOUND,"[%s][%d] the index according to filedName  [%s] can not be found. ",__FILE__,__LINE__,filedName);
        return MTI_ERRCODE_INDEXNOTFOUND;
    }

}
//从索引句柄中查找数据值
MTI_INODE cMTIData::findFromIndexHandle(MTI_INDEX_HANDLE pH,char * key)
{
    int idx1=0,idx2=0,idx3=0;
    if(strlen(key) > MTI_MAX_VALUE_LEN) //键值超长则直接返回空
        return NULL;
        
    getH1H2H3Index(key,idx1,idx2,idx3); //获取三级hash键值
    //printf("idx1:%d idx2:%d idx3:%d\n",idx1,idx2,idx3);
    MTI_INODE tmp = &(pH->hash0[idx3]); //三级键值对应的索引区的处理
    if(tmp->conflict_flag == MTI_CONFICT_N_FLAG)
    {
        if(strcmp(tmp->key0,key) == 0)
            return tmp;
        else
            return NULL;
    }
    else
        return tmp;

}    
    
//6.1、查找的函数(使用索引查找):根据索引名和键值,来查找对应记录,利用hash 函数的 三级索引区来查找,硬解析查找
int cMTIData::doIndexSearch(char * filedName,char * key,MTI_INODE *mR)
{
    MTI_INDEX_HANDLE tmpH = NULL;
    int iRet = 0;
    if(  (iRet = findIndexHandle(filedName,&tmpH)) )
        return iRet;
    
    (*mR) = findFromIndexHandle(tmpH,key);
    
    return 0;
}


//查找的函数(使用预解析句柄查找):需要对预先查找的字段进行预解析,利用hash 函数的 三级索引区来查找。
MTI_INODE cMTIData::doIndexHandleSearch(MTI_INDEX_HANDLE pH,char * key)
{
    if (pH == NULL)
        return NULL;
    if (pH->flag ==MTI_Y_FLAG)
    {
     return findFromIndexHandle(pH,key);
    }
    else
        return NULL;
}
    
//7.1、先要找到索引节点存储区的索引记录第一个索引记录指针
int cMTIData::execIndexHandleSearch(MTI_IR * pIR,MTI_INDEX_HANDLE pH,char * key)
{
    if (pH == NULL || pIR == NULL || key == NULL)
    {
        return -1;
    }
    if (pH->flag !=MTI_Y_FLAG)
    {
        return -1;
    }
    pIR->pID=doIndexHandleSearch(pH,key);
    memset(pIR->key,0,sizeof(pIR->key));
    strcpy(pIR->key,key);
    if(pIR->pID != NULL)//不为空的时候
    {
        pIR->conflict_flag = pIR->pID->conflict_flag;
        pIR->pMR = pIR->pID->index_item;
    }
    else//为空的时候赋初值
    {
        pIR->pMR =NULL;
        pIR->conflict_flag='0';
    }
    return 0;
}


//7.2、从根据索引查找的索引结果区中获取数据真实的一条记录,记得使用索引后,一定要传入参数
MTI_ROW cMTIData::fetchGetIndexRow(MTI_IR * pIR)
{
    if(pIR->pMR == NULL)
        return NULL;
    if(pIR->conflict_flag != MTI_CONFICT_N_FLAG) //当对应的键值标志 不等于 没有冲突时,需要检测冲突,否则不需要检测冲突
    {
        while(conflict_check(pIR->pMR,pIR->key))
        {
            pIR->pMR = pIR->pMR->next;
            continue;
        }
        if(pIR->pMR == NULL)//如果已经为空了,则整个返回
         return NULL;
    }
    MTI_ROW tmp = (MTI_ROW)(pIR->pMR->_t->row_detail);
    
    #ifdef DICT_DEBUG
        printRecord(pIR->pMR->_t);
    #endif
    
    pIR->pMR = pIR->pMR->next;
    return tmp;
}
    
//7.2、全表扫描,没有入参时,直接全表扫描,直接从数据存储区进行遍历
void cMTIData::initGetAllRow(MTI_RECORD ** pMR)
{
    //指向其中的数据存储区首指针
    if(data == NULL)
        (*pMR)=NULL;
    else
        (*pMR) = data;
    return;    
}
//根据数据存储区的首指针来进行遍历
MTI_ROW cMTIData::fetchGetAllRow(MTI_RECORD ** pMR)
{
    if((*pMR) == NULL)
        return NULL;
    
    #ifdef DICT_DEBUG
        printRecord(*pMR);
    #endif
    MTI_ROW tmp = (MTI_ROW)((*pMR)->row_detail);
    (*pMR) = (*pMR)->next;
    
    return tmp;
}
    
//8.1、清空数据区和索引区 并释放对应的存储空间,并重置相关信息,类似于 truncate table
void cMTIData::truncate()
{
    //先释放索引区
    freeIndex();
    //再释放数据区
    freeData();
    
    return;
}

//8.2、清空数据区和索引区 并释放对应的存储空间,并删除索引结构,表结构等相关信息,相当于drop table
void cMTIData::drop()
{
    //三个函数的调用顺序不能变
    
    //先释放索引区
    freeIndex();
    
    //再释放数据区
    freeData();
    
    //辅助类 清表时使用 函数:去掉索引和表结构相关信息
    clearTableStruct();
    
    return;
}

    
//辅助类 清表时使用 函数:
//删除释放索引区
void cMTIData::freeIndex()
{
    MTI_INDEX * pI = index;
    MTI_INDEX * pItmp =NULL;
    
    MTI_INDEX_ITEM * pIT    = NULL;
    MTI_INDEX_ITEM * pITtmp = NULL;
    MTI_INDEX_RECORD * pIR = NULL;
    MTI_INDEX_RECORD * pIRtmp = NULL;
    while(pI!= NULL)
    {
        
        pIR = pI->top; //被使用的索引节点首节点(栈的链式结构)
        while(pIR != NULL)
        {        
            pIT = pIR->_t->index_item;
            
            //重新把索引记录的节点 初始化
            pIR->_t->index_item = NULL;
            pIR->_t->conflict_flag = '0';
            memset(pIR->_t->key0,0,sizeof(pIR->_t->key0));
            while(pIT != NULL)
            {
                pITtmp = pIT->next;
                
                pIT->clear(); //置空相关区域
                delete pIT; //释放索引记录区信息的指针
                
                pIT = pITtmp;
            }
            pIRtmp = pIR->next;
            
            pIR->_t->clear(); //置空相关区域
            pIR->clear(); //置空相关区域
            
            delete pIR;
            
            pIR = pIRtmp;
        }
        
        pI->top =  NULL;//最后把当前索引 被使用的索引节点首节点(栈的链式结构) 赋值为空
        
        pItmp=pI->next;
        
        if(preDataFalg == MTI_Y_FLAG) //如果是预申请模式
        {
            if(pI->preI != NULL)
                delete [] pI->preI;
            pI->preI = NULL;
        }
        
        pI=pItmp;
    }
    
    return;
}
    
//辅助类 清表时使用 函数:
void cMTIData::freeData()
{
    MTI_RECORD * pD = data;
    MTI_RECORD * pDtmp =NULL;
    int i = 0;
        
    
    while(pD!= NULL)
    {
            pDtmp=pD->next;
            
            delete [] pD->rowContent; //删除动态申请的二维数组
            
            pD->clear();//置空相关数据区
            delete pD; //释放当前记录区当前指针
        
            pD=pDtmp;
    
    }
    if (preDataFalg == MTI_Y_FLAG)//预申请模式直接将一次性申请的内存数据区释放
    {
        if(preDataX!=NULL)
        {
            delete [] preDataX;
            preDataX=NULL;
        }
        if(preDataR!=NULL)
        {
            delete [] preDataR;
            preDataR=NULL;
        }
    }
        
    data = NULL;
    tail = NULL;
    
    return;
}

//辅助类 清表时使用 函数:去掉索引和表结构相关信息
void cMTIData::clearTableStruct()
{
    //清除索引结构区
    MTI_INDEX * pI = index;
    MTI_INDEX * pItmp =NULL;
    
    while(pI!= NULL)
    {
        pItmp=pI->next;
        
        pI->clear();//置空相关区域指针
        delete pI;
        
        pI=pItmp;
    }
    index=NULL;
    
    //清空表结构相关信息
    memset(&F,0,sizeof(MTI_FIELD));
    
    memset(table_name,0,sizeof(table_name));
    
    preDataFalg='0'; //数据存储区一次性预先申请
    preDataNum=0;  //数据预先申请的条数
    preDataX=NULL;
    preDataR=NULL;
    
    return;
}

//把表字段以及头部分打印出来
void    cMTIData::printHeadInfo()
{
    char tmpStr[2048];
    memset(tmpStr,0,sizeof(tmpStr));
    
    for(int i=0;i<F.num;i++)
    {
        strcat(tmpStr,F.field[i].name);
        if ( i != F.num - 1)
        strcat(tmpStr,"  ");
    }
    
    printf("%s\n%s\n",tmpStr,MTI_PRINT_LINE_INFO);
    return;
}
    
//打印结尾部分信息
void    cMTIData::printTailInfo()
{
    
    printf("%s\n",MTI_PRINT_LINE_INFO);
    return;
}
    
//打印信息返回条数
void    cMTIData::printRecordNum(unsigned int num)
{
    printf("%d rows selected\n\b",num);
    return;
}

//打印当前记录的值所有字段值,测试用
int cMTIData::printRecord(MTI_RECORD * pR)
{
    if (pR==NULL)
    {
        printf("pR record is invalid ,pR == NULL\n");
        return - 1;
    }
    if (pR->flag != MTI_Y_FLAG)
    {
        printf("pR record is invalid  pR->flag [%c] not equal [%c]\n",pR->flag,MTI_Y_FLAG);
        return - 1;
    }
    
    int size = 4096;
    char tmpStr[size+1];
    memset(tmpStr,0,sizeof(tmpStr));
    
    for(int i=0;i<pR->num;i++)
    {
        if(strlen(tmpStr) + strlen(pR->row_detail[i]) < size )
        {
            strcat(tmpStr,pR->row_detail[i]);
            if ( i != pR->num - 1)
            strcat(tmpStr," ");
        }
    }
    printf("%s\n",tmpStr);
    
    return 0;
}
    
//打印当前表的所有数据内容
int cMTIData::printAllInfo()
{
    int Rnum = 0;//初始化记录数
    MTI_RECORD * iTmp = data;
    
    printf("\nMTI Table Name: --==【%s】\n",table_name);
    
    printHeadInfo();
    
    while(iTmp != NULL)
    {
        if(printRecord(iTmp))
        {
            printf("found data record wrong ...\n");
            return -1;
        }
        Rnum++;
        iTmp= iTmp->next;
    }

    printTailInfo();
    printRecordNum(Rnum);
    
    return 0;
}

void cMTIData::printIndexHandleSearch(MTI_INDEX_HANDLE pH,char * key)
{
    int Rnum = 0;//初始化记录数
    MTI_RECORD * iTmp = NULL;
    printf("\nMTI Table Name: --==【%s】 , search key value 【%s】\n",table_name,key);
    
    
    /*<! 性能统计*/
    stat_time laststat_time;
  stat_time curstat_time;
  memset(&laststat_time,0,sizeof(stat_time));memset(&curstat_time,0,sizeof(curstat_time));
  do_stat_deal(&laststat_time,&curstat_time,STAT_START); //【性能统计,统计查询耗时】
    /*<! 性能统计*/
    
    MTI_INODE pR = NULL;
    pR = doIndexHandleSearch(pH,key);
    
    /*<! 性能统计*/
    do_stat_deal(&laststat_time,&curstat_time,STAT_STOP); //【性能统计,统计查询耗时】
    /*<! 性能统计*/
    
    printResult(pR,key);    
    
    /*<! 性能统计*/
    do_stat_print(&laststat_time,&curstat_time,"");
    /*<! 性能统计*/
    
    return;
}

//冲突检测函数 0 没有冲突,非0 有冲突,入参为需要检测的键值
int cMTIData::conflict_check(MTI_RESULT pMR,char * key)
{
    //当pMR为空,则返回0,相当于不在存在冲突
    if (pMR==NULL)
    {
        return 0;
    }
    else
    {
        //如果值是一致的就不会 认为没有冲突
        //printf("------------|pMR->key[%s],key[%s]\n",pMR->key,key);
        if (strcmp(pMR->key,key) == 0)
            return 0;
    }
    return 1;
}
    
//打印根据索引超找到的数据内容
int cMTIData::printResult(MTI_INODE pMR,char *key)
{    
    int Rnum = 0;//初始化记录数
    printHeadInfo();
    MTI_RECORD * iTmp =NULL; //初始化
    
    if (pMR==NULL)
    {
        //说明索引区没有存储对应的数据,do nothing
    }
    else
    {
        MTI_RESULT pTmp = pMR->index_item;
        
        
        while( pTmp!=NULL)
        {
            //如果键区首节点的冲突标志不等于没有冲突,则添加冲突检测,如果没有冲突,直接不进行冲突检测
            if(pMR->conflict_flag != MTI_CONFICT_N_FLAG)
            {
                if(conflict_check(pTmp,key)) //若存在冲突则绕过此条继续遍历链表
              {
                  pTmp = pTmp->next;
                    continue;
              }
              if(pTmp == NULL)//如果已经为空了,则整个返回
                  return 0;
            }
            
            iTmp = pTmp->_t;
            if(printRecord(iTmp))
            {
                printf("found data record wrong ...\n");
                return -1;
            }
            Rnum++;
            pTmp = pTmp->next;
        }
    }
    printTailInfo();
    printRecordNum(Rnum);
    
    
    return 0;
}

//hash数值函数
unsigned long cMTIData::ELFHash(char *str)
{
    unsigned long hash = 0;  
  unsigned long x = 0;  
      
  while (*str)  
  {  
    hash = (hash << 4) + (*str++);//hash左移4位,把当前字符ASCII存入hash低四位。   
    if ((x = hash & 0xF0000000L) != 0)  
    {  
       //如果最高的四位不为0,则说明字符多余7个,现在正在存第8个字符,如果不处理,再加下一个字符时,第一个字符会被移出,因此要有如下处理。  
       //该处理,如果对于字符串(a-z 或者A-Z)就会仅仅影响5-8位,否则会影响5-31位,因为C语言使用的算数移位  
       //因为1-4位刚刚存储了新加入到字符,所以不能>>28  
       hash ^= (x >> 24);  
       //上面这行代码并不会对X有影响,本身X和hash的高4位相同,下面这行代码&~即对28-31(高4位)位清零。  
       hash &= ~x;  
    }  
  }  
  //返回一个符号位为0的数,即丢弃最高位,以免函数外产生影响。(我们可以考虑,如果只有字符,符号位不可能为负)  
  return (hash & 0x7FFFFFFF);  
}

//将字符串中的数值,解析到 idx1 idx2 idx3 三者的值,其中 str 是纯字符串数值,调用前注意需要处理判断串
void cMTIData::parseH1H2H3(char *str,int &idx1,int & idx2,int &idx3)
{
    char tmpStr3[4+1];
    
    int len = strlen(str);
    
    if(len <=4)
    {
        idx1 = 0;
        idx2 = 0;
        idx3 = atoi(str);
    }
    else
    {
        memset(tmpStr3,0,sizeof(tmpStr3));
        //截取后四位,对于大的数值型字符串,比如手机号段用后四位,对于不规则的字符串,采用elfhash后的数字取后四位
        strncpy(tmpStr3,str+len-4,4);
        
        idx1 = 0;
        idx2 = 0;
        idx3 = atoi(tmpStr3);
    }
    //printf("h1:%d h2:%d h3:%d,str[%s]\n",idx1,idx2,idx3,str);
    
    return;
}    

//利用elfhash的函数,返回的 unsigned long
//来构造生成三级索引的值idx1 idx2 idx3 三者的值
void cMTIData::getH1H2H3Index(char *str,int &idx1,int & idx2,int &idx3)
{
    if(str == NULL)
    {
        idx1 = 0;idx2 = 0;idx3 = 0;
    }
    else
    {
        //字符串纯数字字符串
        if( isNumber(str))
        {
                parseH1H2H3(str,idx1,idx2,idx3);
        }
        else
        {
              char tmpStr[15+1];
              memset(tmpStr,0,sizeof(tmpStr));
              
              sprintf(tmpStr,"%ld",ELFHash(str)); //获取elfhash数值
              
                parseH1H2H3(tmpStr,idx1,idx2,idx3);
        }
    }
    return;
}
//构造函数
MTI_IR::MTI_IR()
{
    pMR=NULL;
    conflict_flag='0';
    pID=NULL;
    key[0]=0;
}



/*<! (Memory Table Interface Embed In Your Application) end */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值