0
点赞
收藏
分享

微信扫一扫

PostgreSQL数据库网络层——libpq Event例子解读


本篇博客分析PostgreSQL数据库网络层——libpq Event System中提及的示例,以学习libpq Event System的使用。
PQregisterEventProc向 libpq 注册事件回调过程。必须在每个要接收事件的 PGconn 上注册一次事件过程。 除了内存之外,可以向连接注册的事件过程的数量没有限制。 如果成功,该函数返回一个非零值,如果失败则返回零。触发 libpq 事件时将调用 proc 参数。 它的内存地址也用于查找instanceData。 name 参数用于引用错误消息中的事件过程。 此值不能为 NULL 或零长度字符串。 名称字符串被复制到 PGconn 中,因此传递的内容不需要长期存在。 每当事件发生时,passThrough 指针就会传递给 proc。 此参数可以为 NULL。

/* called once on any connection that should receive events. Sends a PGEVT_REGISTER to myEventProc. */
if (!PQregisterEventProc(conn, myEventProc, "mydata_proc", NULL)) {
fprintf(stderr, "Cannot register PGEventProc\n");
PQfinish(conn);
return 1;
}

上面的代码就是向conn结构体中注册myEventProc回调函数。首先我们看一下PGconn中Event相关字段,eventArraySize是events数组大小,nEvents是events已经使用的元素的数量。

/* Event procs registered via PQregisterEventProc */
PGEvent *events; /* expandable array of event data */
int nEvents; /* number of active events */
int eventArraySize; /* allocated array size */

typedef struct PGEvent
{
PGEventProc proc; /* the function to call on events */
char *name; /* used only for error messages */
void *passThrough; /* pointer supplied at registration time */
void *data; /* optional state (instance) data */
bool resultInitialized; /* T if RESULTCREATE/COPY succeeded */
} PGEvent;

PQregisterEventProc函数就是

int PQregisterEventProc(PGconn *conn, PGEventProc proc, const char *name, void *passThrough) {
int i;
PGEventRegister regevt; // 这个结构体就包含了一个成员就是PGconn指针
if (!proc || !conn || !name || !*name) return false; /* bad arguments */
for (i = 0; i < conn->nEvents; i++) {
if (conn->events[i].proc == proc)
return false; /* already registered */
}
if (conn->nEvents >= conn->eventArraySize) { // 扩容
PGEvent *e;
int newSize;
newSize = conn->eventArraySize ? conn->eventArraySize * 2 : 8;
if (conn->events)e = (PGEvent *) realloc(conn->events, newSize * sizeof(PGEvent));
else e = (PGEvent *) malloc(newSize * sizeof(PGEvent));
if (!e) return false;
conn->eventArraySize = newSize;
conn->events = e;
}
// 使用下一个空闲的元素
conn->events[conn->nEvents].proc = proc; // 回调设置到这里
conn->events[conn->nEvents].name = strdup(name);
if (!conn->events[conn->nEvents].name) return false;
conn->events[conn->nEvents].passThrough = passThrough;
conn->events[conn->nEvents].data = NULL;
conn->events[conn->nEvents].resultInitialized = false;
conn->nEvents++;

regevt.conn = conn;
if (!proc(PGEVT_REGISTER, &regevt, passThrough)) { // 调用回调函数,PGEVT_REGISTER代表注册事件在调用PQregisterEventProc时发生
conn->nEvents--;
free(conn->events[conn->nEvents].name);
return false;
}
return true;
}

myEventProc回调函数对于PGEVT_REGISTER类型的操作就是调用PQsetInstanceData函数将过程 proc 的连接 conn 的 instanceData 设置为数据。

static int myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) {
switch (evtId) {
case PGEVT_REGISTER: {
PGEventRegister *e = (PGEventRegister *)evtInfo;
mydata *data = get_mydata(e->conn);
/* associate app specific data with connection */
PQsetInstanceData(e->conn, myEventProc, data);
break;
}
int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data) {
int i;
if (!conn || !proc) return false;
for (i = 0; i < conn->nEvents; i++) {
if (conn->events[i].proc == proc) {
conn->events[i].data = data;
return true;
}
}
return false;
}


举报

相关推荐

0 条评论