暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

人大金仓数据库KingbaseES DCI初始化模块的处理过程

原创 数据猿 2023-12-12
501


金仓数据库KingbaseES———DCI初始化模块的处理过程

关键字:

DCI、初始化、连接建立、人大金仓、KingbaseES

DCI初始化环境

初始化环境是连接数据库进行各项操作的前提。OCI的初始化模块包含了初始化OCI全局环境,分配所有句柄的父句柄——环境句柄,再依次分配其他句柄并设置相关属性。各个函数的调用关系如图1所示。

C:\Users\yangli\Desktop\OCI接口函数调用\初始化模块函数调用关系.png

图1 初始化模块函数调用关系

分配和初始化环境句柄有DCIInitialize+DCIEnvInit、DCIEnvCreate两种实现方式,DCIInitialize()和DCIEnvInit()主要是为了兼容早期版本。服务器上下文句柄及其子句柄可以通过DCIHandleAlloc函数显示分配并进行初始化,也可以使用DCILogon()、DCILogon2()隐式分配服务器上下文句柄,并已经初始化。对于数据库连接,仅维护一个单独的用户会话可以调用DCILogon()、DCILogon2()初始化上下文句柄。对于复杂会话管理的应用程序,必须显式分配服务器上下文,并将服务器和用户会话显式设置到上下文句柄。DCIServerAttach( )将数据库名挂载到服务器句柄上(即dblink参数),并不执行实质性的连接工作。具体操作如下:

err = DCIInitialize((ub4) OCI_DEFAULT, (dvoid *)0, (dvoid * (*)(dvoid *, size_t)) 0, (dvoid * (*)(dvoid *, dvoid *, size_t))0, (void (*)(dvoid *, dvoid *)) 0);

if (err != OCI_SUCCESS)

{

printf("OCIInitialize failed\n");

return err;

}

err = DCIEnvInit((OCIEnv **) &pEnv, OCI_DEFAULT, 0, NULL);

if (err != OCI_SUCCESS)

{

printf("OCIEnvInit failed\n");

return err;

}

err = DCIHandleAlloc((dvoid *) pEnv, (dvoid **) &pError, OCI_HTYPE_ERROR, 0, NULL);

err = DCIHandleAlloc(envhp, (void **) svchp, DCI_HTYPE_SVCCTX, 0, NULL);

if (err != DCI_SUCCESS)

        goto end;

/* Allocate Server Handle */

err = DCIHandleAlloc(envhp, (dvoid **) &((*svchp)->pServer), DCI_HTYPE_SERVER, (size_t) 0, NULL);

if (err != DCI_SUCCESS)

        goto end;

/* Set Server Into ServerContext */

err = DCIAttrSet(*svchp, DCI_HTYPE_SVCCTX, (*svchp)->pServer, 0, DCI_ATTR_SERVER, errhp);

/* AttachServer */

err = DCIServerAttach((*svchp)->pServer, errhp, dbname, (sb4)strlen(dbname), DCI_DEFAULT);

/* Allocate Session Handle */

err = DCIHandleAlloc(envhp, (dvoid **) &((*svchp)->pSession), (ub4) DCI_HTYPE_SESSION, (size_t) 0, NULL);

if (err != DCI_SUCCESS)

        goto end;

/* Set Session Into ServerContext */

err = DCIAttrSet(*svchp, DCI_HTYPE_SVCCTX, (*svchp)->pSession, 0, DCI_ATTR_SESSION, errhp);

/* Set Session UserName */

err = DCIAttrSet((*svchp)->pSession, DCI_HTYPE_SESSION, (void *) username, (ub4)strlen(username), DCI_ATTR_USERNAME, errhp);

/* Set Session Password */

err = DCIAttrSet((*svchp)->pSession, DCI_HTYPE_SESSION, (void *) password, (ub4)strlen(password), DCI_ATTR_PASSWORD, errhp);

end:

if (err != DCI_SUCCESS)

{

    if (*svchp)

    {

        if ((*svchp)->pSession)

          DCIHandleFree((dvoid *)(*svchp)->pSession, DCI_HTYPE_SESSION);

        if ((*svchp)->pServer)

         DCIHandleFree((dvoid *) ((*svchp)->pServer), DCI_HTYPE_SERVER);

        DCIHandleFree((void *) *svchp, DCI_HTYPE_SVCCTX);

        *svchp = NULL;

   }

#ifdef NCI_JK

        err = DCI_ERROR;

#endif

    }

由于句柄申请过程中涉及到动态内存空间的申请,一旦申请失败,就要调用相应的句柄释放函数释放资源,以免造成内存泄漏。

KSAPI_AllocEnv、ENV_Constructor、KSAPI_AllocConnect、CC_Constructor等是ODBC层的句柄申请和空间分配操作,仅处理环境句柄与会话句柄结构体成员EnvironmentClass与ConnectionClass的空间分配。在当前代码中,主要是对ODBC层的句柄申请和分配进行封装,并设置相关错误码,ODBC层的错误码并不出现在DCI分配的错误句柄中,而是由ODBC层的句柄自己携带,进行相应的逻辑判断,只将少量句柄传入DCI层并转化为Oracle的标准错误码。

DCI初始化资源释放

在程序执行结束,与服务器断开连接之后,需要依次释放初始化过程中申请的各类句柄资源,其函数调用关系如图2所示。

C:\Users\yangli\Desktop\OCI接口函数调用\初始化模块资源释放函数调用关系.png

图2 初始化资源释放函数调用关系

初始化申请的环境释放过程中,首先应处理服务上下文句柄的三个子句柄:

① 对应DCIServerAttach( ),在服务器句柄释放之前,需要调用DCIServerDetach( )解除服务上下文句柄与数据库的关联,将srvhp->dblink释放并置空;

② 释放会话句柄。由于同一个会话句柄可能会创建多个数据库连接,例如读写分离,负载均衡等,因此在会话句柄释放时需要循环调用KSAPI_FreeConnect( ),以便释放所有连接。连接释放过程涉及到了ODBC层的ConnectionClass相关资源的释放:首先从当前环境中移除连接ENV_remove_connection,若未成功移除,设置错误信息

CC_set_error(conn, CONN_ERR_IN_USE, "A transaction is currently being executed.", func);

之后,在

char CC_Destructor(ConnectionClass *conn)

中调用CC_cleanup清除连接,并且释放conn->__error_message空间。

③释放服务器句柄。

处理完服务上下文相关的子句柄之后,就可依次释放服务上下文句柄、错误句柄和环境句柄。由于环境句柄是所有句柄的父句柄,所以一般在程序最后才进行释放。

具体操作为:

err = DCIServerDetach(pServer, pError, OCI_DEFAULT);

err = DCIHandleFree(pSession, OCI_HTYPE_SESSION);

pSession = NULL;

err = DCIHandleFree((dvoid *) pSvcCtx, (ub4) OCI_HTYPE_SVCCTX);

if (err != OCI_SUCCESS)

{

      printf("OCIHandleFree OCI_HTYPE_SVCCTX failed\n");

}

err = DCIHandleFree((dvoid *) pError, (ub4) OCI_HTYPE_ERROR);

if (err != OCI_SUCCESS)

{

      printf("OCIHandleFree OCI_HTYPE_ERROR failed\n");

}

pError = NULL;

err = DCIHandleFree((dvoid *) pEnv, (ub4) OCI_HTYPE_ENV);

if (err != OCI_SUCCESS)

{

      printf("OCIHandleFree OCI_HTYPE_ENV failed\n");

}

pEnv = NULL;


「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论