YY哥的技术随笔——关注Linux、数据库和云计算SQLite入门与分析(七)---浅谈SQLite的虚拟机写在前面:虚拟机技术在现在是一个非常热的技术,它的历史也很悠久。最早的虚拟机可追溯到IBM的VM/370,到上个世纪90年代,在计算机程序设计语言领域又出现一件革命性的事情——Java语言的出现,它与c++最大的不同在于它必须在Java虚拟机上运行。Java虚拟机掀起了虚拟机技术的热潮,随后,Microsoft也不甘落后,雄心勃勃的推出了.Net平台。由于在这里主要讨论SQLite的虚拟机,不打算对这些做过多评论,但是作为对比,我会先对Java虚拟机作一个概述。好了,下面进入正题。 1、概述 JVM定义了独立于平台的类文件格式和字节码形式的指令集。在任何Java程序的字节码表示形式中,变量和方法的引用都是使用符号,而不是使用具体的数字。由于内存的布局要在运行时才确定,所以类的变量和方法的改变不会影响现存的字节码。例如,一个Java程序引用了其他系统中的某个类,该系统中那个类的更新不会使这个Java程序崩溃。这也提高了Java的平台独立性。 虚拟机一般都采用了基于栈的架构,这种架构易于实现。虚拟机方法显著提高了程序语言的可移植性和安全性,但同时也导致了执行效率的下降。
2、Java虚拟机 2.1、概述 2.2、Java虚拟机 Java虚拟机的结构分为:类装载子系统,运行时数据区,执行引擎,本地方法接口。其中运行时数据区又分为:方法区,堆,Java栈,PC寄存器,本地方法栈。
关于Java虚拟机就介绍到此,由于Java虚拟机内容庞大,在这里不可能一一介绍,如果想更多了解Java虚拟机,参见《深入Java虚拟机》。 3、SQLite虚拟机 在SQLite的后端(backend)的上一层,通常叫做虚拟数据库引擎(virtual database engine),或者叫做虚拟机(virtual machine)。从作用上来说,它是SQLite的核心。用户程序发出的SQL语句请求,由前端(frontend)编译器(以后会继续介绍)处理,生成字节代码程序(bytecode programs),然后由VM解释执行。VM执行时,又会调用B-tree模块的相关的接口,并输出执行的结果(本节将以一个具体的查询过程来描述这一过程)。 3.1、虚拟机的内部结构 先来看一个简单的例子: int main(int argc, char **argv)
{ int rc, i, id, cid; char *name; char *sql; char *zErr; sqlite3 *db; sqlite3_stmt *stmt; sql="select id,name,cid from episodes"; //打开数据库 sqlite3_open("test.db", &db); //编译sql语句 sqlite3_prepare(db, sql, strlen(sql), &stmt, NULL); //调用VM,执行VDBE程序 rc = sqlite3_step(stmt); while(rc == SQLITE_ROW) { id = sqlite3_column_int(stmt, 0); name = (char *)sqlite3_column_text(stmt, 1); cid = sqlite3_column_int(stmt, 2); if(name != NULL){ fprintf(stderr, "Row: id=%i, cid=%i, name='%s'\n", id,cid,name); } else { /* Field is NULL */ fprintf(stderr, "Row: id=%i, cid=%i, name=NULL\n", id,cid); } rc = sqlite3_step(stmt); } //释放资源 sqlite3_finalize(stmt); //关闭数据库 sqlite3_close(db); return 0; }
这段程序很简单,它的功能就是遍历整个表,并把查询结果输出。 vdbe的定义: Code
由vdbe的定义,可以总结出SQLite虚拟机的内部结构: 3.2、指令 int nOp; /* Number of instructions in the program(指令的条数) */
Op *aOp; /* Space to hold the virtual machine's program(指令)*/ aOp数组保存有SQL经过编译后生成的所有指令,对于上面的例子为: 0、Goto(0x5b-91) |0|0c
1、Integer(0x2d-45) |0|0 2、OpenRead(0x0c-12)|0|2 3、SetNumColumns(0x64-100)|0|03 4、Rewind(0x77-119) |0|0a 5、Rowid(0x23-35) |0|0 6、Column(0x02-2) |0|1 7、Column(0x02-2) |0|2 8、Callback(0x36-54)|3|0 9、Next(0x68) |0|5 10、Close 11、Halt 12、Transaction(0x66-102)|0|0 13、VerifyCookie(0x61-97)|0|1 14、Goto(0x5b-91) |0|1| sqlite3_step()引起VDBE解释引擎执行这段代码,下面来分析该段指令的执行过程: Goto:这是一条跳转指令,它的作用仅仅是跳到第12条指令; SetNumColumns:对P1确定的游标的列数设置为P2(在这里为3),在OP_Column指令执行前,该指令应该被调用来 设置表的列数; Rewind:移动当前游标(P1)移到表或索引的第一条记录; Callback:该指令执行后,PC将指向下一条指令。该指令的执行会结束sqlite3_step()的运行,并向其返回 SQLITE_ROW ——如果存在记录的话;并将VDBE的PC指针指向下一条指令——即Next指令,所以当 重新 调用sqlite3_step()执行VDBE程序时,会执行Next指令(具体的分析见后面的指令实例分析); Next:将游标移到下一条记录,并将PC指向第5条指令; 3.3、栈 Mem *aStack; /* The operand stack, except string values(栈空间) */
Mem *pTos; /* Top entry in the operand stack(栈顶指针) */ aStack是VDBE执行时使用的栈,它主要用来保指令执行进需要的参数,以及指令执行时产生的中间结果(参见后面的指令实例分析)。 3.4、指令计数器(PC) /*执行VDBE程序.当从数据库中取出一行数据时,该函数会调用回调函数(如果有的话),
**或者返回SQLITE_ROW. */ int sqlite3VdbeExec( Vdbe *p /* The VDBE */ ){ //指令计数器 int pc; /* The program counter */ //当前指令 Op *pOp; /* Current operation */ int rc = SQLITE_OK; /* Value to return */ //数据库 sqlite3 *db = p->db; /* The database */ u8 encoding = ENC(db); /* The database encoding */ //栈顶 Mem *pTos; /* Top entry in the operand stack */ if( p->magic!=VDBE_MAGIC_RUN ) return SQLITE_MISUSE; //当前栈顶指针 pTos = p->pTos; if( p->rc==SQLITE_NOMEM ){ /* This happens if a malloc() inside a call to sqlite3_column_text() or ** sqlite3_column_text16() failed. */ goto no_mem; } p->rc = SQLITE_OK; //如果需要进行出栈操作,则进行出栈操作 if( p->popStack ){ popStack(&pTos, p->popStack); p->popStack = 0; } //表明栈中没有结果 p->resOnStack = 0; db->busyHandler.nBusy = 0; //执行指令 for(pc=p->pc; rc==SQLITE_OK; pc++){ //取出操作码 pOp = &p->aOp[pc]; switch( pOp->opcode ){ //跳到操作数P2指向的指令 case OP_Goto: { /* no-push */ CHECK_FOR_INTERRUPT; //设置pc pc = pOp->p2 - 1; break; } //P1入栈 case OP_Integer: { //当前栈顶指针上移 pTos++; //设为整型 pTos->flags = MEM_Int; //取操作数P1,并赋值 pTos->i = pOp->p1; break; } //其它指令的实现 }//end switch }//end for }
3.6、指令实例分析 由于篇幅限制,仅给出几条的指令的实现,其它具体实现见源码。 1、Callback指令 Code
2、Rewind指令 Code
3、Column指令 Code
4、Next指令 Code 评论列表
终于看到你分析虚拟机了,谢谢你的分享,可能这种东西只有知音才可以有共鸣。你写得很认真。非常感谢。
虚拟“数据库”?
|
|