2015-10-16 21:12 GMT+02:00 Robert Haas <robertmh...@gmail.com>: > On Fri, Oct 16, 2015 at 6:22 AM, Pavel Stehule <pavel.steh...@gmail.com> > wrote: > > in GoodData we have this feature implemented - little bit different > named - > > DROP DATABASE FORCE > > > > It is useful in complex environment with mix of pooled and not pooled > > connections - and in our environment - about 2K databases per server with > > lot of dropped / created databases per server / per day. > > > > I can publish this patch, if there will be any interest. > > I think this would be a useful feature. What would one do about > prepared transactions? >
It doesn't solve it - GoodData doesn't use it - so I didn't solve this question - it emulates manual maintenance. In our solution can be some opened issues. Patch attached Regards Pavel > > -- > Robert Haas > EnterpriseDB: http://www.enterprisedb.com > The Enterprise PostgreSQL Company >
*** ./src/backend/commands/dbcommands.c.orig 2015-02-16 18:29:19.296790829 +0100 --- ./src/backend/commands/dbcommands.c 2015-02-17 10:59:50.999374567 +0100 *************** *** 456,462 **** * to wait 5 sec. We try to raise warning after 1 minute and and raise * a error after 5 minutes. */ ! if (!CountOtherDBBackends(src_dboid, ¬herbackends, &npreparedxacts, true)) break; if (loops++ % 12 == 0) --- 456,462 ---- * to wait 5 sec. We try to raise warning after 1 minute and and raise * a error after 5 minutes. */ ! if (!CountOtherDBBackends(src_dboid, ¬herbackends, &npreparedxacts, true, false)) break; if (loops++ % 12 == 0) *************** *** 787,793 **** * DROP DATABASE */ void ! dropdb(const char *dbname, bool missing_ok) { Oid db_id; bool db_istemplate; --- 787,793 ---- * DROP DATABASE */ void ! dropdb(const char *dbname, bool missing_ok, bool force) { Oid db_id; bool db_istemplate; *************** *** 795,800 **** --- 795,801 ---- HeapTuple tup; int notherbackends; int npreparedxacts; + int loops = 0; /* * Look up the target database's OID, and get exclusive lock on it. We *************** *** 864,875 **** * * As in CREATE DATABASE, check this after other error conditions. */ ! if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts, false)) ! ereport(ERROR, ! (errcode(ERRCODE_OBJECT_IN_USE), ! errmsg("database \"%s\" is being accessed by other users", ! dbname), ! errdetail_busy_db(notherbackends, npreparedxacts))); /* * Remove the database's tuple from pg_database. --- 865,897 ---- * * As in CREATE DATABASE, check this after other error conditions. */ ! for (;;) ! { ! /* ! * CountOtherDBBackends check usage of database by other backends and try ! * to wait 5 sec. We try to raise warning after 1 minute and and raise ! * a error after 5 minutes. ! */ ! if (!CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts, true, force)) ! break; ! ! if (force && loops++ % 12 == 0) ! ereport(WARNING, ! (errcode(ERRCODE_OBJECT_IN_USE), ! errmsg("source database \"%s\" is being accessed by other users", ! dbname), ! errdetail_busy_db(notherbackends, npreparedxacts))); ! ! /* without "force" flag raise exception immediately, or after 5 minutes */ ! if (!force || loops % 60 == 0) ! ereport(ERROR, ! (errcode(ERRCODE_OBJECT_IN_USE), ! errmsg("source database \"%s\" is being accessed by other users", ! dbname), ! errdetail_busy_db(notherbackends, npreparedxacts))); ! ! CHECK_FOR_INTERRUPTS(); ! } /* * Remove the database's tuple from pg_database. *************** *** 1007,1013 **** * * As in CREATE DATABASE, check this after other error conditions. */ ! if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts, false)) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("database \"%s\" is being accessed by other users", --- 1029,1035 ---- * * As in CREATE DATABASE, check this after other error conditions. */ ! if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts, false, false)) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("database \"%s\" is being accessed by other users", *************** *** 1132,1138 **** * * As in CREATE DATABASE, check this after other error conditions. */ ! if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts, false)) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("database \"%s\" is being accessed by other users", --- 1154,1160 ---- * * As in CREATE DATABASE, check this after other error conditions. */ ! if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts, false, false)) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("database \"%s\" is being accessed by other users", *** ./src/backend/nodes/copyfuncs.c.orig 2015-02-17 10:34:40.385775458 +0100 --- ./src/backend/nodes/copyfuncs.c 2015-02-17 10:35:31.041859691 +0100 *************** *** 3175,3180 **** --- 3175,3181 ---- COPY_STRING_FIELD(dbname); COPY_SCALAR_FIELD(missing_ok); + COPY_SCALAR_FIELD(force); return newnode; } *** ./src/backend/nodes/equalfuncs.c.orig 2015-02-17 10:34:40.388775463 +0100 --- ./src/backend/nodes/equalfuncs.c 2015-02-17 10:35:31.043859695 +0100 *************** *** 1475,1480 **** --- 1475,1481 ---- { COMPARE_STRING_FIELD(dbname); COMPARE_SCALAR_FIELD(missing_ok); + COMPARE_SCALAR_FIELD(force); return true; } *** ./src/backend/parser/gram.y.orig 2015-02-17 10:35:21.334843550 +0100 --- ./src/backend/parser/gram.y 2015-02-17 10:35:31.049859705 +0100 *************** *** 7853,7870 **** * This is implicitly CASCADE, no need for drop behavior *****************************************************************************/ ! DropdbStmt: DROP DATABASE database_name { DropdbStmt *n = makeNode(DropdbStmt); n->dbname = $3; n->missing_ok = FALSE; $$ = (Node *)n; } ! | DROP DATABASE IF_P EXISTS database_name { DropdbStmt *n = makeNode(DropdbStmt); n->dbname = $5; n->missing_ok = TRUE; $$ = (Node *)n; } ; --- 7853,7872 ---- * This is implicitly CASCADE, no need for drop behavior *****************************************************************************/ ! DropdbStmt: DROP DATABASE database_name opt_force { DropdbStmt *n = makeNode(DropdbStmt); n->dbname = $3; n->missing_ok = FALSE; + n->force = $4; $$ = (Node *)n; } ! | DROP DATABASE IF_P EXISTS database_name opt_force { DropdbStmt *n = makeNode(DropdbStmt); n->dbname = $5; n->missing_ok = TRUE; + n->force = $6; $$ = (Node *)n; } ; *** ./src/backend/storage/ipc/procarray.c.orig 2015-02-16 18:29:19.298790832 +0100 --- ./src/backend/storage/ipc/procarray.c 2015-02-17 10:44:43.422803881 +0100 *************** *** 2405,2414 **** * continue (in simple implementation based only on PGPROC entries). In this case we should * not calculate this process safely, becase createdb holds a lock. * * */ bool ! CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared, bool is_createdb_cmd) { ProcArrayStruct *arrayP = procArray; --- 2405,2417 ---- * continue (in simple implementation based only on PGPROC entries). In this case we should * not calculate this process safely, becase createdb holds a lock. * + * A option "force_terminate" enforce termination other sessions, that uses database. When we + * try to drop database, we should to calculate with all attached process. * */ bool ! CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared, ! bool is_createdb_cmd, bool force_terminate) { ProcArrayStruct *arrayP = procArray; *************** *** 2453,2458 **** --- 2456,2473 ---- if ((pgxact->vacuumFlags & PROC_IS_AUTOVACUUM) && nautovacs < MAXAUTOVACPIDS) autovac_pids[nautovacs++] = proc->pid; + else + { + if (force_terminate) + { + /* try to terminate backend */ + #ifdef HAVE_SETSID + kill(-(proc->pid), SIGTERM); + #else + kill(proc->pid, SIGTERM) + #endif + } + } } } *** ./src/backend/tcop/utility.c.orig 2015-02-17 10:35:21.341843562 +0100 --- ./src/backend/tcop/utility.c 2015-02-17 10:35:31.053859711 +0100 *************** *** 940,946 **** DropdbStmt *stmt = (DropdbStmt *) parsetree; PreventTransactionChain(isTopLevel, "DROP DATABASE"); ! dropdb(stmt->dbname, stmt->missing_ok); } break; --- 940,946 ---- DropdbStmt *stmt = (DropdbStmt *) parsetree; PreventTransactionChain(isTopLevel, "DROP DATABASE"); ! dropdb(stmt->dbname, stmt->missing_ok, stmt->force); } break; *** ./src/include/commands/dbcommands.h.orig 2015-02-17 10:35:21.344843567 +0100 --- ./src/include/commands/dbcommands.h 2015-02-17 10:35:31.054859713 +0100 *************** *** 53,59 **** } xl_dbase_drop_rec; extern void createdb(const CreatedbStmt *stmt); ! extern void dropdb(const char *dbname, bool missing_ok); extern void RenameDatabase(const char *oldname, const char *newname); extern void AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel); extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt); --- 53,59 ---- } xl_dbase_drop_rec; extern void createdb(const CreatedbStmt *stmt); ! extern void dropdb(const char *dbname, bool missing_ok, bool force); extern void RenameDatabase(const char *oldname, const char *newname); extern void AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel); extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt); *** ./src/include/nodes/parsenodes.h.orig 2015-02-17 10:35:21.347843571 +0100 --- ./src/include/nodes/parsenodes.h 2015-02-17 10:35:31.055859715 +0100 *************** *** 2350,2355 **** --- 2350,2356 ---- NodeTag type; char *dbname; /* database to drop */ bool missing_ok; /* skip error if db is missing? */ + bool force; /* terminate all other sessions in db */ } DropdbStmt; /* ---------------------- *** ./src/include/storage/procarray.h.orig 2015-02-17 10:35:31.056859716 +0100 --- ./src/include/storage/procarray.h 2015-02-17 10:57:20.417113491 +0100 *************** *** 72,78 **** extern int CountUserBackends(Oid roleid); extern bool CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared, ! bool is_createdb_cmd); extern void XidCacheRemoveRunningXids(TransactionId xid, int nxids, const TransactionId *xids, --- 72,78 ---- extern int CountUserBackends(Oid roleid); extern bool CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared, ! bool is_createdb_cmd, bool force_terminate); extern void XidCacheRemoveRunningXids(TransactionId xid, int nxids, const TransactionId *xids,
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers