CVS update: php3/functions
| From: | tommay | Date: | Thu, 05 Nov 1998 01:09:55 +0000 |
| Subject: | CVS update: php3/functions | ||
| Groups: | php.dev | ||
| Request: | Send a blank email to php-dev+get-2200@lists.php.net to get a copy of this message | ||
Date: Wednesday November 4, 1998 @ 20:09
Author: tommay
Update of /repository/php3/functions
In directory asf:/u2/tmp/cvs-serv17256
Modified Files:
sybase-ct.c
Log Message:
php3_sybct_query: added deadlock detection and automatic query retry.
Tested on Solaris 2.6 with 11.5 ct-lib and Linux with 11.0 ct-lib,
against Sybase 11.5.1 on Solaris and MS SQL Server 6.5 on NT.
It makes sense to add it at this level because 1) deadlock would otherwise
cause the query to fail (or maybe not, depending on the server), but such
failure is currently indistinguishable from a hard error such as a network
disconnect, 2) the doc for both sybase and mssql say deadlock is inevitable
and advocate checking for deadlock and retrying, 3) by doing it here we
relieve the application programmer of some tedium and responsibility.
Index: php3/functions/sybase-ct.c
diff -c php3/functions/sybase-ct.c:1.52 php3/functions/sybase-ct.c:1.53
*** php3/functions/sybase-ct.c:1.52 Wed Nov 4 15:12:04 1998
--- php3/functions/sybase-ct.c Wed Nov 4 20:09:54 1998
***************
*** 27,33 ****
+----------------------------------------------------------------------+
*/
! /* $Id: sybase-ct.c,v 1.52 1998/11/04 20:12:04 tommay Exp $ */
#ifndef MSVC5
--- 27,33 ----
+----------------------------------------------------------------------+
*/
! /* $Id: sybase-ct.c,v 1.53 1998/11/05 01:09:54 tommay Exp $ */
#ifndef MSVC5
***************
*** 211,216 ****
--- 211,232 ----
php3_error(E_WARNING,"Sybase: Server message: %s (severity %d, procedure %s)",
srvmsg->text, srvmsg->severity, ((srvmsg->proclen>0) ? srvmsg->proc :
"N/A"));
}
+
+ /* If this is a deadlock message, set the connection's deadlock flag
+ * so we will retry the request. Sorry about the bare constant here,
+ * but it's not defined anywhere and it's a "well-known" number.
+ */
+ if (srvmsg->msgnumber == 1205) {
+ sybct_link *sybct;
+
+ if (ct_con_props(connection, CS_GET, CS_USERDATA, &sybct, CS_SIZEOF(sybct),
NULL)==CS_SUCCEED) {
+ sybct->deadlock = 1;
+ }
+ else {
+ /* oh well */
+ }
+ }
+
return CS_SUCCEED;
}
***************
*** 304,309 ****
--- 320,332 ----
return 0;
}
+ /* Note - this saves a copy of sybct, not a pointer to it. */
+ if (ct_con_props(sybct->connection, CS_SET, CS_USERDATA, &sybct, CS_SIZEOF(sybct),
NULL)!=CS_SUCCEED) {
+ php3_error(E_WARNING,"Sybase: Unable to set userdata");
+ ct_con_drop(sybct->connection);
+ return 0;
+ }
+
if (user) {
ct_con_props(sybct->connection, CS_SET, CS_USERNAME, user, CS_NULLTERM, NULL);
}
***************
*** 336,342 ****
char *user,*passwd,*host;
char *hashed_details;
int hashed_details_length;
! sybct_link sybct,*sybct_ptr;
resource_list = list;
resource_plist = plist;
--- 359,365 ----
char *user,*passwd,*host;
char *hashed_details;
int hashed_details_length;
! sybct_link *sybct_ptr;
resource_list = list;
resource_plist = plist;
***************
*** 422,435 ****
RETURN_FALSE;
}
! if (!_php3_sybct_really_connect(&sybct, host, user, passwd)) {
efree(hashed_details);
RETURN_FALSE;
}
/* hash it up */
- sybct_ptr = (sybct_link *) malloc(sizeof(sybct_link));
- memcpy(sybct_ptr,&sybct,sizeof(sybct_link));
new_le.type = php3_sybct_module.le_plink;
new_le.ptr = sybct_ptr;
if (_php3_hash_update(plist, hashed_details, hashed_details_length+1, (void *) &new_le,
sizeof(list_entry),NULL)==FAILURE) {
--- 445,458 ----
RETURN_FALSE;
}
! sybct_ptr = (sybct_link *) malloc(sizeof(sybct_link));
! if (!_php3_sybct_really_connect(sybct_ptr, host, user, passwd)) {
! free(sybct_ptr);
efree(hashed_details);
RETURN_FALSE;
}
/* hash it up */
new_le.type = php3_sybct_module.le_plink;
new_le.ptr = sybct_ptr;
if (_php3_hash_update(plist, hashed_details, hashed_details_length+1, (void *) &new_le,
sizeof(list_entry),NULL)==FAILURE) {
***************
*** 460,481 ****
RETURN_FALSE;
}
if (!(con_status & CS_CONSTAT_CONNECTED) || (con_status & CS_CONSTAT_DEAD)) {
if (con_status & CS_CONSTAT_CONNECTED) {
ct_close(sybct_ptr->connection, CS_FORCE_CLOSE);
}
/* Create a new connection, then replace the old
* connection. If we fail to create a new connection,
! * leave the old one so there will be a connection,
* even if it is a non-functional one. This is because
* code may still be holding an id for this connection
* so we can't free the CS_CONNECTION.
*/
! if (!_php3_sybct_really_connect(&sybct, host, user, passwd)) {
efree(hashed_details);
RETURN_FALSE;
}
! ct_con_drop(sybct_ptr->connection);
! memcpy(sybct_ptr,&sybct,sizeof(sybct_link));
}
}
return_value->value.lval = php3_list_insert(sybct_ptr,php3_sybct_module.le_plink);
--- 483,511 ----
RETURN_FALSE;
}
if (!(con_status & CS_CONSTAT_CONNECTED) || (con_status & CS_CONSTAT_DEAD)) {
+ sybct_link sybct;
+
if (con_status & CS_CONSTAT_CONNECTED) {
ct_close(sybct_ptr->connection, CS_FORCE_CLOSE);
}
/* Create a new connection, then replace the old
* connection. If we fail to create a new connection,
! * put the old one back so there will be a connection,
* even if it is a non-functional one. This is because
* code may still be holding an id for this connection
* so we can't free the CS_CONNECTION.
+ * (This is actually totally hokey, it would be better
+ * to just ct_con_drop() the connection and set
+ * sybct_ptr->connection to NULL, then test it for
+ * NULL before trying to use it elsewhere . . .)
*/
! memcpy(&sybct,sybct_ptr,sizeof(sybct_link));
! if (!_php3_sybct_really_connect(sybct_ptr, host, user, passwd)) {
! memcpy(sybct_ptr,&sybct,sizeof(sybct_link));
efree(hashed_details);
RETURN_FALSE;
}
! ct_con_drop(sybct.connection); /* drop old connection */
}
}
return_value->value.lval = php3_list_insert(sybct_ptr,php3_sybct_module.le_plink);
***************
*** 513,526 ****
RETURN_FALSE;
}
! if (!_php3_sybct_really_connect(&sybct, host, user, passwd)) {
efree(hashed_details);
RETURN_FALSE;
}
/* add it to the list */
- sybct_ptr = (sybct_link *) emalloc(sizeof(sybct_link));
- memcpy(sybct_ptr,&sybct,sizeof(sybct_link));
return_value->value.lval = php3_list_insert(sybct_ptr,php3_sybct_module.le_link);
return_value->type = IS_LONG;
--- 543,556 ----
RETURN_FALSE;
}
! sybct_ptr = (sybct_link *) emalloc(sizeof(sybct_link));
! if (!_php3_sybct_really_connect(sybct_ptr, host, user, passwd)) {
! efree(sybct_ptr);
efree(hashed_details);
RETURN_FALSE;
}
/* add it to the list */
return_value->value.lval = php3_list_insert(sybct_ptr,php3_sybct_module.le_link);
return_value->type = IS_LONG;
***************
*** 728,734 ****
*/
if (ct_res_info(sybct_ptr->cmd, CS_NUMDATA, &num_fields, CS_UNUSED, NULL)!=CS_SUCCEED) {
- ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_ALL);
return NULL;
}
--- 758,763 ----
***************
*** 834,840 ****
if (retcode != CS_END_DATA) {
_free_sybct_result(result);
result = NULL;
- ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_ALL);
} else {
result->fields = (sybct_field *) emalloc(sizeof(sybct_field)*num_fields);
j=0;
--- 863,868 ----
***************
*** 878,890 ****
pval *query,*sybct_link_index;
int id,type;
sybct_link *sybct_ptr;
! sybct_result *result = NULL;
CS_INT restype;
CS_RETCODE retcode;
enum {
! Q_SUCCESS,
! Q_FAILURE,
! Q_RESULT,
} status;
switch(ARG_COUNT(ht)) {
--- 906,918 ----
pval *query,*sybct_link_index;
int id,type;
sybct_link *sybct_ptr;
! sybct_result *result;
CS_INT restype;
CS_RETCODE retcode;
enum {
! Q_RESULT, /* Success with results. */
! Q_SUCCESS, /* Success but no results. */
! Q_FAILURE, /* Failure, no results. */
} status;
switch(ARG_COUNT(ht)) {
***************
*** 914,1013 ****
convert_to_string(query);
! if (ct_command(sybct_ptr->cmd, CS_LANG_CMD, query->value.str.val, CS_NULLTERM,
CS_UNUSED)!=CS_SUCCEED) {
! RETURN_FALSE;
! }
! if (ct_send(sybct_ptr->cmd)!=CS_SUCCEED) {
! ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_ALL);
! RETURN_FALSE;
! }
! /* Use the first result set or succeed/fail status and discard the
! * others. Applications really shouldn't be making calls that
! * return multiple result sets, but if they do then we need to
! * properly read or cancel them or the connection will become
! * unusable.
! */
! if (ct_results(sybct_ptr->cmd, &restype)!=CS_SUCCEED) {
! ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_ALL);
! RETURN_FALSE;
! }
! switch ((int) restype) {
! case CS_CMD_FAIL:
! default:
! status = Q_FAILURE;
! break;
! case CS_CMD_SUCCEED:
! case CS_CMD_DONE:
! case CS_COMPUTEFMT_RESULT:
! case CS_ROWFMT_RESULT:
! case CS_DESCRIBE_RESULT:
! case CS_MSG_RESULT:
! status = Q_SUCCESS;
! break;
! case CS_COMPUTE_RESULT:
! case CS_CURSOR_RESULT:
! case CS_PARAM_RESULT:
! case CS_ROW_RESULT:
! case CS_STATUS_RESULT:
! status = Q_RESULT;
! result = _php3_sybct_fetch_result_set(sybct_ptr);
! break;
! }
! /* The only restype we should get now is CS_CMD_DONE, possibly
! * followed by a CS_STATUS_RESULT/CS_CMD_SUCCEED/CS_CMD_DONE
! * sequence if the command was a stored procedure call. But we
! * still need to read and discard unexpected results. We might
! * want to return a failure in this case because the application
! * won't be getting all the results it asked for.
! */
! while ((retcode = ct_results(sybct_ptr->cmd, &restype))==CS_SUCCEED) {
! switch ((int) restype) {
! case CS_CMD_SUCCEED:
! case CS_CMD_DONE:
! break;
case CS_CMD_FAIL:
status = Q_FAILURE;
break;
!
case CS_COMPUTE_RESULT:
case CS_CURSOR_RESULT:
case CS_PARAM_RESULT:
case CS_ROW_RESULT:
- /* Unexpected results, cancel them. */
case CS_STATUS_RESULT:
! ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_CURRENT);
break;
default:
status = Q_FAILURE;
break;
}
- if (status == Q_FAILURE) {
- ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_ALL);
- }
- }
! switch (retcode) {
! case CS_END_RESULTS:
! /* Normal. */
break;
! case CS_FAIL:
! /* Hopefully this either cleans up the connection, or the
! * connection ends up marked dead so it will be reopened
! * if it is persistent. We may want to do
! * ct_close(CS_FORCE_CLOSE) if ct_cancel() fails; see the
! * doc for ct_results()==CS_FAIL.
! */
! ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_ALL);
! case CS_CANCELED:
! default:
! status = Q_FAILURE;
! break;
}
if (status == Q_SUCCESS) {
--- 942,1075 ----
convert_to_string(query);
! /* Repeat until we don't deadlock. */
! for (;;) {
! result = NULL;
! sybct_ptr->deadlock = 0;
! /* On Solaris 11.5, ct_command() can be moved outside the
! * loop, but not on Linux 11.0.
! */
! if (ct_command(sybct_ptr->cmd, CS_LANG_CMD, query->value.str.val, CS_NULLTERM,
CS_UNUSED)!=CS_SUCCEED) {
! RETURN_FALSE;
! }
! if (ct_send(sybct_ptr->cmd)!=CS_SUCCEED) {
! ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_ALL);
! RETURN_FALSE;
! }
+ /* Use the first result set or succeed/fail status and discard the
+ * others. Applications really shouldn't be making calls that
+ * return multiple result sets, but if they do then we need to
+ * properly read or cancel them or the connection will become
+ * unusable.
+ */
+ if (ct_results(sybct_ptr->cmd, &restype)!=CS_SUCCEED) {
+ ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_ALL);
+ RETURN_FALSE;
+ }
+
+ switch ((int) restype) {
case CS_CMD_FAIL:
+ default:
status = Q_FAILURE;
break;
! case CS_CMD_SUCCEED:
! case CS_CMD_DONE:
! case CS_COMPUTEFMT_RESULT:
! case CS_ROWFMT_RESULT:
! case CS_DESCRIBE_RESULT:
! case CS_MSG_RESULT:
! status = Q_SUCCESS;
! break;
case CS_COMPUTE_RESULT:
case CS_CURSOR_RESULT:
case CS_PARAM_RESULT:
case CS_ROW_RESULT:
case CS_STATUS_RESULT:
! result = _php3_sybct_fetch_result_set(sybct_ptr);
! if (result == NULL) {
! ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_ALL);
! RETURN_FALSE;
! }
! status = Q_RESULT;
break;
+ }
+
+ /* The only restype we should get now is CS_CMD_DONE, possibly
+ * followed by a CS_STATUS_RESULT/CS_CMD_SUCCEED/CS_CMD_DONE
+ * sequence if the command was a stored procedure call. But we
+ * still need to read and discard unexpected results. We might
+ * want to return a failure in this case because the application
+ * won't be getting all the results it asked for.
+ */
+ while ((retcode = ct_results(sybct_ptr->cmd, &restype))==CS_SUCCEED) {
+ switch ((int) restype) {
+ case CS_CMD_SUCCEED:
+ case CS_CMD_DONE:
+ break;
+
+ case CS_CMD_FAIL:
+ status = Q_FAILURE;
+ break;
+ case CS_COMPUTE_RESULT:
+ case CS_CURSOR_RESULT:
+ case CS_PARAM_RESULT:
+ case CS_ROW_RESULT:
+ /* Unexpected results, cancel them. */
+ case CS_STATUS_RESULT:
+ ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_CURRENT);
+ break;
+
+ default:
+ status = Q_FAILURE;
+ break;
+ }
+ if (status == Q_FAILURE) {
+ ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_ALL);
+ }
+ }
+
+ switch (retcode) {
+ case CS_END_RESULTS:
+ /* Normal. */
+ break;
+
+ case CS_FAIL:
+ /* Hopefully this either cleans up the connection, or the
+ * connection ends up marked dead so it will be reopened
+ * if it is persistent. We may want to do
+ * ct_close(CS_FORCE_CLOSE) if ct_cancel() fails; see the
+ * doc for ct_results()==CS_FAIL.
+ */
+ ct_cancel(NULL, sybct_ptr->cmd, CS_CANCEL_ALL);
+ case CS_CANCELED:
default:
status = Q_FAILURE;
break;
}
! /* If or completed without deadlock, break out of the loop.
! * Sometimes deadlock results in failures and sometimes not,
! * it seems to depend on the server flavor. But we want to
! * retry all deadlocks.
! */
! if (sybct_ptr->deadlock == 0) {
break;
+ }
! /* Get rid of any results we may have fetched. This happens:
! * e.g., our result set may be a stored procedure status which
! * is returned even if the stored procedure deadlocks. As an
! * optimization, we could try not to fetch results in known
! * deadlock condittions, but deadlock is (should be) rare.
! */
! if (result != NULL) {
! _free_sybct_result(result);
! }
}
if (status == Q_SUCCESS) {
***************
*** 1018,1027 ****
if (result != NULL) {
_free_sybct_result(result);
}
- RETURN_FALSE;
- }
-
- if (result == NULL) {
RETURN_FALSE;
}
--- 1080,1085 ----
--
PHP Development Mailing List http://www.php.net/
To unsubscribe send an empty message to php-dev-unsubscribe@lists.php.net
For help: php-dev-help@lists.php.net