From e12c950e8fdebe5ba0942b7ddf18573f5afc4e2b Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Sat, 17 Jun 2017 12:15:28 +0900 Subject: [PATCH] Reduce roundtrips when using SAVEPOINTs by issuing multiple commands after prepending (RELEASE xxxx;)SAVEPOINT; to simple queries. Unfortunately it's impossible to recover syntax errors after this change. --- connection.c | 128 +++++++++++++++++++++++++++++++++------------------ connection.h | 3 ++ execute.c | 38 +++++++++------ misc.c | 2 +- 4 files changed, 110 insertions(+), 61 deletions(-) diff --git a/connection.c b/connection.c index e2ae5ed..81f3cf9 100644 --- a/connection.c +++ b/connection.c @@ -1542,13 +1542,6 @@ void CC_on_abort_partial(ConnectionClass *conn) { mylog("CC_on_abort_partial in\n"); CONNLOCK_ACQUIRE(conn); - if (!conn->internal_op) /* manually rolling back to */ - { - conn->internal_svp = 0; /* possibly an internal savepoint is invalid */ - mylog(" %s:reset an internal savepoint\n", __FUNCTION__); - conn->opt_previous = 0; /* unknown */ - } - CC_init_opt_in_progress(conn); ProcessRollback(conn, TRUE, TRUE); CC_discard_marked_objects(conn); CONNLOCK_RELEASE(conn); @@ -1625,7 +1618,9 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD BOOL ignore_abort_on_conn = ((flag & IGNORE_ABORT_ON_CONN) != 0), create_keyset = ((flag & CREATE_KEYSET) != 0), issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self)), - rollback_on_error, query_rollback, end_with_commit, read_only; + rollback_on_error, query_rollback, end_with_commit, + read_only, prepend_savepoint = FALSE, + ignore_roundtrip_time = ((self->connInfo.extra_opts & BIT_IGNORE_ROUND_TRIP_TIME) != 0); char *ptr; BOOL ReadyToReturn = FALSE, @@ -1635,9 +1630,9 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD discard_next_begin = FALSE, discard_next_savepoint = FALSE, consider_rollback; - int func_cs_count = 0; + int func_cs_count = 0, i; size_t query_buf_len = 0; - char *query_buf = NULL; + char *query_buf = NULL, prepend_cmd[64]; size_t query_len; /* QR_set_command() dups this string so doesn't need static */ @@ -1676,7 +1671,7 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD * and the appeneded query would be issued separately. * Otherwise a multiple command query would be issued. */ - if (appendq && (self->connInfo.extra_opts & BIT_IGNORE_ROUND_TRIP_TIME) != 0) + if (appendq && ignore_roundtrip_time) { res = CC_send_query_append(self, query, qi, flag, stmt, NULL); if (QR_command_maybe_successful(res)) @@ -1711,6 +1706,8 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD if (read_only) svpopt |= SVPOPT_RDONLY; + if (!ignore_roundtrip_time) + svpopt |= SVPOPT_REDUCE_ROUNDTRIP; if (!CC_started_rbpoint(self)) { if (SQL_ERROR == SetStatementSvp(astmt, svpopt)) @@ -1722,41 +1719,78 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD } } + /* prepend internal savepoint command ? */ + if (PREPEND_IN_PROGRESS == self->internal_op) + prepend_savepoint = TRUE; + /* append all these together, to avoid round-trips */ query_len = strlen(query); +mylog("!!!! %s:query_len=%u\n", __FUNCTION__, query_len); - query_buf_len = strlen(bgncmd) + 1 - + strlen(svpcmd) + 1 + strlen(per_query_svp) + 1 - + query_len - + (appendq ? (1 + strlen(appendq)) : 0) - + 1 + strlen(rlscmd) + strlen(per_query_svp) - + 1; - query_buf = malloc(query_buf_len); - if (!query_buf) - { - CC_set_error(self, CONN_NO_MEMORY_ERROR, "Couldn't alloc buffer for query.", ""); - goto cleanup; - } - query_buf[0] = '\0'; - if (issue_begin) - { - snprintfcat(query_buf, query_buf_len, "%s;", bgncmd); - discard_next_begin = TRUE; - } - if (query_rollback) - { - snprintfcat(query_buf, query_buf_len, "%s %s;", svpcmd, per_query_svp); - discard_next_savepoint = TRUE; - } - strlcat(query_buf, query, query_buf_len); - if (appendq) + for (i = 0; i < 2; i++) /* 0:calculate& alloc 1:snprint */ { - snprintfcat(query_buf, query_buf_len, ";%s", appendq); - } - if (query_rollback) - { - snprintfcat(query_buf, query_buf_len, ";%s %s", rlscmd, per_query_svp); + /* issue_begin, query_rollback and prepend_savepoint are exclusive */ + if (issue_begin) + { + if (0 == i) + query_buf_len += (strlen(bgncmd) + 1); + else + { + snprintfcat(query_buf, query_buf_len, "%s;", bgncmd); + discard_next_begin = TRUE; + } + } + else if (query_rollback) + { + if (0 == i) + query_buf_len += (strlen(svpcmd) + 1 + strlen(per_query_svp) + 1); + else + { + snprintfcat(query_buf, query_buf_len, "%s %s;", svpcmd, per_query_svp); + discard_next_savepoint = TRUE; + } + } + else if (prepend_savepoint) + { + if (0 == i) + query_buf_len += (GenerateSvpCommand(self, prepend_cmd, sizeof(prepend_cmd)) + 1); + else + { + snprintfcat(query_buf, query_buf_len, "%s;", prepend_cmd); + self->internal_op = SAVEPOINT_IN_PROGRESS; + } + } + if (0 == i) + query_buf_len += query_len; + else + strlcat(query_buf, query, query_buf_len); + if (appendq) + { + if (0 == i) + query_buf_len += (1 + strlen(appendq)); + else + snprintfcat(query_buf, query_buf_len, ";%s", appendq); + } + if (query_rollback) + { + if (0 == i) + query_buf_len += (1 + strlen(rlscmd) + 1 + strlen(per_query_svp)); + else + snprintfcat(query_buf, query_buf_len, ";%s %s", rlscmd, per_query_svp); + } + if (0 == i) + { + query_buf_len++; + query_buf = malloc(query_buf_len); + if (!query_buf) + { + CC_set_error(self, CONN_NO_MEMORY_ERROR, "Couldn't alloc buffer for query.", ""); + goto cleanup; + } + query_buf[0] = '\0'; + } } +inolog("!!!! %s:query_buf=%s(%d)\n", __FUNCTION__, query_buf, query_buf_len); /* Set up notice receiver */ nrarg.conn = self; @@ -1859,15 +1893,19 @@ inolog("Discarded the first SAVEPOINT\n"); { CC_mark_cursors_doubtful(self); CC_set_in_error_trans(self); /* mark the transaction error in case of manual rollback */ - if (!self->internal_op) - self->internal_svp = 0; + if (ROLLBACK_IN_PROGRESS != self->internal_op) + { + mylog(" %s:reset an internal savepoint\n", __FUNCTION__); + self->internal_svp = 0; /* possibly an internal savepoint is invalid */ + self->opt_previous = 0; /* unknown */ + } + CC_init_opt_in_progress(self); } else if (strnicmp(cmdbuffer, rlscmd, strlen(rlscmd)) == 0) { + self->internal_svp = 0; if (SAVEPOINT_IN_PROGRESS == self->internal_op) break; /* discard the result */ - else /* internal savepoint may become invalid */ - self->internal_svp = 0; } /* * DROP TABLE or ALTER TABLE may change diff --git a/connection.h b/connection.h index 37f04e2..e90d765 100644 --- a/connection.h +++ b/connection.h @@ -474,16 +474,19 @@ enum { enum { SAVEPOINT_IN_PROGRESS = 1 ,ROLLBACK_IN_PROGRESS = 2 + ,PREPEND_IN_PROGRESS = 2 }; /* StatementSvp entry option */ enum { SVPOPT_RDONLY = 1L + ,SVPOPT_REDUCE_ROUNDTRIP = (1L << 1) }; #define INIT_SVPOPT (SVPOPT_RDONLY) #define CC_svp_init(a) ((a)->internal_svp = (a)->internal_op = 0, (a)->opt_in_progress = (a)->opt_previous = INIT_SVPOPT) #define CC_init_opt_in_progress(a) ((a)->opt_in_progress = INIT_SVPOPT) #define CC_init_opt_previous(a) ((a)->opt_previous = INIT_SVPOPT) +int GenerateSvpCommand(ConnectionClass *conn, char *cmd, int bufsize); #ifdef __cplusplus } #endif diff --git a/execute.c b/execute.c index df0abc7..068a44e 100644 --- a/execute.c +++ b/execute.c @@ -398,7 +398,7 @@ int HowToPrepareBeforeExec(StatementClass *stmt, BOOL checkOnly) static const char *GetSvpName(const ConnectionClass *conn, char *wrk, int wrksize) { - snprintf(wrk, wrksize, "_EXEC_SVP_%p_%d", conn, conn->internal_svp); + snprintf(wrk, wrksize, "_EXEC_SVP_%p", conn); return wrk; } @@ -585,6 +585,21 @@ inolog("%s:%p->external=%d\n", func, stmt, stmt->external); return ret; } +int +GenerateSvpCommand(ConnectionClass *conn, char *cmd, int buflen) +{ + char esavepoint[32]; + int rtn; + + cmd[0] = '\0'; +#ifdef _RELEASE_INTERNAL_SAVEPOINT + if (conn->internal_svp) + rtn = snprintf(cmd, buflen, "RELEASE %s;", GetSvpName(conn, esavepoint, sizeof(esavepoint))); +#endif /* _RELEASE_INTERNAL_SAVEPOINT */ + rtn = snprintfcat(cmd, buflen, "SAVEPOINT %s", GetSvpName(conn, esavepoint, sizeof(esavepoint))); + return rtn; +} + /* * Must be in a transaction or the subsequent execution * invokes a transaction. @@ -633,25 +648,18 @@ inolog(" !!!! %s:%p->accessed=%d opt=%u in_progress=%u prev=%u\n", __FUNCTION__, } if (need_savep) { - int internal_svp = conn->internal_svp; - - cmd[0] = '\0'; -#ifdef _RELEASE_INTERNAL_SAVEPOINT - if (conn->internal_svp) - SPRINTF_FIXED(cmd, "RELEASE %s;", GetSvpName(conn, esavepoint, sizeof(esavepoint))); -#endif /* _RELEASE_INTERNAL_SAVEPOINT */ - conn->internal_svp = 1; - SPRINTFCAT_FIXED(cmd, "SAVEPOINT %s", GetSvpName(conn, esavepoint, sizeof(esavepoint))); - conn->internal_svp = internal_svp; + if (0 != (option & SVPOPT_REDUCE_ROUNDTRIP)) + { + conn->internal_op = PREPEND_IN_PROGRESS; + CC_set_accessed_db(conn); + return ret; + } + GenerateSvpCommand(conn, cmd, sizeof(cmd)); conn->internal_op = SAVEPOINT_IN_PROGRESS; res = CC_send_query(conn, cmd, NULL, 0, NULL); conn->internal_op = 0; if (QR_command_maybe_successful(res)) - { - // conn->internal_svp = 1; - // CC_start_rbpoint(conn); ret = SQL_SUCCESS; - } else { SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal SAVEPOINT failed", func); diff --git a/misc.c b/misc.c index 926c288..cd8948c 100644 --- a/misc.c +++ b/misc.c @@ -172,7 +172,7 @@ snprintfcat(char *buf, size_t size, const char *format, ...) va_start(arglist, format); len = vsnprintf(buf + pos, size - pos, format, arglist); va_end(arglist); - return len; + return len + pos; } /* -- 2.39.5