mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-02-02 08:40:39 +01:00
Implemented CORE-4263: Database linger
This commit is contained in:
parent
ae5e485cc5
commit
120b10a78a
@ -223,3 +223,16 @@ export FB_EXPECTED_DB=employee
|
|||||||
fbsvcmgr host:service_mgr user sysdba password xxx action_db_stats dbname employee sts_data_pages
|
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.
|
Certainly any other database action can be used here.
|
||||||
|
|
||||||
|
|
||||||
|
6) Services API extension - using services to temporary turn off linger for database.
|
||||||
|
(Alex Peshkov, peshkoff@mail.ru, 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
|
||||||
|
34
doc/sql.extensions/README.linger
Normal file
34
doc/sql.extensions/README.linger
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
SQL Language Extension: ALTER DATABASE SET/DROP LINGER
|
||||||
|
|
||||||
|
Implements capability to manage database linger.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
Alex Peshkoff <peshkoff@mail.ru>
|
||||||
|
|
||||||
|
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).
|
@ -63,6 +63,7 @@ const SINT64 sw_trusted_auth = QUADCONST(0x0000000100000000); // Byte 4, Bit 0
|
|||||||
const SINT64 sw_trusted_svc = QUADCONST(0x0000000200000000);
|
const SINT64 sw_trusted_svc = QUADCONST(0x0000000200000000);
|
||||||
const SINT64 sw_trusted_role = QUADCONST(0x0000000400000000);
|
const SINT64 sw_trusted_role = QUADCONST(0x0000000400000000);
|
||||||
const SINT64 sw_fetch_password = QUADCONST(0x0000000800000000);
|
const SINT64 sw_fetch_password = QUADCONST(0x0000000800000000);
|
||||||
|
const SINT64 sw_nolinger = QUADCONST(0x0000001000000000);
|
||||||
|
|
||||||
|
|
||||||
enum alice_switches
|
enum alice_switches
|
||||||
@ -117,7 +118,8 @@ enum alice_switches
|
|||||||
IN_SW_ALICE_TRUSTED_USER = 45,
|
IN_SW_ALICE_TRUSTED_USER = 45,
|
||||||
IN_SW_ALICE_TRUSTED_ROLE = 46,
|
IN_SW_ALICE_TRUSTED_ROLE = 46,
|
||||||
IN_SW_ALICE_HIDDEN_ONLINE = 47,
|
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";
|
static const char* const ALICE_SW_ASYNC = "ASYNC";
|
||||||
@ -129,7 +131,7 @@ static const char* const ALICE_SW_MODE_RW = "READ_WRITE";
|
|||||||
static const Switches::in_sw_tab_t alice_in_sw_table[] =
|
static const Switches::in_sw_tab_t alice_in_sw_table[] =
|
||||||
{
|
{
|
||||||
{IN_SW_ALICE_ACTIVATE, isc_spb_prp_activate, "ACTIVATE_SHADOW", sw_activate,
|
{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
|
// msg 25: \t-activate shadow file for database usage
|
||||||
{IN_SW_ALICE_ATTACH, isc_spb_prp_attachments_shutdown, "ATTACH", sw_attach,
|
{IN_SW_ALICE_ATTACH, isc_spb_prp_attachments_shutdown, "ATTACH", sw_attach,
|
||||||
sw_shut, 0, false, 26, 2, NULL},
|
sw_shut, 0, false, 26, 2, NULL},
|
||||||
@ -145,7 +147,7 @@ static const Switches::in_sw_tab_t alice_in_sw_table[] =
|
|||||||
0, 0, false, 28, 1, NULL},
|
0, 0, false, 28, 1, NULL},
|
||||||
// msg 28: \t-buffers\tset page buffers <n>
|
// msg 28: \t-buffers\tset page buffers <n>
|
||||||
{IN_SW_ALICE_COMMIT, isc_spb_rpr_commit_trans, "COMMIT", sw_commit,
|
{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>
|
// msg 29: \t-commit\t\tcommit transaction <tr / all>
|
||||||
{IN_SW_ALICE_CACHE, 0, "CACHE", sw_cache,
|
{IN_SW_ALICE_CACHE, 0, "CACHE", sw_cache,
|
||||||
sw_shut, 0, false, 30, 2, NULL},
|
sw_shut, 0, false, 30, 2, NULL},
|
||||||
@ -176,14 +178,17 @@ static const Switches::in_sw_tab_t alice_in_sw_table[] =
|
|||||||
0, 0, false, 36, 1, NULL},
|
0, 0, false, 36, 1, NULL},
|
||||||
// msg 36: \t-kill\t\tkill all unavailable shadow files
|
// msg 36: \t-kill\t\tkill all unavailable shadow files
|
||||||
{IN_SW_ALICE_LIST, isc_spb_rpr_list_limbo_trans, "LIST", sw_list,
|
{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
|
// msg 37: \t-list\t\tshow limbo transactions
|
||||||
{IN_SW_ALICE_MEND, isc_spb_rpr_mend_db, "MEND", sw_mend | sw_validate | sw_full,
|
{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
|
// msg 38: \t-mend\t\tprepare corrupt database for backup
|
||||||
{IN_SW_ALICE_MODE, 0, "MODE", sw_mode,
|
{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
|
// 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,
|
{IN_SW_ALICE_NO_UPDATE, isc_spb_rpr_check_db, "NO_UPDATE", sw_no_update,
|
||||||
sw_validate, 0, false, 39, 1, NULL},
|
sw_validate, 0, false, 39, 1, NULL},
|
||||||
// msg 39: \t-no_update\tread-only validation (-v)
|
// msg 39: \t-no_update\tread-only validation (-v)
|
||||||
@ -205,20 +210,20 @@ static const Switches::in_sw_tab_t alice_in_sw_table[] =
|
|||||||
*/
|
*/
|
||||||
#endif
|
#endif
|
||||||
{IN_SW_ALICE_ROLLBACK, isc_spb_rpr_rollback_trans, "ROLLBACK", sw_rollback,
|
{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>
|
// 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,
|
{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},
|
0, 0, false, 111, 2, NULL},
|
||||||
// msg 111: \t-SQL_dialect\t\set dataabse dialect n
|
// msg 111: \t-SQL_dialect\t\set dataabse dialect n
|
||||||
{IN_SW_ALICE_SWEEP, isc_spb_rpr_sweep_db, "SWEEP", sw_sweep,
|
{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
|
// msg 45: \t-sweep\t\tforce garbage collection
|
||||||
{IN_SW_ALICE_SHUT, isc_spb_prp_shutdown_mode, "SHUTDOWN", sw_shut,
|
{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),
|
0, ~(sw_shut | sw_attach | sw_cache | sw_force | sw_tran | sw_user | sw_password),
|
||||||
false, 46, 2, NULL},
|
false, 46, 2, NULL},
|
||||||
// msg 46: \t-shut\t\tshutdown
|
// msg 46: \t-shut\t\tshutdown
|
||||||
{IN_SW_ALICE_TWO_PHASE, isc_spb_rpr_recover_two_phase, "TWO_PHASE", sw_two_phase,
|
{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
|
// msg 47: \t-two_phase\tperform automated two-phase recovery
|
||||||
{IN_SW_ALICE_TRAN, isc_spb_prp_transactions_shutdown, "TRANSACTION", sw_tran,
|
{IN_SW_ALICE_TRAN, isc_spb_prp_transactions_shutdown, "TRANSACTION", sw_tran,
|
||||||
sw_shut, 0, false, 48, 3, NULL},
|
sw_shut, 0, false, 48, 3, NULL},
|
||||||
@ -233,16 +238,16 @@ static const Switches::in_sw_tab_t alice_in_sw_table[] =
|
|||||||
{IN_SW_ALICE_TRUSTED_ROLE, 0, TRUSTED_ROLE_SWITCH, sw_trusted_role,
|
{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},
|
sw_trusted_svc, (sw_user | sw_password), false, 0, TRUSTED_ROLE_SWITCH_LEN, NULL},
|
||||||
{IN_SW_ALICE_NO_RESERVE, 0, "USE", sw_no_reserve,
|
{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
|
// msg 49: \t-use\t\tuse full or reserve space for versions
|
||||||
{IN_SW_ALICE_USER, 0, "USER", sw_user,
|
{IN_SW_ALICE_USER, 0, "USER", sw_user,
|
||||||
0, (sw_trusted_auth | sw_trusted_svc | sw_trusted_role), false, 50, 4, NULL},
|
0, (sw_trusted_auth | sw_trusted_svc | sw_trusted_role), false, 50, 4, NULL},
|
||||||
// msg 50: \t-user\t\tdefault user name
|
// msg 50: \t-user\t\tdefault user name
|
||||||
{IN_SW_ALICE_VALIDATE, isc_spb_rpr_validate_db, "VALIDATE", sw_validate,
|
{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
|
// msg 51: \t-validate\tvalidate database structure
|
||||||
{IN_SW_ALICE_WRITE, 0, "WRITE", sw_write,
|
{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
|
// msg 52: \t-write\t\twrite synchronously or asynchronously
|
||||||
#ifdef DEV_BUILD
|
#ifdef DEV_BUILD
|
||||||
{IN_SW_ALICE_X, 0, "X", 0,
|
{IN_SW_ALICE_X, 0, "X", 0,
|
||||||
|
@ -323,6 +323,9 @@ static void buildDpb(Firebird::ClumpletWriter& dpb, const SINT64 switches)
|
|||||||
dpb.insertInt(isc_dpb_set_db_sql_dialect, tdgbl->ALICE_data.ua_db_SQL_dialect);
|
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;
|
const unsigned char* authBlock;
|
||||||
unsigned int authBlockSize = tdgbl->uSvc->getAuthBlock(&authBlock);
|
unsigned int authBlockSize = tdgbl->uSvc->getAuthBlock(&authBlock);
|
||||||
|
|
||||||
|
@ -28,6 +28,12 @@ CREATE DOMAIN PLG$PASSWD AS VARCHAR(64) CHARACTER SET BINARY;
|
|||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
||||||
|
|
||||||
|
/* Linger is definitely useful for security database */
|
||||||
|
ALTER DATABASE SET LINGER TO 60; /* one minute */
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
|
||||||
/* Table: RDB$USERS */
|
/* Table: RDB$USERS */
|
||||||
CREATE TABLE PLG$USERS (
|
CREATE TABLE PLG$USERS (
|
||||||
PLG$USER_NAME SEC$USER_NAME NOT NULL PRIMARY KEY,
|
PLG$USER_NAME SEC$USER_NAME NOT NULL PRIMARY KEY,
|
||||||
|
@ -10056,6 +10056,12 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
|
|||||||
alterCharSetNode.execute(tdbb, dsqlScratch, transaction);
|
alterCharSetNode.execute(tdbb, dsqlScratch, transaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (linger >= 0)
|
||||||
|
{
|
||||||
|
DBB.RDB$LINGER.NULL = FALSE;
|
||||||
|
DBB.RDB$LINGER = linger;
|
||||||
|
}
|
||||||
|
|
||||||
if (clauses & CLAUSE_BEGIN_BACKUP)
|
if (clauses & CLAUSE_BEGIN_BACKUP)
|
||||||
changeBackupMode(tdbb, transaction, CLAUSE_BEGIN_BACKUP);
|
changeBackupMode(tdbb, transaction, CLAUSE_BEGIN_BACKUP);
|
||||||
|
|
||||||
|
@ -1945,6 +1945,7 @@ public:
|
|||||||
: DdlNode(p),
|
: DdlNode(p),
|
||||||
create(false),
|
create(false),
|
||||||
createLength(0),
|
createLength(0),
|
||||||
|
linger(-1),
|
||||||
clauses(0),
|
clauses(0),
|
||||||
differenceFile(p),
|
differenceFile(p),
|
||||||
setDefaultCharSet(p),
|
setDefaultCharSet(p),
|
||||||
@ -1977,7 +1978,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
bool create; // Is the node created with a CREATE DATABASE command?
|
bool create; // Is the node created with a CREATE DATABASE command?
|
||||||
SLONG createLength;
|
SLONG createLength, linger;
|
||||||
unsigned clauses;
|
unsigned clauses;
|
||||||
Firebird::string differenceFile;
|
Firebird::string differenceFile;
|
||||||
Firebird::MetaName setDefaultCharSet;
|
Firebird::MetaName setDefaultCharSet;
|
||||||
|
@ -561,6 +561,7 @@ using namespace Firebird;
|
|||||||
%token <metaNamePtr> UNKNOWN
|
%token <metaNamePtr> UNKNOWN
|
||||||
%token <metaNamePtr> USAGE
|
%token <metaNamePtr> USAGE
|
||||||
%token <metaNamePtr> RDB_RECORD_VERSION
|
%token <metaNamePtr> RDB_RECORD_VERSION
|
||||||
|
%token <metaNamePtr> LINGER
|
||||||
|
|
||||||
// precedence declarations for expression evaluation
|
// precedence declarations for expression evaluation
|
||||||
|
|
||||||
@ -3697,6 +3698,10 @@ db_alter_clause($alterDatabaseNode)
|
|||||||
{ $alterDatabaseNode->cryptPlugin = *$3; }
|
{ $alterDatabaseNode->cryptPlugin = *$3; }
|
||||||
| DECRYPT
|
| DECRYPT
|
||||||
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_DECRYPT; }
|
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_DECRYPT; }
|
||||||
|
| SET LINGER TO long_integer
|
||||||
|
{ $alterDatabaseNode->linger = $4; }
|
||||||
|
| DROP LINGER
|
||||||
|
{ $alterDatabaseNode->linger = 0; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
@ -7111,6 +7116,7 @@ non_reserved_word
|
|||||||
| RANK
|
| RANK
|
||||||
| ROW_NUMBER
|
| ROW_NUMBER
|
||||||
| USAGE
|
| USAGE
|
||||||
|
| LINGER
|
||||||
;
|
;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
@ -120,6 +120,7 @@
|
|||||||
#define isc_dpb_auth_plugin_list 85
|
#define isc_dpb_auth_plugin_list 85
|
||||||
#define isc_dpb_auth_plugin_name 86
|
#define isc_dpb_auth_plugin_name 86
|
||||||
#define isc_dpb_config 87
|
#define isc_dpb_config 87
|
||||||
|
#define isc_dpb_nolinger 88
|
||||||
|
|
||||||
/**************************************************/
|
/**************************************************/
|
||||||
/* clumplet tags used inside isc_dpb_address_path */
|
/* clumplet tags used inside isc_dpb_address_path */
|
||||||
@ -403,6 +404,7 @@
|
|||||||
#define isc_spb_prp_set_sql_dialect 14
|
#define isc_spb_prp_set_sql_dialect 14
|
||||||
#define isc_spb_prp_activate 0x0100
|
#define isc_spb_prp_activate 0x0100
|
||||||
#define isc_spb_prp_db_online 0x0200
|
#define isc_spb_prp_db_online 0x0200
|
||||||
|
#define isc_spb_prp_nolinger 0x0400
|
||||||
#define isc_spb_prp_force_shutdown 41
|
#define isc_spb_prp_force_shutdown 41
|
||||||
#define isc_spb_prp_attachments_shutdown 42
|
#define isc_spb_prp_attachments_shutdown 42
|
||||||
#define isc_spb_prp_transactions_shutdown 43
|
#define isc_spb_prp_transactions_shutdown 43
|
||||||
|
@ -146,8 +146,9 @@ public:
|
|||||||
virtual const char* FB_CARG getConfigFileName() = 0;
|
virtual const char* FB_CARG getConfigFileName() = 0;
|
||||||
virtual IConfig* FB_CARG getDefaultConfig() = 0;
|
virtual IConfig* FB_CARG getDefaultConfig() = 0;
|
||||||
virtual IFirebirdConf* FB_CARG getFirebirdConf() = 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
|
// Required to creat instances of given plugin
|
||||||
class IPluginFactory : public IVersioned
|
class IPluginFactory : public IVersioned
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
const USHORT f_dat_id = 1;
|
const USHORT f_dat_id = 1;
|
||||||
const USHORT f_dat_class = 2;
|
const USHORT f_dat_class = 2;
|
||||||
const USHORT f_dat_charset = 3;
|
const USHORT f_dat_charset = 3;
|
||||||
|
const USHORT f_dat_linger = 4;
|
||||||
|
|
||||||
|
|
||||||
// Relation 2 (RDB$FIELDS)
|
// Relation 2 (RDB$FIELDS)
|
||||||
|
@ -77,6 +77,11 @@ namespace Jrd
|
|||||||
|
|
||||||
Database::~Database()
|
Database::~Database()
|
||||||
{
|
{
|
||||||
|
if (dbb_linger_timer)
|
||||||
|
{
|
||||||
|
dbb_linger_timer->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
{ // scope
|
{ // scope
|
||||||
SyncLockGuard guard(&dbb_sortbuf_sync, SYNC_EXCLUSIVE, "Database::~Database");
|
SyncLockGuard guard(&dbb_sortbuf_sync, SYNC_EXCLUSIVE, "Database::~Database");
|
||||||
|
|
||||||
@ -313,4 +318,45 @@ namespace Jrd
|
|||||||
|
|
||||||
return 0;
|
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
|
} // namespace
|
||||||
|
@ -301,11 +301,31 @@ public:
|
|||||||
bool exist;
|
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;
|
Firebird::MemoryStats temp_stats;
|
||||||
MemoryPool* const pool = MemoryPool::createPool(NULL, 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);
|
pool->setStatsGroup(dbb->dbb_memory_stats);
|
||||||
return dbb;
|
return dbb;
|
||||||
}
|
}
|
||||||
@ -437,6 +457,10 @@ public:
|
|||||||
SharedCounter dbb_shared_counter;
|
SharedCounter dbb_shared_counter;
|
||||||
CryptoManager* dbb_crypto_manager;
|
CryptoManager* dbb_crypto_manager;
|
||||||
Firebird::RefPtr<ExistenceRefMutex> dbb_init_fini;
|
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
|
// returns true if primary file is located on raw device
|
||||||
bool onRawDevice() const;
|
bool onRawDevice() const;
|
||||||
@ -464,7 +488,7 @@ public:
|
|||||||
void deletePool(MemoryPool* pool);
|
void deletePool(MemoryPool* pool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Database(MemoryPool* p)
|
Database(MemoryPool* p, Firebird::IPluginConfig* pConf)
|
||||||
: dbb_permanent(p),
|
: dbb_permanent(p),
|
||||||
dbb_page_manager(this, *p),
|
dbb_page_manager(this, *p),
|
||||||
dbb_modules(*p),
|
dbb_modules(*p),
|
||||||
@ -478,7 +502,10 @@ private:
|
|||||||
dbb_tip_cache(NULL),
|
dbb_tip_cache(NULL),
|
||||||
dbb_creation_date(Firebird::TimeStamp::getCurrentTimeStamp()),
|
dbb_creation_date(Firebird::TimeStamp::getCurrentTimeStamp()),
|
||||||
dbb_external_file_directory_list(NULL),
|
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);
|
dbb_pools.add(p);
|
||||||
}
|
}
|
||||||
|
@ -453,8 +453,8 @@ private:
|
|||||||
class JProvider : public Firebird::StdPlugin<Firebird::IProvider, FB_PROVIDER_VERSION>
|
class JProvider : public Firebird::StdPlugin<Firebird::IProvider, FB_PROVIDER_VERSION>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit JProvider(Firebird::IPluginConfig*)
|
explicit JProvider(Firebird::IPluginConfig* pConf)
|
||||||
: cryptCallback(NULL)
|
: cryptCallback(NULL), pluginConfig(pConf)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,6 +479,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Firebird::ICryptKeyCallback* cryptCallback;
|
Firebird::ICryptKeyCallback* cryptCallback;
|
||||||
|
Firebird::IPluginConfig* pluginConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline JStatement::JStatement(dsql_req* handle, JAttachment* ja, Firebird::Array<UCHAR>& meta)
|
inline JStatement::JStatement(dsql_req* handle, JAttachment* ja, Firebird::Array<UCHAR>& meta)
|
||||||
|
@ -403,6 +403,7 @@ static bool drop_package_header(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
|||||||
static bool drop_package_body(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
static bool drop_package_body(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||||
static bool grant_privileges(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 db_crypt(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||||
|
static bool set_linger(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
|
||||||
|
|
||||||
// ----------------------------------------------------------------
|
// ----------------------------------------------------------------
|
||||||
|
|
||||||
@ -493,6 +494,7 @@ static const deferred_task task_table[] =
|
|||||||
{ dfw_check_not_null, check_not_null },
|
{ dfw_check_not_null, check_not_null },
|
||||||
{ dfw_store_view_context_type, store_view_context_type },
|
{ dfw_store_view_context_type, store_view_context_type },
|
||||||
{ dfw_db_crypt, db_crypt },
|
{ dfw_db_crypt, db_crypt },
|
||||||
|
{ dfw_set_linger, set_linger },
|
||||||
{ dfw_null, NULL }
|
{ dfw_null, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1526,6 +1528,36 @@ static bool db_crypt(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra*
|
|||||||
return false;
|
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)
|
static bool check_not_null(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
|
@ -177,3 +177,5 @@
|
|||||||
FIELD(fld_os_user , nam_os_user , dtype_varying , 255 , dsc_text_type_metadata , NULL , true)
|
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_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_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)
|
||||||
|
@ -165,6 +165,8 @@ enum irq_type_t
|
|||||||
irq_grant15, // process grant option (generators)
|
irq_grant15, // process grant option (generators)
|
||||||
irq_grant16, // process grant option (domains)
|
irq_grant16, // process grant option (domains)
|
||||||
|
|
||||||
|
irq_linger, // get database linger value
|
||||||
|
|
||||||
irq_MAX
|
irq_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
133
src/jrd/jrd.cpp
133
src/jrd/jrd.cpp
@ -335,7 +335,6 @@ int JProvider::release()
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void shutdownBeforeUnload()
|
static void shutdownBeforeUnload()
|
||||||
{
|
{
|
||||||
LocalStatus status;
|
LocalStatus status;
|
||||||
@ -837,6 +836,7 @@ public:
|
|||||||
bool dpb_utf8_filename;
|
bool dpb_utf8_filename;
|
||||||
ULONG dpb_ext_call_depth;
|
ULONG dpb_ext_call_depth;
|
||||||
ULONG dpb_flags; // to OR'd with dbb_flags
|
ULONG dpb_flags; // to OR'd with dbb_flags
|
||||||
|
bool dpb_nolinger;
|
||||||
|
|
||||||
// here begin compound objects
|
// here begin compound objects
|
||||||
// for constructor to work properly dpb_user_name
|
// for constructor to work properly dpb_user_name
|
||||||
@ -950,20 +950,22 @@ static VdnResult verifyDatabaseName(const PathName&, ISC_STATUS*, bool);
|
|||||||
static void unwindAttach(thread_db* tdbb, const Exception& ex, Firebird::IStatus* userStatus,
|
static void unwindAttach(thread_db* tdbb, const Exception& ex, Firebird::IStatus* userStatus,
|
||||||
Jrd::Attachment* attachment, Database* dbb);
|
Jrd::Attachment* attachment, Database* dbb);
|
||||||
static JAttachment* init(thread_db*, const PathName&, const PathName&, RefPtr<Config>, bool,
|
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 JAttachment* create_attachment(const PathName&, Database*, const DatabaseOptions&);
|
||||||
static void prepare_tra(thread_db*, jrd_tra*, USHORT, const UCHAR*);
|
static void prepare_tra(thread_db*, jrd_tra*, USHORT, const UCHAR*);
|
||||||
static void start_transaction(thread_db* tdbb, bool transliterate, jrd_tra** tra_handle,
|
static void start_transaction(thread_db* tdbb, bool transliterate, jrd_tra** tra_handle,
|
||||||
Jrd::Attachment* attachment, unsigned int tpb_length, const UCHAR* tpb);
|
Jrd::Attachment* attachment, unsigned int tpb_length, const UCHAR* tpb);
|
||||||
static void release_attachment(thread_db*, Jrd::Attachment*);
|
static void release_attachment(thread_db*, Jrd::Attachment*);
|
||||||
static void rollback(thread_db*, jrd_tra*, const bool);
|
static void rollback(thread_db*, jrd_tra*, const bool);
|
||||||
static bool shutdown_database(Database*, const bool);
|
|
||||||
static void strip_quotes(string&);
|
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 void getUserInfo(UserId&, const DatabaseOptions&, const char*, const RefPtr<Config>*);
|
||||||
|
|
||||||
static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM);
|
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) :
|
TraceFailedConnection::TraceFailedConnection(const char* filename, const DatabaseOptions* options) :
|
||||||
m_filename(filename),
|
m_filename(filename),
|
||||||
@ -1331,7 +1333,7 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
|||||||
// Unless we're already attached, do some initialization
|
// Unless we're already attached, do some initialization
|
||||||
RefMutexUnlock initGuard;
|
RefMutexUnlock initGuard;
|
||||||
JAttachment* jAtt = init(tdbb, expanded_name, is_alias ? org_filename : expanded_name,
|
JAttachment* jAtt = init(tdbb, expanded_name, is_alias ? org_filename : expanded_name,
|
||||||
config, true, options, initGuard);
|
config, true, options, initGuard, pluginConfig);
|
||||||
|
|
||||||
dbb = tdbb->getDatabase();
|
dbb = tdbb->getDatabase();
|
||||||
fb_assert(dbb);
|
fb_assert(dbb);
|
||||||
@ -1431,6 +1433,9 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
|||||||
SDW_init(tdbb, options.dpb_activate_shadow, options.dpb_delete_shadow);
|
SDW_init(tdbb, options.dpb_activate_shadow, options.dpb_delete_shadow);
|
||||||
CCH_init2(tdbb);
|
CCH_init2(tdbb);
|
||||||
|
|
||||||
|
// linger
|
||||||
|
dbb->dbb_linger_seconds = MET_get_linger(tdbb);
|
||||||
|
|
||||||
// Init complete - we can release dbInitMutex
|
// Init complete - we can release dbInitMutex
|
||||||
dbb->dbb_flags &= ~DBB_new;
|
dbb->dbb_flags &= ~DBB_new;
|
||||||
guardDbInit.leave();
|
guardDbInit.leave();
|
||||||
@ -1464,6 +1469,11 @@ JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char*
|
|||||||
attachment->att_flags |= ATT_no_cleanup;
|
attachment->att_flags |= ATT_no_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.dpb_nolinger)
|
||||||
|
{
|
||||||
|
dbb->dbb_linger_seconds = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (options.dpb_disable_wal)
|
if (options.dpb_disable_wal)
|
||||||
{
|
{
|
||||||
ERR_post(Arg::Gds(isc_lock_timeout) <<
|
ERR_post(Arg::Gds(isc_lock_timeout) <<
|
||||||
@ -2422,7 +2432,7 @@ JAttachment* FB_CARG JProvider::createDatabase(IStatus* user_status, const char*
|
|||||||
// Unless we're already attached, do some initialization
|
// Unless we're already attached, do some initialization
|
||||||
RefMutexUnlock initGuard;
|
RefMutexUnlock initGuard;
|
||||||
JAttachment* jAtt = init(tdbb, expanded_name, (is_alias ? org_filename : expanded_name),
|
JAttachment* jAtt = init(tdbb, expanded_name, (is_alias ? org_filename : expanded_name),
|
||||||
config, false, options, initGuard);
|
config, false, options, initGuard, pluginConfig);
|
||||||
|
|
||||||
dbb = tdbb->getDatabase();
|
dbb = tdbb->getDatabase();
|
||||||
fb_assert(dbb);
|
fb_assert(dbb);
|
||||||
@ -2783,12 +2793,16 @@ void JAttachment::freeEngineData(IStatus* user_status)
|
|||||||
if (attachment->att_in_use)
|
if (attachment->att_in_use)
|
||||||
status_exception::raise(Arg::Gds(isc_attachment_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) ||
|
(dbb->dbb_ast_flags & DBB_shutdown) ||
|
||||||
(attachment->att_flags & ATT_shutdown);
|
(attachment->att_flags & ATT_shutdown))
|
||||||
|
{
|
||||||
|
flags |= PURGE_FORCE;
|
||||||
|
}
|
||||||
|
|
||||||
attachment->signalShutdown();
|
attachment->signalShutdown();
|
||||||
purge_attachment(tdbb, this, force);
|
purge_attachment(tdbb, this, flags);
|
||||||
|
|
||||||
att = NULL;
|
att = NULL;
|
||||||
}
|
}
|
||||||
@ -2927,7 +2941,7 @@ void JAttachment::dropDatabase(IStatus* user_status)
|
|||||||
const jrd_file* file = pageSpace->file;
|
const jrd_file* file = pageSpace->file;
|
||||||
const Shadow* shadow = dbb->dbb_shadow;
|
const Shadow* shadow = dbb->dbb_shadow;
|
||||||
|
|
||||||
if (shutdown_database(dbb, false))
|
if (JRD_shutdown_database(dbb))
|
||||||
{
|
{
|
||||||
// This point on database is useless
|
// This point on database is useless
|
||||||
|
|
||||||
@ -5685,6 +5699,10 @@ void DatabaseOptions::get(const UCHAR* dpb, USHORT dpb_length, bool& invalid_cli
|
|||||||
dpb_overwrite = rdr.getInt() != 0;
|
dpb_overwrite = rdr.getInt() != 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case isc_dpb_nolinger:
|
||||||
|
dpb_nolinger = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case isc_dpb_sec_attach:
|
case isc_dpb_sec_attach:
|
||||||
dpb_sec_attach = rdr.getInt() != 0;
|
dpb_sec_attach = rdr.getInt() != 0;
|
||||||
if (dpb_sec_attach)
|
if (dpb_sec_attach)
|
||||||
@ -5857,7 +5875,8 @@ static JAttachment* init(thread_db* tdbb,
|
|||||||
RefPtr<Config> config,
|
RefPtr<Config> config,
|
||||||
bool attach_flag, // only for shared cache
|
bool attach_flag, // only for shared cache
|
||||||
const DatabaseOptions& options,
|
const DatabaseOptions& options,
|
||||||
RefMutexUnlock& initGuard)
|
RefMutexUnlock& initGuard,
|
||||||
|
IPluginConfig* pConf)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -5933,6 +5952,11 @@ static JAttachment* init(thread_db* tdbb,
|
|||||||
|
|
||||||
tdbb->setDatabase(dbb);
|
tdbb->setDatabase(dbb);
|
||||||
jAtt = create_attachment(alias_name, dbb, options);
|
jAtt = create_attachment(alias_name, dbb, options);
|
||||||
|
if (dbb->dbb_linger_timer)
|
||||||
|
{
|
||||||
|
dbb->dbb_linger_timer->reset();
|
||||||
|
}
|
||||||
|
|
||||||
tdbb->setAttachment(jAtt->getHandle());
|
tdbb->setAttachment(jAtt->getHandle());
|
||||||
|
|
||||||
if (options.dpb_config.hasData())
|
if (options.dpb_config.hasData())
|
||||||
@ -5962,7 +5986,7 @@ static JAttachment* init(thread_db* tdbb,
|
|||||||
|
|
||||||
Config::merge(config, &options.dpb_config);
|
Config::merge(config, &options.dpb_config);
|
||||||
|
|
||||||
dbb = Database::create();
|
dbb = Database::create(pConf);
|
||||||
dbb->dbb_config = config;
|
dbb->dbb_config = config;
|
||||||
dbb->dbb_filename = expanded_name;
|
dbb->dbb_filename = expanded_name;
|
||||||
|
|
||||||
@ -6339,19 +6363,39 @@ static void rollback(thread_db* tdbb, jrd_tra* transaction, const bool retaining
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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
|
* Functional description
|
||||||
* Shutdown physical database environment.
|
* Shutdown physical database environment.
|
||||||
*
|
*
|
||||||
**************************************/
|
**************************************/
|
||||||
thread_db* tdbb = JRD_get_thread_data();
|
ThreadContextHolder tdbb(dbb, NULL);
|
||||||
|
|
||||||
RefMutexUnlock finiGuard;
|
RefMutexUnlock finiGuard;
|
||||||
|
|
||||||
@ -6389,6 +6433,29 @@ static bool shutdown_database(Database* dbb, const bool release_pools)
|
|||||||
if (dbb->dbb_attachments)
|
if (dbb->dbb_attachments)
|
||||||
return false;
|
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
|
// Deactivate dbb_init_fini lock
|
||||||
// Since that moment dbb becomes not reusable
|
// Since that moment dbb becomes not reusable
|
||||||
dbb->dbb_init_fini->destroy();
|
dbb->dbb_init_fini->destroy();
|
||||||
@ -6457,7 +6524,7 @@ static bool shutdown_database(Database* dbb, const bool release_pools)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (release_pools)
|
if (flags & SHUT_DBB_RELEASE_POOLS)
|
||||||
{
|
{
|
||||||
tdbb->setDatabase(NULL);
|
tdbb->setDatabase(NULL);
|
||||||
Database::destroy(dbb);
|
Database::destroy(dbb);
|
||||||
@ -6657,7 +6724,7 @@ static void purge_transactions(thread_db* tdbb, Jrd::Attachment* attachment, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 @@ static void purge_attachment(thread_db* tdbb, JAttachment* jAtt, const bool forc
|
|||||||
}
|
}
|
||||||
catch (const Exception&)
|
catch (const Exception&)
|
||||||
{
|
{
|
||||||
if (!force_flag)
|
if (!(flags & PURGE_FORCE))
|
||||||
{
|
{
|
||||||
attachment->att_flags |= ATT_shutdown;
|
attachment->att_flags |= ATT_shutdown;
|
||||||
attachment->att_flags &= ~ATT_purge_started;
|
attachment->att_flags &= ~ATT_purge_started;
|
||||||
@ -6801,12 +6868,12 @@ static void purge_attachment(thread_db* tdbb, JAttachment* jAtt, const bool forc
|
|||||||
if (!(dbb->dbb_flags & DBB_bugcheck))
|
if (!(dbb->dbb_flags & DBB_bugcheck))
|
||||||
{
|
{
|
||||||
// Check for any pending transactions
|
// Check for any pending transactions
|
||||||
purge_transactions(tdbb, attachment, force_flag);
|
purge_transactions(tdbb, attachment, flags & PURGE_FORCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const Exception&)
|
catch (const Exception&)
|
||||||
{
|
{
|
||||||
if (!force_flag)
|
if (!(flags & PURGE_FORCE))
|
||||||
{
|
{
|
||||||
attachment->att_flags |= ATT_shutdown;
|
attachment->att_flags |= ATT_shutdown;
|
||||||
attachment->att_flags &= ~ATT_purge_started;
|
attachment->att_flags &= ~ATT_purge_started;
|
||||||
@ -6840,8 +6907,8 @@ static void purge_attachment(thread_db* tdbb, JAttachment* jAtt, const bool forc
|
|||||||
asyncGuard.leave();
|
asyncGuard.leave();
|
||||||
MutexUnlockGuard cout(*attMutex, FB_FUNCTION);
|
MutexUnlockGuard cout(*attMutex, FB_FUNCTION);
|
||||||
|
|
||||||
// If there are still attachments, do a partial shutdown
|
// Try to close database if there are no attachments
|
||||||
shutdown_database(dbb, true);
|
JRD_shutdown_database(dbb, SHUT_DBB_RELEASE_POOLS | (flags & PURGE_LINGER ? SHUT_DBB_LINGER : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -7105,7 +7172,7 @@ static void unwindAttach(thread_db* tdbb, const Exception& ex, IStatus* userStat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown_database(dbb, true);
|
JRD_shutdown_database(dbb, SHUT_DBB_RELEASE_POOLS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const Exception&)
|
catch (const Exception&)
|
||||||
@ -7155,7 +7222,7 @@ namespace
|
|||||||
{
|
{
|
||||||
// purge attachment, rollback any open transactions
|
// purge attachment, rollback any open transactions
|
||||||
attachment->att_use_count++;
|
attachment->att_use_count++;
|
||||||
purge_attachment(tdbb, jAtt, true);
|
purge_attachment(tdbb, jAtt, PURGE_FORCE);
|
||||||
}
|
}
|
||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
@ -7241,6 +7308,20 @@ static THREAD_ENTRY_DECLARE shutdown_thread(THREAD_ENTRY_PARAM arg)
|
|||||||
// Shutdown existing attachments
|
// Shutdown existing attachments
|
||||||
success = success && shutdownAttachments(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
|
// Extra shutdown operations
|
||||||
Service::shutdownServices();
|
Service::shutdownServices();
|
||||||
}
|
}
|
||||||
|
@ -76,4 +76,10 @@ void JRD_compile(Jrd::thread_db* tdbb, Jrd::Attachment* attachment, Jrd::jrd_req
|
|||||||
bool JRD_verify_database_access(const Firebird::PathName&);
|
bool JRD_verify_database_access(const Firebird::PathName&);
|
||||||
void JRD_shutdown_attachments(Jrd::Database* dbb);
|
void JRD_shutdown_attachments(Jrd::Database* dbb);
|
||||||
void JRD_cancel_operation(Jrd::thread_db* tdbb, Jrd::Attachment* attachment, int option);
|
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 */
|
#endif /* JRD_JRD_PROTO_H */
|
||||||
|
@ -5009,3 +5009,33 @@ static bool verify_TRG_ignore_perm(thread_db* tdbb, const MetaName& trig_name)
|
|||||||
|
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
|
@ -129,5 +129,5 @@ void MET_get_domain(Jrd::thread_db*, MemoryPool& csbPool, const Firebird::MetaN
|
|||||||
Firebird::MetaName MET_get_relation_field(Jrd::thread_db*, MemoryPool& csbPool,
|
Firebird::MetaName MET_get_relation_field(Jrd::thread_db*, MemoryPool& csbPool,
|
||||||
const Firebird::MetaName&, const Firebird::MetaName&, dsc*, Jrd::FieldInfo*);
|
const Firebird::MetaName&, const Firebird::MetaName&, dsc*, Jrd::FieldInfo*);
|
||||||
void MET_update_partners(Jrd::thread_db*);
|
void MET_update_partners(Jrd::thread_db*);
|
||||||
|
int MET_get_linger(Jrd::thread_db*);
|
||||||
#endif // JRD_MET_PROTO_H
|
#endif // JRD_MET_PROTO_H
|
||||||
|
@ -248,6 +248,7 @@ NAME("RDB$PARAMETER_MECHANISM", nam_prm_mechanism)
|
|||||||
NAME("RDB$SOURCE_INFO", nam_src_info)
|
NAME("RDB$SOURCE_INFO", nam_src_info)
|
||||||
|
|
||||||
NAME("RDB$ENGINE_NAME", nam_engine_name)
|
NAME("RDB$ENGINE_NAME", nam_engine_name)
|
||||||
|
NAME("RDB$LINGER", nam_linger)
|
||||||
|
|
||||||
NAME("RDB$PACKAGES", nam_packages)
|
NAME("RDB$PACKAGES", nam_packages)
|
||||||
NAME("RDB$PACKAGE_NAME", nam_pkg_name)
|
NAME("RDB$PACKAGE_NAME", nam_pkg_name)
|
||||||
|
@ -38,6 +38,7 @@ RELATION(nam_database, rel_database, ODS_8_0, rel_persistent)
|
|||||||
FIELD(f_dat_id, nam_r_id, fld_r_id, 0, ODS_8_0)
|
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_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_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
|
END_RELATION
|
||||||
|
|
||||||
// Relation 2 (RDB$FIELDS)
|
// Relation 2 (RDB$FIELDS)
|
||||||
|
@ -502,7 +502,8 @@ enum dfw_t {
|
|||||||
dfw_arg_trg_type, // trigger type
|
dfw_arg_trg_type, // trigger type
|
||||||
dfw_arg_new_name, // new name
|
dfw_arg_new_name, // new name
|
||||||
dfw_arg_field_not_null, // set domain to not nullable
|
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
|
// Verb actions
|
||||||
|
@ -2362,6 +2362,12 @@ void VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
|
|||||||
{
|
{
|
||||||
case rel_database:
|
case rel_database:
|
||||||
check_class(tdbb, transaction, org_rpb, new_rpb, f_dat_class);
|
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;
|
break;
|
||||||
|
|
||||||
case rel_relations:
|
case rel_relations:
|
||||||
|
@ -3,7 +3,7 @@ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUM
|
|||||||
--
|
--
|
||||||
('2013-11-05 13:18:17', 'JRD', 0, 752)
|
('2013-11-05 13:18:17', 'JRD', 0, 752)
|
||||||
('2012-01-23 20:10:30', 'QLI', 1, 532)
|
('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)
|
('1996-11-07 13:39:40', 'GPRE', 4, 1)
|
||||||
('2012-08-27 21:26:00', 'DSQL', 7, 33)
|
('2012-08-27 21:26:00', 'DSQL', 7, 33)
|
||||||
('2013-09-05 12:40:00', 'DYN', 8, 286)
|
('2013-09-05 12:40:00', 'DYN', 8, 286)
|
||||||
|
@ -1591,6 +1591,7 @@ COMMIT WORK;
|
|||||||
(NULL, 'ALICE_gfix', 'alice.cpp', NULL, 3, 118, NULL, 'empty password file @1', NULL, NULL);
|
(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_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);
|
(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
|
||||||
('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_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);
|
('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);
|
||||||
|
@ -400,7 +400,7 @@ int CLIB_ROUTINE main( int argc, char** argv)
|
|||||||
|
|
||||||
const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig());
|
const Firebird::RefPtr<Config> defConf(Config::getDefaultConfig());
|
||||||
const char* path = defConf->getSecurityDatabase();
|
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);
|
isc_attach_database(status, strlen(path), path, &db_handle, sizeof dpb, dpb);
|
||||||
if (status[0] == 1 && status[1] > 0)
|
if (status[0] == 1 && status[1] > 0)
|
||||||
|
@ -390,6 +390,7 @@ const SvcSwitches propertiesOptions[] =
|
|||||||
{"prp_transactions_shutdown", putNumericArgument, 0, isc_spb_prp_transactions_shutdown, 0},
|
{"prp_transactions_shutdown", putNumericArgument, 0, isc_spb_prp_transactions_shutdown, 0},
|
||||||
{"prp_shutdown_mode", putShutdownMode, 0, isc_spb_prp_shutdown_mode, 0},
|
{"prp_shutdown_mode", putShutdownMode, 0, isc_spb_prp_shutdown_mode, 0},
|
||||||
{"prp_online_mode", putShutdownMode, 0, isc_spb_prp_online_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}
|
{0, 0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -406,7 +406,8 @@ namespace
|
|||||||
RefPtr<ConfigFile> pconfig, const PathName& pconfName,
|
RefPtr<ConfigFile> pconfig, const PathName& pconfName,
|
||||||
const PathName& pplugName)
|
const PathName& pplugName)
|
||||||
: module(pmodule), regPlugin(preg), defaultConfig(pconfig),
|
: module(pmodule), regPlugin(preg), defaultConfig(pconfig),
|
||||||
confName(getPool(), pconfName), plugName(getPool(), pplugName)
|
confName(getPool(), pconfName), plugName(getPool(), pplugName),
|
||||||
|
delay(DEFAULT_DELAY)
|
||||||
{
|
{
|
||||||
if (defaultConfig.hasData())
|
if (defaultConfig.hasData())
|
||||||
{
|
{
|
||||||
@ -461,6 +462,19 @@ namespace
|
|||||||
return plugName.c_str();
|
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
|
// ITimer implementation
|
||||||
void FB_CARG handler()
|
void FB_CARG handler()
|
||||||
{ }
|
{ }
|
||||||
@ -473,6 +487,9 @@ namespace
|
|||||||
RefPtr<ConfigFile> defaultConfig;
|
RefPtr<ConfigFile> defaultConfig;
|
||||||
PathName confName;
|
PathName confName;
|
||||||
PathName plugName;
|
PathName plugName;
|
||||||
|
|
||||||
|
static const FB_UINT64 DEFAULT_DELAY = 1000000; // 1 sec
|
||||||
|
FB_UINT64 delay;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Provides per-database configuration from databases.conf.
|
// Provides per-database configuration from databases.conf.
|
||||||
@ -506,6 +523,11 @@ namespace
|
|||||||
return firebirdConf;
|
return firebirdConf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FB_CARG setReleaseDelay(ISC_UINT64 microSeconds)
|
||||||
|
{
|
||||||
|
configuredPlugin->setReleaseDelay(microSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
int FB_CARG release()
|
int FB_CARG release()
|
||||||
{
|
{
|
||||||
if (--refCounter == 0)
|
if (--refCounter == 0)
|
||||||
@ -521,9 +543,10 @@ namespace
|
|||||||
~FactoryParameter()
|
~FactoryParameter()
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_PLUGINS
|
#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
|
#endif
|
||||||
TimerInterfacePtr()->start(configuredPlugin, 1000000); // 1 sec
|
TimerInterfacePtr()->start(configuredPlugin, configuredPlugin->getReleaseDelay());
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<ConfiguredPlugin> configuredPlugin;
|
RefPtr<ConfiguredPlugin> configuredPlugin;
|
||||||
@ -532,13 +555,17 @@ namespace
|
|||||||
|
|
||||||
IPluginBase* ConfiguredPlugin::factory(IFirebirdConf* firebirdConf)
|
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);
|
IPluginBase* plugin = module->getPlugin(regPlugin).factory->createPlugin(par);
|
||||||
if (plugin)
|
if (plugin)
|
||||||
{
|
{
|
||||||
par->addRef();
|
|
||||||
plugin->setOwner(par);
|
plugin->setOwner(par);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
par->release();
|
||||||
|
}
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,6 +243,7 @@ static const TOK tokens[] =
|
|||||||
{LEVEL, "LEVEL", 1, false},
|
{LEVEL, "LEVEL", 1, false},
|
||||||
{LIKE, "LIKE", 1, false},
|
{LIKE, "LIKE", 1, false},
|
||||||
{LIMBO, "LIMBO", 2, true},
|
{LIMBO, "LIMBO", 2, true},
|
||||||
|
{LINGER, "LINGER", 2, true},
|
||||||
{LIST, "LIST", 2, false},
|
{LIST, "LIST", 2, false},
|
||||||
{LN, "LN", 2, false},
|
{LN, "LN", 2, false},
|
||||||
{LOCK, "LOCK", 2, true},
|
{LOCK, "LOCK", 2, true},
|
||||||
|
Loading…
Reference in New Issue
Block a user