STVM(truck of Virtual memory table)是一個開源的使用ANSI C語言編寫、支持本地API調用和網路調用,全表數據基於IPC共享記憶體方式存儲,基於C語言struck結構定義記錄行,RB-Tree和hash作為主要算法的記憶體資料庫,是一款介於SQL和NOSQL之間的一款高速快取資料庫。
基本介紹
- 中文名:高速快取資料庫
- 外文名:STVM
基本簡介,定義,性能,支持語言,欄位類型,使用手冊,開發流程,
基本簡介
由於數據全部存儲在記憶體中,相比較其他類型的快取,運行速度之快可想而知。
定義
stvm是一款其介於介於SQL和NOSQL,擁有以下主要特點
支持SQL基本語法(本版本支持insert、update、delete、select、group order、count,first,游標)功能。
支持序列
支持唯一索引、查詢索引和組合索引(組合索引不必考慮索引欄位先後)
支持條件動態查詢
內置記錄點擊量
集群、主-子分布同步。
事務功能(假性事務)
數據持久性,進程異常退出,不會導致數據丟失,除非系統宕機。
支持網路API和函式API, 支持多執行緒、多進程等等
內置數據版本,維護數據一致安全。
多機集群,數據分區
當然也有幾點缺陷,索引長度限制目前版本64位,修改長度需編譯項目、啟動後不能修改表欄位(ddl語句),不能聯表查詢。
stvm是一款高速快取資料庫,表欄位定義來源與C語言STRUCK,動態條件賦值只需要對結構體成員賦值即為查詢條件。
整個操作提供特定API訪問,減少解析SQL和欄位的時間。
全表數據分3個區(表頭區、索引區、數據區),並且全部存儲在一塊記憶體中。
每張表定義一個資料庫塊,每張表擁有自己讀寫鎖,支持執行緒。
預留拓展表空間參數,但效率會降低擴展個數倍
性能
在相同環境在,用本機API訪問對單標操作是redis的30倍以上。網路api也快1.5倍以上。
比fastdb快倍10左右。
其他沒逐一測試。
支持語言
C | C++ | Java | …… |
支持 | 支持 | 待支持 | - |
欄位類型
欄位類型有LONG,CHAR,DOUB(對應整型、字元型、浮點型)
行記錄建議不要超過500KB
為了避免記憶體的浪費,唯一索引和查詢索引最多各一組。
使用手冊
啟動環境變數:
TVMDBD=/home/stvm/tvmdb 指向stvm工作目錄
TVMCFG=/home/stvm/tvmdb/.tvm.run 啟動參數
配置完成後,stvm -w採用預設啟動參數進去本機模式。
如果集群模式請配置 stvm.conf,然後用stvm -c stvm.conf編譯配置檔案即可。
STVM對外提供2個開發運維工具stvm和調試工具detvm。
stvm -w啟動啟動
stvm -s停止系統
STVM也提供一個類型sqlpuls類型簡單工具,輸入:stvm SQL進入SQL界面,該工具僅僅用來運維調試使用。
stvm dom --進入域的維護
開發流程
創建表
// 定義表序號
#define TBL_USER_INFO 10
必須用C定義STRUCK:
typedef struct __TBL_USER_INFO
{
long acct_id;
char user_no[21];
char user_type[2];
char user_nm[81];
char user_addr[161];
char user_phone[31];
}dbUser;
定義創建表函式
CREATE lCreateUserInfo()
{
DEFINE(TBL_USER_INFO, "TBL_USER_INFO", "", dbUser)
FIELD(dbUser, acct_id, "acct_id", FIELD_LONG)
FIELD(dbUser, user_no, "user_no", FIELD_CHAR)
FIELD(dbUser, user_type, "user_type", FIELD_CHAR)
FIELD(dbUser, user_nm, "user_nm", FIELD_CHAR)
FIELD(dbUser, user_addr, "user_addr", FIELD_CHAR)
FIELD(dbUser, user_phone, "user_phone", FIELD_CHAR)
CREATE_IDX(NORMAL) // 創建查詢索引
IDX_FIELD(dbUser, acct_id, FIELD_LONG)
CREATE_IDX(UNQIUE) // 創建唯一索引
IDX_FIELD(dbUser, user_no, FIELD_CHAR)
IDX_FIELD(dbUser, user_type, FIELD_CHAR)
FINISH
}
調用api:
lCreateTable(pstSavm, TBL_USER_INFO, 100000, lCreateUserInfo)完成對TBL_USER_INFO表的創建。
其中pstSavm為執行緒句柄
TBL_USER_INFO 創建的表序號,
100000初始化記憶體記錄空間條數。
lCreateUserInfo創建表定義函式。
調用成功則返回RC_SUCC, 失敗返回RC_FAIL, 失敗可調用pstSavm->m_lErrno獲取處理失敗錯誤碼,sGetTError(pstSavm->m_lErrno)獲取錯誤信息。
操作表(查詢單記錄)
dbUser stUser;
SATvm *pstSavm = (SATvm *)pGetSATvm();
// 初始化TBL_USER_INFO表,每張表都需要初始化一次, 對於表重建後,需要重新初始化一次。
if(RC_SUCC != lInitSATvm(pstSavm, TBL_USER_INFO))
{
fprintf(stderr, "init failed, err:(%d)(%s)\n", pstSavm->m_lErrno, sGetTError(pstSavm->m_lErrno));
return ;
}
conditinit(pstSavm, stUser, TBL_USER_INFO); // 綁定變數
numberset(pstSavm, stUser, user_type, "1"); // 查詢條件賦值
stringset(pstSavm, stUser, user_no, "20180223"); // 查詢條件賦值
if(RC_SUCC != lSelect(pstSavm, (void *)&stUser)) // 單條記錄查詢
{
fprintf(stderr, "Select錯誤ep:%d, err:(%d)(%s)\n", pstSavm->m_lEType, pstSavm->m_lErrno,
sGetTError(pstSavm->m_lErrno));
return ;
}
fprintf(stdout, "acct_id:%ld, user_no:%s, user_type:%s, user_nm:%s, user_addr:%s, user_phone:%s\n",
stUser.acct_id, stUser.user_no, stUser.user_type, stUser.user_nm, stUser.user_addr, stUser.user_phone);
操作表(查詢多條記錄)
size_t i = 0, lOut;
dbUser *pstUser;
SATvm *pstSavm = (SATvm *)pGetSATvm();
// 初始化TBL_USER_INFO表,每張表都需要初始化一次, 對於表重建後,需要重新初始化一次。
if(RC_SUCC != lInitSATvm(pstSavm, TBL_USER_INFO))
{
fprintf(stderr, "init failed, err:(%d)(%s)\n", pstSavm->m_lErrno, sGetTError(pstSavm->m_lErrno));
return ;
}
conditinit(pstSavm, stUser, TBL_USER_INFO); // 綁定變數
numberset(pstSavm, stUser, user_type, "1"); // 查詢條件賦值
stringset(pstSavm, stUser, user_no, "20180223"); // 查詢條件賦值
if(RC_SUCC != lQuery(pstSavm, &lOut, (void **)&pstUser)) // 批量查詢查詢
{
fprintf(stderr, "Select錯誤ep:%d, err:(%d)(%s)\n", pstSavm->m_lEType, pstSavm->m_lErrno,
sGetTError(pstSavm->m_lErrno));
return ;
}
for(i = 0; i < lOut; i ++)
{
fprintf(stdout, "acct_id:%ld, user_no:%s, user_type:%s, user_nm:%s, user_addr:%s, user_phone:%s\n",
pstUser[i].acct_id, pstUser[i].user_no, pstUser[i].user_type, pstUser[i].user_nm, pstUser[i].user_addr, pstUser[i].user_phone);
}
操作表(新增記錄)
dbUser stUser;
SATvm *pstSavm = (SATvm *)pGetSATvm();
// 初始化TBL_USER_INFO表,每張表都需要初始化一次, 對於表重建後,需要重新初始化一次。
if(RC_SUCC != lInitSATvm(pstSavm, TBL_USER_INFO))
{
fprintf(stderr, "init failed, err:(%d)(%s)\n", pstSavm->m_lErrno, sGetTError(pstSavm->m_lErrno));
return ;
}
stUser.acct_id = 10021; // 對結構體賦值
strcpy(stUser.user_no, "20180223"); // 對結構體賦值
strcpy(stUser.user_type, "1"); // 對結構體賦值
insertinit(pstSavm, stUser, TBL_USER_INFO); // 綁定變數
if(RC_SUCC != lInsert(pstSavm)) // 插入記錄
{
fprintf(stderr, "Select錯誤ep:%d, err:(%d)(%s)\n", pstSavm->m_lEType, pstSavm->m_lErrno,
sGetTError(pstSavm->m_lErrno));
return ;
}
操作表(刪除記錄)
dbUser stUser;
SATvm *pstSavm = (SATvm *)pGetSATvm();
// 初始化TBL_USER_INFO表,每張表都需要初始化一次, 對於表重建後,需要重新初始化一次。
if(RC_SUCC != lInitSATvm(pstSavm, TBL_USER_INFO))
{
fprintf(stderr, "init failed, err:(%d)(%s)\n", pstSavm->m_lErrno, sGetTError(pstSavm->m_lErrno));
return ;
}
conditinit(pstSavm, stAct, TBL_USER_INFO) // 對結構體賦值
numberset(pstSavm, stUser, user_type, "1"); // 查詢條件賦值
stringset(pstSavm, stUser, user_no, "20180223"); // 查詢條件賦值
if(RC_SUCC != lDelete(pstSavm)) // 刪除記錄
{
fprintf(stderr, "Delete err:(%d)(%s)\n", pstSavm->m_lEType, pstSavm->m_lErrno,
sGetTError(pstSavm->m_lErrno));
return ;
}
操作表(修改記錄)
dbUser stUser, stUpd;
SATvm *pstSavm = (SATvm *)pGetSATvm();
if(RC_SUCC != lInitSATvm(pstSavm, TBL_USER_INFO))
{
fprintf(stderr, "init failed, err:(%d)(%s)\n", pstSavm->m_lErrno, sGetTError(pstSavm->m_lErrno));
return ;
}
updateinit(stUpd);
conditinit(pstSavm, stUser, TBL_USER_INFO) // 綁定變數
numberset(pstSavm, stUser, user_type, "1"); // 查詢條件賦值
stringset(pstSavm, stUser, user_no, "20180223"); // 查詢條件賦值
stringupd(pstSavm, stUpd, user_phone, "18691128912");
if(RC_SUCC != lUpdate(pstSavm, (void *)&stUpd))
{
fprintf(stderr, "Update err:(%d)(%s), (%ld)\n", pstSavm->m_lErrno,
sGetTError(pstSavm->m_lErrno), lGetEffect());
return ;
}
其他函式lTruncate、lCount、lExtreme、lGroup, 和網路API如lTvmDelete、lTvmInsert、lTvmSelect、lTvmUpdate、lTvmTruncate、lTvmCount、lTvmExtreme、lTvmGroup、lTvmQuery、不做一一枚舉。