From: <ale...@us...> - 2013-11-14 16:16:37
|
Revision: 58787 http://sourceforge.net/p/firebird/code/58787 Author: alexpeshkoff Date: 2013-11-14 16:16:24 +0000 (Thu, 14 Nov 2013) Log Message: ----------- Implemented CORE-4263: Database linger Modified Paths: -------------- firebird/trunk/doc/README.services_extension firebird/trunk/src/alice/aliceswi.h firebird/trunk/src/alice/exe.cpp firebird/trunk/src/dbs/security.sql firebird/trunk/src/dsql/DdlNodes.epp firebird/trunk/src/dsql/DdlNodes.h firebird/trunk/src/dsql/parse.y firebird/trunk/src/include/consts_pub.h firebird/trunk/src/include/firebird/Plugin.h firebird/trunk/src/include/gen/ids.h firebird/trunk/src/jrd/Database.cpp firebird/trunk/src/jrd/Database.h firebird/trunk/src/jrd/EngineInterface.h firebird/trunk/src/jrd/dfw.epp firebird/trunk/src/jrd/fields.h firebird/trunk/src/jrd/irq.h firebird/trunk/src/jrd/jrd.cpp firebird/trunk/src/jrd/jrd_proto.h firebird/trunk/src/jrd/met.epp firebird/trunk/src/jrd/met_proto.h firebird/trunk/src/jrd/names.h firebird/trunk/src/jrd/relations.h firebird/trunk/src/jrd/tra.h firebird/trunk/src/jrd/vio.cpp firebird/trunk/src/msgs/facilities2.sql firebird/trunk/src/msgs/messages2.sql firebird/trunk/src/remote/server/os/posix/inet_server.cpp firebird/trunk/src/utilities/fbsvcmgr/fbsvcmgr.cpp firebird/trunk/src/yvalve/PluginManager.cpp firebird/trunk/src/yvalve/keywords.cpp Added Paths: ----------- firebird/trunk/doc/sql.extensions/README.linger Modified: firebird/trunk/doc/README.services_extension =================================================================== --- firebird/trunk/doc/README.services_extension 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/doc/README.services_extension 2013-11-14 16:16:24 UTC (rev 58787) @@ -223,3 +223,16 @@ fbsvcmgr host:service_mgr user sysdba password xxx action_db_stats dbname employee sts_data_pages Certainly any other database action can be used here. + + +6) Services API extension - using services to temporary turn off linger for database. +(Alex Peshkov, pes...@ma..., 2013) + +Linger is used to optimize performance in some cases (see also sql.extensions/README.linger). +If you want to turn off linger temporary (for next database close) you may use gfix utility or +services. New tag isc_spb_prp_nolinger is added for it (option). Setting isc_spb_prp_nolinger +option turns off linger for the next database close operation and may be used to force closing +database in linger state. + +Example: +fbsvcmgr host:service_mgr user sysdba password xxx action_properties dbname employee prp_nolinger Added: firebird/trunk/doc/sql.extensions/README.linger =================================================================== --- firebird/trunk/doc/sql.extensions/README.linger (rev 0) +++ firebird/trunk/doc/sql.extensions/README.linger 2013-11-14 16:16:24 UTC (rev 58787) @@ -0,0 +1,34 @@ +SQL Language Extension: ALTER DATABASE SET/DROP LINGER + + Implements capability to manage database linger. + +Author: + Alex Peshkoff <pes...@ma...> + +Syntax is: + + ALTER DATABASE SET LINGER TO {seconds}; + ALTER DATABASE DROP LINGER; + +Description: + +Makes it possible to set and clear linger value for database. + +Database linger makes engine (when running in SS mode) do not close database immediately after +last attachment is closed. This helps to increase performance when database is often opened/closed +with almost zero price. + +To set linger for database do: + ALTER DATABASE SET LINGER TO 30; -- will set linger interval to 30 seconds + +To reset linger for database do: + ALTER DATABASE DROP LINGER; -- will make engine do not delay closing given database + ALTER DATABASE SET LINGER TO 0; -- another way to clean linger settings + +Notice. +Sometimes it may be useful to turn off linger once to force server to close some database not +shutting it down. Dropping linger for it is not good solution - you will have to turn it on +manually later. To perform this task it's better to use GFIX utility with new switch 'NOLinger' - +it makes database be closed immediately when last attachment is gone no matter of linger interval +set in database. Next time linger will work normally. Services API is also available for it - +see details in README.services_extension). Property changes on: firebird/trunk/doc/sql.extensions/README.linger ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Modified: firebird/trunk/src/alice/aliceswi.h =================================================================== --- firebird/trunk/src/alice/aliceswi.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/alice/aliceswi.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -63,6 +63,7 @@ const SINT64 sw_trusted_svc = QUADCONST(0x0000000200000000); const SINT64 sw_trusted_role = QUADCONST(0x0000000400000000); const SINT64 sw_fetch_password = QUADCONST(0x0000000800000000); +const SINT64 sw_nolinger = QUADCONST(0x0000001000000000); enum alice_switches @@ -117,7 +118,8 @@ IN_SW_ALICE_TRUSTED_USER = 45, IN_SW_ALICE_TRUSTED_ROLE = 46, IN_SW_ALICE_HIDDEN_ONLINE = 47, - IN_SW_ALICE_FETCH_PASSWORD = 48 + IN_SW_ALICE_FETCH_PASSWORD = 48, + IN_SW_ALICE_NOLINGER = 49 }; static const char* const ALICE_SW_ASYNC = "ASYNC"; @@ -129,7 +131,7 @@ static const Switches::in_sw_tab_t alice_in_sw_table[] = { {IN_SW_ALICE_ACTIVATE, isc_spb_prp_activate, "ACTIVATE_SHADOW", sw_activate, - 0, ~(sw_activate | sw_user | sw_password), false, 25, 2, NULL}, + 0, ~(sw_activate | sw_user | sw_password | sw_nolinger), false, 25, 2, NULL}, // msg 25: \t-activate shadow file for database usage {IN_SW_ALICE_ATTACH, isc_spb_prp_attachments_shutdown, "ATTACH", sw_attach, sw_shut, 0, false, 26, 2, NULL}, @@ -145,7 +147,7 @@ 0, 0, false, 28, 1, NULL}, // msg 28: \t-buffers\tset page buffers <n> {IN_SW_ALICE_COMMIT, isc_spb_rpr_commit_trans, "COMMIT", sw_commit, - 0, ~(sw_commit | sw_user | sw_password), false, 29, 2, NULL}, + 0, ~(sw_commit | sw_user | sw_password | sw_nolinger), false, 29, 2, NULL}, // msg 29: \t-commit\t\tcommit transaction <tr / all> {IN_SW_ALICE_CACHE, 0, "CACHE", sw_cache, sw_shut, 0, false, 30, 2, NULL}, @@ -176,14 +178,17 @@ 0, 0, false, 36, 1, NULL}, // msg 36: \t-kill\t\tkill all unavailable shadow files {IN_SW_ALICE_LIST, isc_spb_rpr_list_limbo_trans, "LIST", sw_list, - 0, ~(sw_list | sw_user | sw_password), false, 37, 1, NULL}, + 0, ~(sw_list | sw_user | sw_password | sw_nolinger), false, 37, 1, NULL}, // msg 37: \t-list\t\tshow limbo transactions {IN_SW_ALICE_MEND, isc_spb_rpr_mend_db, "MEND", sw_mend | sw_validate | sw_full, - 0, ~(sw_no_update | sw_user | sw_password), false, 38, 2, NULL}, + 0, ~(sw_no_update | sw_user | sw_password | sw_nolinger), false, 38, 2, NULL}, // msg 38: \t-mend\t\tprepare corrupt database for backup {IN_SW_ALICE_MODE, 0, "MODE", sw_mode, - 0, ~(sw_mode | sw_user | sw_password), false, 109, 2, NULL}, + 0, ~(sw_mode | sw_user | sw_password | sw_nolinger), false, 109, 2, NULL}, // msg 109: \t-mode\t\tread_only or read_write + {IN_SW_ALICE_NOLINGER, isc_spb_prp_nolinger, "NOLINGER", sw_nolinger, + 0, sw_shut, false, 121, 3, NULL}, + // msg 121: -nolinger do not use linger on database this time (once) {IN_SW_ALICE_NO_UPDATE, isc_spb_rpr_check_db, "NO_UPDATE", sw_no_update, sw_validate, 0, false, 39, 1, NULL}, // msg 39: \t-no_update\tread-only validation (-v) @@ -205,20 +210,20 @@ */ #endif {IN_SW_ALICE_ROLLBACK, isc_spb_rpr_rollback_trans, "ROLLBACK", sw_rollback, - 0, ~(sw_rollback | sw_user | sw_password), false, 44, 1, NULL}, + 0, ~(sw_rollback | sw_user | sw_password | sw_nolinger), false, 44, 1, NULL}, // msg 44: \t-rollback\trollback transaction <tr / all> {IN_SW_ALICE_SET_DB_SQL_DIALECT, isc_spb_prp_set_sql_dialect, "SQL_DIALECT", sw_set_db_dialect, 0, 0, false, 111, 2, NULL}, // msg 111: \t-SQL_dialect\t\set dataabse dialect n {IN_SW_ALICE_SWEEP, isc_spb_rpr_sweep_db, "SWEEP", sw_sweep, - 0, ~(sw_sweep | sw_user | sw_password), false, 45, 2, NULL}, + 0, ~(sw_sweep | sw_user | sw_password | sw_nolinger), false, 45, 2, NULL}, // msg 45: \t-sweep\t\tforce garbage collection {IN_SW_ALICE_SHUT, isc_spb_prp_shutdown_mode, "SHUTDOWN", sw_shut, 0, ~(sw_shut | sw_attach | sw_cache | sw_force | sw_tran | sw_user | sw_password), false, 46, 2, NULL}, // msg 46: \t-shut\t\tshutdown {IN_SW_ALICE_TWO_PHASE, isc_spb_rpr_recover_two_phase, "TWO_PHASE", sw_two_phase, - 0, ~(sw_two_phase | sw_user | sw_password), false, 47, 2, NULL}, + 0, ~(sw_two_phase | sw_user | sw_password | sw_nolinger), false, 47, 2, NULL}, // msg 47: \t-two_phase\tperform automated two-phase recovery {IN_SW_ALICE_TRAN, isc_spb_prp_transactions_shutdown, "TRANSACTION", sw_tran, sw_shut, 0, false, 48, 3, NULL}, @@ -233,16 +238,16 @@ {IN_SW_ALICE_TRUSTED_ROLE, 0, TRUSTED_ROLE_SWITCH, sw_trusted_role, sw_trusted_svc, (sw_user | sw_password), false, 0, TRUSTED_ROLE_SWITCH_LEN, NULL}, {IN_SW_ALICE_NO_RESERVE, 0, "USE", sw_no_reserve, - 0, ~(sw_no_reserve | sw_user | sw_password), false, 49, 1, NULL}, + 0, ~(sw_no_reserve | sw_user | sw_password | sw_nolinger), false, 49, 1, NULL}, // msg 49: \t-use\t\tuse full or reserve space for versions {IN_SW_ALICE_USER, 0, "USER", sw_user, 0, (sw_trusted_auth | sw_trusted_svc | sw_trusted_role), false, 50, 4, NULL}, // msg 50: \t-user\t\tdefault user name {IN_SW_ALICE_VALIDATE, isc_spb_rpr_validate_db, "VALIDATE", sw_validate, - 0, ~(sw_validate | sw_user | sw_password), false, 51, 1, NULL}, + 0, ~(sw_validate | sw_user | sw_password | sw_nolinger), false, 51, 1, NULL}, // msg 51: \t-validate\tvalidate database structure {IN_SW_ALICE_WRITE, 0, "WRITE", sw_write, - 0, ~(sw_write | sw_user | sw_password), false, 52, 1, NULL}, + 0, ~(sw_write | sw_user | sw_password | sw_nolinger), false, 52, 1, NULL}, // msg 52: \t-write\t\twrite synchronously or asynchronously #ifdef DEV_BUILD {IN_SW_ALICE_X, 0, "X", 0, Modified: firebird/trunk/src/alice/exe.cpp =================================================================== --- firebird/trunk/src/alice/exe.cpp 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/alice/exe.cpp 2013-11-14 16:16:24 UTC (rev 58787) @@ -323,6 +323,9 @@ dpb.insertInt(isc_dpb_set_db_sql_dialect, tdgbl->ALICE_data.ua_db_SQL_dialect); } + if (switches & sw_nolinger) + dpb.insertTag(isc_dpb_nolinger); + const unsigned char* authBlock; unsigned int authBlockSize = tdgbl->uSvc->getAuthBlock(&authBlock); Modified: firebird/trunk/src/dbs/security.sql =================================================================== --- firebird/trunk/src/dbs/security.sql 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/dbs/security.sql 2013-11-14 16:16:24 UTC (rev 58787) @@ -28,6 +28,12 @@ COMMIT; +/* Linger is definitely useful for security database */ +ALTER DATABASE SET LINGER TO 60; /* one minute */ + +COMMIT; + + /* Table: RDB$USERS */ CREATE TABLE PLG$USERS ( PLG$USER_NAME SEC$USER_NAME NOT NULL PRIMARY KEY, Modified: firebird/trunk/src/dsql/DdlNodes.epp =================================================================== --- firebird/trunk/src/dsql/DdlNodes.epp 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/dsql/DdlNodes.epp 2013-11-14 16:16:24 UTC (rev 58787) @@ -10056,6 +10056,12 @@ alterCharSetNode.execute(tdbb, dsqlScratch, transaction); } + if (linger >= 0) + { + DBB.RDB$LINGER.NULL = FALSE; + DBB.RDB$LINGER = linger; + } + if (clauses & CLAUSE_BEGIN_BACKUP) changeBackupMode(tdbb, transaction, CLAUSE_BEGIN_BACKUP); Modified: firebird/trunk/src/dsql/DdlNodes.h =================================================================== --- firebird/trunk/src/dsql/DdlNodes.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/dsql/DdlNodes.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -1945,6 +1945,7 @@ : DdlNode(p), create(false), createLength(0), + linger(-1), clauses(0), differenceFile(p), setDefaultCharSet(p), @@ -1977,7 +1978,7 @@ public: bool create; // Is the node created with a CREATE DATABASE command? - SLONG createLength; + SLONG createLength, linger; unsigned clauses; Firebird::string differenceFile; Firebird::MetaName setDefaultCharSet; Modified: firebird/trunk/src/dsql/parse.y =================================================================== --- firebird/trunk/src/dsql/parse.y 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/dsql/parse.y 2013-11-14 16:16:24 UTC (rev 58787) @@ -561,6 +561,7 @@ %token <metaNamePtr> UNKNOWN %token <metaNamePtr> USAGE %token <metaNamePtr> RDB_RECORD_VERSION +%token <metaNamePtr> LINGER // precedence declarations for expression evaluation @@ -3697,6 +3698,10 @@ { $alterDatabaseNode->cryptPlugin = *$3; } | DECRYPT { $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_DECRYPT; } + | SET LINGER TO long_integer + { $alterDatabaseNode->linger = $4; } + | DROP LINGER + { $alterDatabaseNode->linger = 0; } ; @@ -7111,6 +7116,7 @@ | RANK | ROW_NUMBER | USAGE + | LINGER ; %% Modified: firebird/trunk/src/include/consts_pub.h =================================================================== --- firebird/trunk/src/include/consts_pub.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/include/consts_pub.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -120,6 +120,7 @@ #define isc_dpb_auth_plugin_list 85 #define isc_dpb_auth_plugin_name 86 #define isc_dpb_config 87 +#define isc_dpb_nolinger 88 /**************************************************/ /* clumplet tags used inside isc_dpb_address_path */ @@ -403,6 +404,7 @@ #define isc_spb_prp_set_sql_dialect 14 #define isc_spb_prp_activate 0x0100 #define isc_spb_prp_db_online 0x0200 +#define isc_spb_prp_nolinger 0x0400 #define isc_spb_prp_force_shutdown 41 #define isc_spb_prp_attachments_shutdown 42 #define isc_spb_prp_transactions_shutdown 43 Modified: firebird/trunk/src/include/firebird/Plugin.h =================================================================== --- firebird/trunk/src/include/firebird/Plugin.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/include/firebird/Plugin.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -146,8 +146,9 @@ virtual const char* FB_CARG getConfigFileName() = 0; virtual IConfig* FB_CARG getDefaultConfig() = 0; virtual IFirebirdConf* FB_CARG getFirebirdConf() = 0; + virtual void FB_CARG setReleaseDelay(ISC_UINT64 microSeconds) = 0; }; -#define FB_PLUGIN_CONFIG_VERSION (FB_REFCOUNTED_VERSION + 3) +#define FB_PLUGIN_CONFIG_VERSION (FB_REFCOUNTED_VERSION + 4) // Required to creat instances of given plugin class IPluginFactory : public IVersioned Modified: firebird/trunk/src/include/gen/ids.h =================================================================== --- firebird/trunk/src/include/gen/ids.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/include/gen/ids.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -39,6 +39,7 @@ const USHORT f_dat_id = 1; const USHORT f_dat_class = 2; const USHORT f_dat_charset = 3; + const USHORT f_dat_linger = 4; // Relation 2 (RDB$FIELDS) Modified: firebird/trunk/src/jrd/Database.cpp =================================================================== --- firebird/trunk/src/jrd/Database.cpp 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/Database.cpp 2013-11-14 16:16:24 UTC (rev 58787) @@ -77,6 +77,11 @@ Database::~Database() { + if (dbb_linger_timer) + { + dbb_linger_timer->destroy(); + } + { // scope SyncLockGuard guard(&dbb_sortbuf_sync, SYNC_EXCLUSIVE, "Database::~Database"); @@ -313,4 +318,45 @@ return 0; } + + void Database::Linger::handler() + { + JRD_shutdown_database(dbb, SHUT_DBB_RELEASE_POOLS); + } + + int Database::Linger::release() + { + if (--refCounter == 0) + { + delete this; + return 0; + } + + return 1; + } + + void Database::Linger::reset() + { + if (active) + { + TimerInterfacePtr()->stop(this); + active = false; + } + } + + void Database::Linger::set(unsigned seconds) + { + if (dbb) + { + TimerInterfacePtr()->start(this, seconds * 1000 * 1000); + active = true; + } + } + + void Database::Linger::destroy() + { + dbb = NULL; + reset(); + } + } // namespace Modified: firebird/trunk/src/jrd/Database.h =================================================================== --- firebird/trunk/src/jrd/Database.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/Database.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -301,11 +301,31 @@ bool exist; }; - static Database* create() + class Linger : public Firebird::RefCntIface<Firebird::ITimer, FB_TIMER_VERSION> { + public: + Linger(Database* a_dbb) + : dbb(a_dbb), active(false) + { } + + void set(unsigned seconds); + void reset(); + void destroy(); + + // ITimer implementation + void FB_CARG handler(); + int FB_CARG release(); + + private: + Database* dbb; + bool active; + }; + + static Database* create(Firebird::IPluginConfig* pConf) + { Firebird::MemoryStats temp_stats; MemoryPool* const pool = MemoryPool::createPool(NULL, temp_stats); - Database* const dbb = FB_NEW(*pool) Database(pool); + Database* const dbb = FB_NEW(*pool) Database(pool, pConf); pool->setStatsGroup(dbb->dbb_memory_stats); return dbb; } @@ -437,6 +457,10 @@ SharedCounter dbb_shared_counter; CryptoManager* dbb_crypto_manager; Firebird::RefPtr<ExistenceRefMutex> dbb_init_fini; + Firebird::RefPtr<Linger> dbb_linger_timer; + unsigned dbb_linger_seconds; + time_t dbb_linger_end; + Firebird::RefPtr<Firebird::IPluginConfig> dbb_plugin_config; // returns true if primary file is located on raw device bool onRawDevice() const; @@ -464,7 +488,7 @@ void deletePool(MemoryPool* pool); private: - explicit Database(MemoryPool* p) + Database(MemoryPool* p, Firebird::IPluginConfig* pConf) : dbb_permanent(p), dbb_page_manager(this, *p), dbb_modules(*p), @@ -478,7 +502,10 @@ dbb_tip_cache(NULL), dbb_creation_date(Firebird::TimeStamp::getCurrentTimeStamp()), dbb_external_file_directory_list(NULL), - dbb_init_fini(FB_NEW(*getDefaultMemoryPool()) ExistenceRefMutex()) + dbb_init_fini(FB_NEW(*getDefaultMemoryPool()) ExistenceRefMutex()), + dbb_linger_seconds(0), + dbb_linger_end(0), + dbb_plugin_config(pConf) { dbb_pools.add(p); } Modified: firebird/trunk/src/jrd/EngineInterface.h =================================================================== --- firebird/trunk/src/jrd/EngineInterface.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/EngineInterface.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -453,8 +453,8 @@ class JProvider : public Firebird::StdPlugin<Firebird::IProvider, FB_PROVIDER_VERSION> { public: - explicit JProvider(Firebird::IPluginConfig*) - : cryptCallback(NULL) + explicit JProvider(Firebird::IPluginConfig* pConf) + : cryptCallback(NULL), pluginConfig(pConf) { } @@ -479,6 +479,7 @@ private: Firebird::ICryptKeyCallback* cryptCallback; + Firebird::IPluginConfig* pluginConfig; }; inline JStatement::JStatement(dsql_req* handle, JAttachment* ja, Firebird::Array<UCHAR>& meta) Modified: firebird/trunk/src/jrd/dfw.epp =================================================================== --- firebird/trunk/src/jrd/dfw.epp 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/dfw.epp 2013-11-14 16:16:24 UTC (rev 58787) @@ -403,6 +403,7 @@ static bool drop_package_body(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool grant_privileges(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool db_crypt(thread_db*, SSHORT, DeferredWork*, jrd_tra*); +static bool set_linger(thread_db*, SSHORT, DeferredWork*, jrd_tra*); // ---------------------------------------------------------------- @@ -493,6 +494,7 @@ { dfw_check_not_null, check_not_null }, { dfw_store_view_context_type, store_view_context_type }, { dfw_db_crypt, db_crypt }, + { dfw_set_linger, set_linger }, { dfw_null, NULL } }; @@ -1526,6 +1528,36 @@ return false; } +static bool set_linger(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra*) +{ +/************************************** + * + * s e t _ l i n g e r + * + ************************************** + * + * Set linger interval in Database block. + * + **************************************/ + + SET_TDBB(tdbb); + Database* const dbb = tdbb->getDatabase(); + + switch (phase) + { + case 1: + case 2: + case 3: + return true; + + case 4: + dbb->dbb_linger_seconds = atoi(work->dfw_name.c_str()); // number stored as string + break; + } + + return false; +} + static bool check_not_null(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction) { /************************************** Modified: firebird/trunk/src/jrd/fields.h =================================================================== --- firebird/trunk/src/jrd/fields.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/fields.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -177,3 +177,5 @@ FIELD(fld_os_user , nam_os_user , dtype_varying , 255 , dsc_text_type_metadata , NULL , true) FIELD(fld_gen_val , nam_gen_val , dtype_int64 , sizeof(SINT64) , 0 , NULL , true) FIELD(fld_auth_method , nam_auth_method , dtype_varying , 255 , dsc_text_type_ascii , NULL , true) + + FIELD(fld_linger , nam_linger , dtype_long , sizeof(SLONG) , 0 , NULL , true) Modified: firebird/trunk/src/jrd/irq.h =================================================================== --- firebird/trunk/src/jrd/irq.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/irq.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -165,6 +165,8 @@ irq_grant15, // process grant option (generators) irq_grant16, // process grant option (domains) + irq_linger, // get database linger value + irq_MAX }; Modified: firebird/trunk/src/jrd/jrd.cpp =================================================================== --- firebird/trunk/src/jrd/jrd.cpp 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/jrd.cpp 2013-11-14 16:16:24 UTC (rev 58787) @@ -335,7 +335,6 @@ return 1; } - static void shutdownBeforeUnload() { LocalStatus status; @@ -837,6 +836,7 @@ bool dpb_utf8_filename; ULONG dpb_ext_call_depth; ULONG dpb_flags; // to OR'd with dbb_flags + bool dpb_nolinger; // here begin compound objects // for constructor to work properly dpb_user_name @@ -950,20 +950,22 @@ static void unwindAttach(thread_db* tdbb, const Exception& ex, Firebird::IStatus* userStatus, Jrd::Attachment* attachment, Database* dbb); static JAttachment* init(thread_db*, const PathName&, const PathName&, RefPtr<Config>, bool, - const DatabaseOptions&, RefMutexUnlock&); + const DatabaseOptions&, RefMutexUnlock&, IPluginConfig*); static JAttachment* create_attachment(const PathName&, Database*, const DatabaseOptions&); static void prepare_tra(thread_db*, jrd_tra*, USHORT, const UCHAR*); static void start_transaction(thread_db* tdbb, bool transliterate, jrd_tra** tra_handle, Jrd::Attachment* attachment, unsigned int tpb_length, const UCHAR* tpb); static void release_attachment(thread_db*, Jrd::Attachment*); static void rollback(thread_db*, jrd_tra*, const bool); -static bool shutdown_database(Database*, const bool); static void strip_quotes(string&); -static void purge_attachment(thread_db*, JAttachment*, const bool); +static void purge_attachment(thread_db* tdbb, JAttachment* jAtt, unsigned flags = 0); static void getUserInfo(UserId&, const DatabaseOptions&, const char*, const RefPtr<Config>*); static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM); +// purge_attachment() flags +static const unsigned PURGE_FORCE = 0x01; +static const unsigned PURGE_LINGER = 0x02; TraceFailedConnection::TraceFailedConnection(const char* filename, const DatabaseOptions* options) : m_filename(filename), @@ -1331,7 +1333,7 @@ // Unless we're already attached, do some initialization RefMutexUnlock initGuard; JAttachment* jAtt = init(tdbb, expanded_name, is_alias ? org_filename : expanded_name, - config, true, options, initGuard); + config, true, options, initGuard, pluginConfig); dbb = tdbb->getDatabase(); fb_assert(dbb); @@ -1431,6 +1433,9 @@ SDW_init(tdbb, options.dpb_activate_shadow, options.dpb_delete_shadow); CCH_init2(tdbb); + // linger + dbb->dbb_linger_seconds = MET_get_linger(tdbb); + // Init complete - we can release dbInitMutex dbb->dbb_flags &= ~DBB_new; guardDbInit.leave(); @@ -1464,6 +1469,11 @@ attachment->att_flags |= ATT_no_cleanup; } + if (options.dpb_nolinger) + { + dbb->dbb_linger_seconds = 0; + } + if (options.dpb_disable_wal) { ERR_post(Arg::Gds(isc_lock_timeout) << @@ -2422,7 +2432,7 @@ // Unless we're already attached, do some initialization RefMutexUnlock initGuard; JAttachment* jAtt = init(tdbb, expanded_name, (is_alias ? org_filename : expanded_name), - config, false, options, initGuard); + config, false, options, initGuard, pluginConfig); dbb = tdbb->getDatabase(); fb_assert(dbb); @@ -2783,12 +2793,16 @@ if (attachment->att_in_use) status_exception::raise(Arg::Gds(isc_attachment_in_use)); - const bool force = engineShutdown || + unsigned flags = PURGE_LINGER; + if (engineShutdown || (dbb->dbb_ast_flags & DBB_shutdown) || - (attachment->att_flags & ATT_shutdown); + (attachment->att_flags & ATT_shutdown)) + { + flags |= PURGE_FORCE; + } attachment->signalShutdown(); - purge_attachment(tdbb, this, force); + purge_attachment(tdbb, this, flags); att = NULL; } @@ -2927,7 +2941,7 @@ const jrd_file* file = pageSpace->file; const Shadow* shadow = dbb->dbb_shadow; - if (shutdown_database(dbb, false)) + if (JRD_shutdown_database(dbb)) { // This point on database is useless @@ -5685,6 +5699,10 @@ dpb_overwrite = rdr.getInt() != 0; break; + case isc_dpb_nolinger: + dpb_nolinger = true; + break; + case isc_dpb_sec_attach: dpb_sec_attach = rdr.getInt() != 0; if (dpb_sec_attach) @@ -5857,7 +5875,8 @@ RefPtr<Config> config, bool attach_flag, // only for shared cache const DatabaseOptions& options, - RefMutexUnlock& initGuard) + RefMutexUnlock& initGuard, + IPluginConfig* pConf) { /************************************** * @@ -5933,6 +5952,11 @@ tdbb->setDatabase(dbb); jAtt = create_attachment(alias_name, dbb, options); + if (dbb->dbb_linger_timer) + { + dbb->dbb_linger_timer->reset(); + } + tdbb->setAttachment(jAtt->getHandle()); if (options.dpb_config.hasData()) @@ -5962,7 +5986,7 @@ Config::merge(config, &options.dpb_config); - dbb = Database::create(); + dbb = Database::create(pConf); dbb->dbb_config = config; dbb->dbb_filename = expanded_name; @@ -6339,19 +6363,39 @@ } -static bool shutdown_database(Database* dbb, const bool release_pools) +static void setEngineReleaseDelay(Database* dbb) { -/************************************** + unsigned maxLinger = 0; + { // scope + MutexLockGuard listGuardForLinger(databases_mutex, FB_FUNCTION); + for (Database* d = databases; d; d = d->dbb_next) + { + if ((!d->dbb_attachments) && (d->dbb_linger_end > maxLinger)) + { + maxLinger = d->dbb_linger_end; + } + } + } + + ++maxLinger; // avoid rounding errors + time_t t = time(NULL); + dbb->dbb_plugin_config->setReleaseDelay(maxLinger > t ? (maxLinger - t) * 1000 * 1000 : 0); +} + + +bool JRD_shutdown_database(Database* dbb, const unsigned flags) +{ +/************************************************* * - * s h u t d o w n _ d a t a b a s e + * J R D _ s h u t d o w n _ d a t a b a s e * - ************************************** + ************************************************* * * Functional description * Shutdown physical database environment. * **************************************/ - thread_db* tdbb = JRD_get_thread_data(); + ThreadContextHolder tdbb(dbb, NULL); RefMutexUnlock finiGuard; @@ -6389,6 +6433,29 @@ if (dbb->dbb_attachments) return false; + // Database linger + if ((flags & SHUT_DBB_LINGER) && + (!(engineShutdown || (dbb->dbb_ast_flags & DBB_shutdown))) && + (dbb->dbb_linger_seconds > 0) && + dbb->dbb_config->getSharedCache()) + { + if (!dbb->dbb_linger_timer) + { + dbb->dbb_linger_timer = new Database::Linger(dbb); + } + + dbb->dbb_linger_end = time(NULL) + dbb->dbb_linger_seconds; + dbb->dbb_linger_timer->set(dbb->dbb_linger_seconds); + + setEngineReleaseDelay(dbb); + + return false; + } + + // Reset provider unload delay if needed + dbb->dbb_linger_end = 0; + setEngineReleaseDelay(dbb); + // Deactivate dbb_init_fini lock // Since that moment dbb becomes not reusable dbb->dbb_init_fini->destroy(); @@ -6457,7 +6524,7 @@ } } - if (release_pools) + if (flags & SHUT_DBB_RELEASE_POOLS) { tdbb->setDatabase(NULL); Database::destroy(dbb); @@ -6657,7 +6724,7 @@ } -static void purge_attachment(thread_db* tdbb, JAttachment* jAtt, const bool force_flag) +static void purge_attachment(thread_db* tdbb, JAttachment* jAtt, unsigned flags) { /************************************** * @@ -6781,7 +6848,7 @@ } catch (const Exception&) { - if (!force_flag) + if (!(flags & PURGE_FORCE)) { attachment->att_flags |= ATT_shutdown; attachment->att_flags &= ~ATT_purge_started; @@ -6801,12 +6868,12 @@ if (!(dbb->dbb_flags & DBB_bugcheck)) { // Check for any pending transactions - purge_transactions(tdbb, attachment, force_flag); + purge_transactions(tdbb, attachment, flags & PURGE_FORCE); } } catch (const Exception&) { - if (!force_flag) + if (!(flags & PURGE_FORCE)) { attachment->att_flags |= ATT_shutdown; attachment->att_flags &= ~ATT_purge_started; @@ -6840,8 +6907,8 @@ asyncGuard.leave(); MutexUnlockGuard cout(*attMutex, FB_FUNCTION); - // If there are still attachments, do a partial shutdown - shutdown_database(dbb, true); + // Try to close database if there are no attachments + JRD_shutdown_database(dbb, SHUT_DBB_RELEASE_POOLS | (flags & PURGE_LINGER ? SHUT_DBB_LINGER : 0)); } @@ -7105,7 +7172,7 @@ } } - shutdown_database(dbb, true); + JRD_shutdown_database(dbb, SHUT_DBB_RELEASE_POOLS); } } catch (const Exception&) @@ -7155,7 +7222,7 @@ { // purge attachment, rollback any open transactions attachment->att_use_count++; - purge_attachment(tdbb, jAtt, true); + purge_attachment(tdbb, jAtt, PURGE_FORCE); } catch (const Exception& ex) { @@ -7241,6 +7308,20 @@ // Shutdown existing attachments success = success && shutdownAttachments(attachments); + { // scope + MutexLockGuard guard(databases_mutex, FB_FUNCTION); + + for (Database** ptrDbb = &databases; *ptrDbb;) + { + Database* dbb = *ptrDbb; + JRD_shutdown_database(dbb, SHUT_DBB_RELEASE_POOLS); + if (dbb == *ptrDbb) + { + ptrDbb = &(dbb->dbb_next); + } + } + // No need in databases_mutex any more + } // Extra shutdown operations Service::shutdownServices(); } Modified: firebird/trunk/src/jrd/jrd_proto.h =================================================================== --- firebird/trunk/src/jrd/jrd_proto.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/jrd_proto.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -76,4 +76,10 @@ bool JRD_verify_database_access(const Firebird::PathName&); void JRD_shutdown_attachments(Jrd::Database* dbb); void JRD_cancel_operation(Jrd::thread_db* tdbb, Jrd::Attachment* attachment, int option); + +bool JRD_shutdown_database(Jrd::Database* dbb, const unsigned flags = 0); +// JRD_shutdown_database() flags +static const unsigned SHUT_DBB_RELEASE_POOLS = 0x01; +static const unsigned SHUT_DBB_LINGER = 0x02; + #endif /* JRD_JRD_PROTO_H */ Modified: firebird/trunk/src/jrd/met.epp =================================================================== --- firebird/trunk/src/jrd/met.epp 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/met.epp 2013-11-14 16:16:24 UTC (rev 58787) @@ -5009,3 +5009,33 @@ return false; } + +int MET_get_linger(Jrd::thread_db* tdbb) +{ +/************************************** + * + * M E T _ g e t _ l i n g e r + * + ************************************** + * + * Functional description + * Return linger value for current database + * + **************************************/ + SET_TDBB(tdbb); + Jrd::Attachment* attachment = tdbb->getAttachment(); + int rc = 0; + + AutoCacheRequest request(tdbb, irq_linger, IRQ_REQUESTS); + FOR(REQUEST_HANDLE request) + DAT IN RDB$DATABASE + { + if (!DAT.RDB$LINGER.NULL) + { + rc = DAT.RDB$LINGER; + } + } + END_FOR + + return rc; +} Modified: firebird/trunk/src/jrd/met_proto.h =================================================================== --- firebird/trunk/src/jrd/met_proto.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/met_proto.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -129,5 +129,5 @@ Firebird::MetaName MET_get_relation_field(Jrd::thread_db*, MemoryPool& csbPool, const Firebird::MetaName&, const Firebird::MetaName&, dsc*, Jrd::FieldInfo*); void MET_update_partners(Jrd::thread_db*); - +int MET_get_linger(Jrd::thread_db*); #endif // JRD_MET_PROTO_H Modified: firebird/trunk/src/jrd/names.h =================================================================== --- firebird/trunk/src/jrd/names.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/names.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -248,6 +248,7 @@ NAME("RDB$SOURCE_INFO", nam_src_info) NAME("RDB$ENGINE_NAME", nam_engine_name) +NAME("RDB$LINGER", nam_linger) NAME("RDB$PACKAGES", nam_packages) NAME("RDB$PACKAGE_NAME", nam_pkg_name) Modified: firebird/trunk/src/jrd/relations.h =================================================================== --- firebird/trunk/src/jrd/relations.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/relations.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -38,6 +38,7 @@ FIELD(f_dat_id, nam_r_id, fld_r_id, 0, ODS_8_0) FIELD(f_dat_class, nam_class, fld_class, 1, ODS_8_0) FIELD(f_dat_charset, nam_charset_name, fld_charset_name, 1, ODS_8_0) + FIELD(f_dat_linger, nam_linger, fld_linger, 1, ODS_12_0) END_RELATION // Relation 2 (RDB$FIELDS) Modified: firebird/trunk/src/jrd/tra.h =================================================================== --- firebird/trunk/src/jrd/tra.h 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/tra.h 2013-11-14 16:16:24 UTC (rev 58787) @@ -502,7 +502,8 @@ dfw_arg_trg_type, // trigger type dfw_arg_new_name, // new name dfw_arg_field_not_null, // set domain to not nullable - dfw_db_crypt // change database encryption status + dfw_db_crypt, // change database encryption status + dfw_set_linger // set database linger }; // Verb actions Modified: firebird/trunk/src/jrd/vio.cpp =================================================================== --- firebird/trunk/src/jrd/vio.cpp 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/jrd/vio.cpp 2013-11-14 16:16:24 UTC (rev 58787) @@ -2362,6 +2362,12 @@ { case rel_database: check_class(tdbb, transaction, org_rpb, new_rpb, f_dat_class); + EVL_field(0, org_rpb->rpb_record, f_dat_linger, &desc1); + EVL_field(0, new_rpb->rpb_record, f_dat_linger, &desc2); + if (MOV_compare(&desc1, &desc2)) + { + DFW_post_work(transaction, dfw_set_linger, &desc2, 0); + } break; case rel_relations: Modified: firebird/trunk/src/msgs/facilities2.sql =================================================================== --- firebird/trunk/src/msgs/facilities2.sql 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/msgs/facilities2.sql 2013-11-14 16:16:24 UTC (rev 58787) @@ -3,7 +3,7 @@ -- ('2013-11-05 13:18:17', 'JRD', 0, 752) ('2012-01-23 20:10:30', 'QLI', 1, 532) -('2009-07-16 05:26:11', 'GFIX', 3, 121) +('2013-11-13 15:59:10', 'GFIX', 3, 122) ('1996-11-07 13:39:40', 'GPRE', 4, 1) ('2012-08-27 21:26:00', 'DSQL', 7, 33) ('2013-09-05 12:40:00', 'DYN', 8, 286) Modified: firebird/trunk/src/msgs/messages2.sql =================================================================== --- firebird/trunk/src/msgs/messages2.sql 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/msgs/messages2.sql 2013-11-14 16:16:24 UTC (rev 58787) @@ -1591,6 +1591,7 @@ (NULL, 'ALICE_gfix', 'alice.cpp', NULL, 3, 118, NULL, 'empty password file @1', NULL, NULL); (NULL, 'ALICE_gfix', 'alice.cpp', NULL, 3, 119, NULL, ' -fe(tch_password) fetch password from file', NULL, NULL); (NULL, 'alice', 'alice.cpp', NULL, 3, 120, NULL, 'usage: gfix [options] <database>', NULL, NULL); +('gfix_opt_nolinger', 'ALICE_gfix', 'alice.c', NULL, 3, 121, NULL, ' -nol(inger) close database ignoring linger setting for it', NULL, NULL); -- DSQL ('dsql_dbkey_from_non_table', 'MAKE_desc', 'make.c', NULL, 7, 2, NULL, 'Cannot SELECT RDB$DB_KEY from a stored procedure.', NULL, NULL); ('dsql_transitional_numeric', 'dsql_yyparse', 'parse.y', NULL, 7, 3, NULL, 'Precision 10 to 18 changed from DOUBLE PRECISION in SQL dialect 1 to 64-bit scaled integer in SQL dialect 3', NULL, NULL); Modified: firebird/trunk/src/remote/server/os/posix/inet_server.cpp =================================================================== --- firebird/trunk/src/remote/server/os/posix/inet_server.cpp 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/remote/server/os/posix/inet_server.cpp 2013-11-14 16:16:24 UTC (rev 58787) @@ -400,7 +400,7 @@ const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig()); const char* path = defConf->getSecurityDatabase(); - const char dpb[] = {isc_dpb_version1, isc_dpb_gsec_attach, 1, 1, isc_dpb_address_path, 0}; + const char dpb[] = {isc_dpb_version1, isc_dpb_sec_attach, 1, 1, isc_dpb_address_path, 0}; isc_attach_database(status, strlen(path), path, &db_handle, sizeof dpb, dpb); if (status[0] == 1 && status[1] > 0) Modified: firebird/trunk/src/utilities/fbsvcmgr/fbsvcmgr.cpp =================================================================== --- firebird/trunk/src/utilities/fbsvcmgr/fbsvcmgr.cpp 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/utilities/fbsvcmgr/fbsvcmgr.cpp 2013-11-14 16:16:24 UTC (rev 58787) @@ -390,6 +390,7 @@ {"prp_transactions_shutdown", putNumericArgument, 0, isc_spb_prp_transactions_shutdown, 0}, {"prp_shutdown_mode", putShutdownMode, 0, isc_spb_prp_shutdown_mode, 0}, {"prp_online_mode", putShutdownMode, 0, isc_spb_prp_online_mode, 0}, + {"prp_nolinger", putOption, 0, isc_spb_prp_nolinger, 0}, {0, 0, 0, 0, 0} }; Modified: firebird/trunk/src/yvalve/PluginManager.cpp =================================================================== --- firebird/trunk/src/yvalve/PluginManager.cpp 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/yvalve/PluginManager.cpp 2013-11-14 16:16:24 UTC (rev 58787) @@ -406,7 +406,8 @@ RefPtr<ConfigFile> pconfig, const PathName& pconfName, const PathName& pplugName) : module(pmodule), regPlugin(preg), defaultConfig(pconfig), - confName(getPool(), pconfName), plugName(getPool(), pplugName) + confName(getPool(), pconfName), plugName(getPool(), pplugName), + delay(DEFAULT_DELAY) { if (defaultConfig.hasData()) { @@ -461,6 +462,19 @@ return plugName.c_str(); } + void setReleaseDelay(ISC_UINT64 microSeconds) + { +#ifdef DEBUG_PLUGINS + fprintf(stderr, "Set delay for ConfiguredPlugin %s:%p\n", plugName.c_str(), this); +#endif + delay = microSeconds > DEFAULT_DELAY ? microSeconds : DEFAULT_DELAY; + } + + ISC_UINT64 getReleaseDelay() + { + return delay; + } + // ITimer implementation void FB_CARG handler() { } @@ -473,6 +487,9 @@ RefPtr<ConfigFile> defaultConfig; PathName confName; PathName plugName; + + static const FB_UINT64 DEFAULT_DELAY = 1000000; // 1 sec + FB_UINT64 delay; }; // Provides per-database configuration from databases.conf. @@ -506,6 +523,11 @@ return firebirdConf; } + void FB_CARG setReleaseDelay(ISC_UINT64 microSeconds) + { + configuredPlugin->setReleaseDelay(microSeconds); + } + int FB_CARG release() { if (--refCounter == 0) @@ -521,9 +543,10 @@ ~FactoryParameter() { #ifdef DEBUG_PLUGINS - fprintf(stderr, "~FactoryParameter places configuredPlugin %s in unload query\n", configuredPlugin->getPlugName()); + fprintf(stderr, "~FactoryParameter places configuredPlugin %s in unload query for %d seconds\n", + configuredPlugin->getPlugName(), configuredPlugin->getReleaseDelay() / 1000000); #endif - TimerInterfacePtr()->start(configuredPlugin, 1000000); // 1 sec + TimerInterfacePtr()->start(configuredPlugin, configuredPlugin->getReleaseDelay()); } RefPtr<ConfiguredPlugin> configuredPlugin; @@ -532,13 +555,17 @@ IPluginBase* ConfiguredPlugin::factory(IFirebirdConf* firebirdConf) { - RefPtr<FactoryParameter> par(new FactoryParameter(this, firebirdConf)); + FactoryParameter* par = new FactoryParameter(this, firebirdConf); + par->addRef(); IPluginBase* plugin = module->getPlugin(regPlugin).factory->createPlugin(par); if (plugin) { - par->addRef(); plugin->setOwner(par); } + else + { + par->release(); + } return plugin; } Modified: firebird/trunk/src/yvalve/keywords.cpp =================================================================== --- firebird/trunk/src/yvalve/keywords.cpp 2013-11-14 15:36:59 UTC (rev 58786) +++ firebird/trunk/src/yvalve/keywords.cpp 2013-11-14 16:16:24 UTC (rev 58787) @@ -243,6 +243,7 @@ {LEVEL, "LEVEL", 1, false}, {LIKE, "LIKE", 1, false}, {LIMBO, "LIMBO", 2, true}, + {LINGER, "LINGER", 2, true}, {LIST, "LIST", 2, false}, {LN, "LN", 2, false}, {LOCK, "LOCK", 2, true}, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |