| 
      
      
      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.
 |