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