mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-22 18:43:02 +01:00
Merge branch 'master' into work/parallel_v5
This commit is contained in:
commit
5edefaba91
@ -61,8 +61,6 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DATABASE DB = STATIC FILENAME "yachts.lnk";
|
|
||||||
|
|
||||||
#define DB tdgbl->db_handle
|
#define DB tdgbl->db_handle
|
||||||
#define fbTrans tdgbl->tr_handle
|
#define fbTrans tdgbl->tr_handle
|
||||||
#define gds_trans tdgbl->tr_handle
|
#define gds_trans tdgbl->tr_handle
|
||||||
@ -70,6 +68,12 @@ DATABASE DB = STATIC FILENAME "yachts.lnk";
|
|||||||
#define isc_status (&tdgbl->status_vector)
|
#define isc_status (&tdgbl->status_vector)
|
||||||
#define gds_status (&tdgbl->status_vector)
|
#define gds_status (&tdgbl->status_vector)
|
||||||
|
|
||||||
|
// unused
|
||||||
|
#define fbProvider
|
||||||
|
#define fbStatus2
|
||||||
|
|
||||||
|
DATABASE DB = STATIC FILENAME "yachts.lnk";
|
||||||
|
|
||||||
|
|
||||||
void detectRuntimeODS()
|
void detectRuntimeODS()
|
||||||
{
|
{
|
||||||
|
@ -72,8 +72,6 @@ using namespace Burp;
|
|||||||
// GPRE. This is to avoid multiple threading problems with module
|
// GPRE. This is to avoid multiple threading problems with module
|
||||||
// level statics.
|
// level statics.
|
||||||
|
|
||||||
DATABASE DB = STATIC FILENAME "yachts.lnk" RUNTIME * dbb_file;
|
|
||||||
|
|
||||||
#define DB tdgbl->db_handle
|
#define DB tdgbl->db_handle
|
||||||
#define fbTrans tdgbl->tr_handle
|
#define fbTrans tdgbl->tr_handle
|
||||||
#define gds_trans tdgbl->tr_handle
|
#define gds_trans tdgbl->tr_handle
|
||||||
@ -81,6 +79,12 @@ DATABASE DB = STATIC FILENAME "yachts.lnk" RUNTIME * dbb_file;
|
|||||||
#define isc_status (&tdgbl->status_vector)
|
#define isc_status (&tdgbl->status_vector)
|
||||||
#define gds_status (&tdgbl->status_vector)
|
#define gds_status (&tdgbl->status_vector)
|
||||||
|
|
||||||
|
// unused
|
||||||
|
#define fbProvider
|
||||||
|
#define fbStatus2
|
||||||
|
|
||||||
|
DATABASE DB = STATIC FILENAME "yachts.lnk" RUNTIME * dbb_file;
|
||||||
|
|
||||||
namespace // unnamed, private
|
namespace // unnamed, private
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -73,8 +73,6 @@ using namespace Burp;
|
|||||||
// GPRE. This is to avoid multiple threading problems with module
|
// GPRE. This is to avoid multiple threading problems with module
|
||||||
// level statics.
|
// level statics.
|
||||||
|
|
||||||
DATABASE DB = STATIC FILENAME "yachts.lnk";
|
|
||||||
|
|
||||||
#define DB tdgbl->db_handle
|
#define DB tdgbl->db_handle
|
||||||
#define fbTrans tdgbl->tr_handle
|
#define fbTrans tdgbl->tr_handle
|
||||||
#define gds_trans tdgbl->tr_handle
|
#define gds_trans tdgbl->tr_handle
|
||||||
@ -82,6 +80,12 @@ DATABASE DB = STATIC FILENAME "yachts.lnk";
|
|||||||
#define isc_status (&tdgbl->status_vector)
|
#define isc_status (&tdgbl->status_vector)
|
||||||
#define gds_status (&tdgbl->status_vector)
|
#define gds_status (&tdgbl->status_vector)
|
||||||
|
|
||||||
|
// unused
|
||||||
|
#define fbProvider
|
||||||
|
#define fbStatus2
|
||||||
|
|
||||||
|
DATABASE DB = STATIC FILENAME "yachts.lnk";
|
||||||
|
|
||||||
|
|
||||||
namespace // unnamed, private
|
namespace // unnamed, private
|
||||||
{
|
{
|
||||||
@ -1682,16 +1686,22 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
|||||||
burp_fld* field = NULL;
|
burp_fld* field = NULL;
|
||||||
FbLocalStatus status_vector;
|
FbLocalStatus status_vector;
|
||||||
USHORT count, field_number, field_length = 0;
|
USHORT count, field_number, field_length = 0;
|
||||||
UCHAR* buffer = NULL;
|
UCHAR** buffer = NULL;
|
||||||
UCHAR* p = NULL;
|
UCHAR* p = NULL;
|
||||||
UCHAR blr_buffer[200]; // enough for a sdl with 16 dimensions
|
UCHAR blr_buffer[200]; // enough for a sdl with 16 dimensions
|
||||||
lstring xdr_slice;
|
lstring xdr_slice;
|
||||||
|
|
||||||
// don't free something you don't allocate
|
|
||||||
lstring xdr_buffer;
|
lstring xdr_buffer;
|
||||||
xdr_buffer.lstr_allocated = 0;
|
xdr_buffer.lstr_allocated = 0;
|
||||||
xdr_buffer.lstr_address = NULL;
|
xdr_buffer.lstr_address = NULL;
|
||||||
|
|
||||||
|
Firebird::Cleanup datClean( [&] {
|
||||||
|
if (buffer && *buffer)
|
||||||
|
BURP_free(*buffer);
|
||||||
|
if (tdgbl->gbl_sw_transportable && xdr_buffer.lstr_allocated)
|
||||||
|
BURP_free(xdr_buffer.lstr_address);
|
||||||
|
} );
|
||||||
|
|
||||||
// Pick up attributes
|
// Pick up attributes
|
||||||
SLONG fld_ranges[2 * MAX_DIMENSION];
|
SLONG fld_ranges[2 * MAX_DIMENSION];
|
||||||
SLONG slice_length = 0;
|
SLONG slice_length = 0;
|
||||||
@ -1990,7 +2000,6 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
|||||||
|
|
||||||
if (data_at == 0)
|
if (data_at == 0)
|
||||||
{
|
{
|
||||||
buffer = BURP_alloc (return_length);
|
|
||||||
SLONG lcount = 0;
|
SLONG lcount = 0;
|
||||||
if (tdgbl->gbl_sw_transportable)
|
if (tdgbl->gbl_sw_transportable)
|
||||||
{
|
{
|
||||||
@ -2005,19 +2014,23 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
|||||||
lcount |= get(tdgbl) << 8;
|
lcount |= get(tdgbl) << 8;
|
||||||
lcount |= get(tdgbl) << 16;
|
lcount |= get(tdgbl) << 16;
|
||||||
lcount |= get(tdgbl) << 24;
|
lcount |= get(tdgbl) << 24;
|
||||||
|
|
||||||
xdr_buffer.lstr_length = xdr_buffer.lstr_allocated = lcount;
|
xdr_buffer.lstr_length = xdr_buffer.lstr_allocated = lcount;
|
||||||
xdr_buffer.lstr_address = BURP_alloc(lcount);
|
p = xdr_buffer.lstr_address = BURP_alloc(lcount);
|
||||||
|
|
||||||
xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length;
|
xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length;
|
||||||
xdr_slice.lstr_address = buffer;
|
buffer = &xdr_slice.lstr_address;
|
||||||
p = xdr_buffer.lstr_address;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p = buffer;
|
buffer = &p;
|
||||||
lcount = return_length;
|
lcount = return_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fb_assert(buffer);
|
||||||
|
*buffer = BURP_alloc(return_length);
|
||||||
|
|
||||||
if (lcount)
|
if (lcount)
|
||||||
get_block(tdgbl, p, lcount);
|
get_block(tdgbl, p, lcount);
|
||||||
|
|
||||||
@ -2027,7 +2040,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
|||||||
|
|
||||||
DB->putSlice(&status_vector, gds_trans, blob_id, blr_length, blr_buffer,
|
DB->putSlice(&status_vector, gds_trans, blob_id, blr_length, blr_buffer,
|
||||||
0, NULL, // parameters for subset of an array handling
|
0, NULL, // parameters for subset of an array handling
|
||||||
elements_written * field->fld_length, buffer + data_at);
|
elements_written * field->fld_length, (*buffer) + data_at);
|
||||||
if (status_vector->hasData())
|
if (status_vector->hasData())
|
||||||
{
|
{
|
||||||
BURP_print (false, 81, field->fld_name);
|
BURP_print (false, 81, field->fld_name);
|
||||||
@ -2116,7 +2129,6 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
|||||||
|
|
||||||
const USHORT blr_length = blr - blr_buffer;
|
const USHORT blr_length = blr - blr_buffer;
|
||||||
|
|
||||||
buffer = BURP_alloc (return_length);
|
|
||||||
SLONG lcount = 0;
|
SLONG lcount = 0;
|
||||||
if (tdgbl->gbl_sw_transportable)
|
if (tdgbl->gbl_sw_transportable)
|
||||||
{
|
{
|
||||||
@ -2132,18 +2144,21 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
|||||||
xdr_buffer.lstr_allocated |= get(tdgbl) << 16;
|
xdr_buffer.lstr_allocated |= get(tdgbl) << 16;
|
||||||
xdr_buffer.lstr_allocated |= get(tdgbl) << 24;
|
xdr_buffer.lstr_allocated |= get(tdgbl) << 24;
|
||||||
lcount = xdr_buffer.lstr_length = xdr_buffer.lstr_allocated;
|
lcount = xdr_buffer.lstr_length = xdr_buffer.lstr_allocated;
|
||||||
xdr_buffer.lstr_address = BURP_alloc (xdr_buffer.lstr_allocated);
|
p = xdr_buffer.lstr_address = BURP_alloc(xdr_buffer.lstr_allocated);
|
||||||
|
|
||||||
xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length;
|
xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length;
|
||||||
xdr_slice.lstr_address = buffer;
|
buffer = &xdr_slice.lstr_address;
|
||||||
p = xdr_buffer.lstr_address;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p = buffer;
|
buffer = &p;
|
||||||
lcount = return_length;
|
lcount = return_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fb_assert(buffer);
|
||||||
|
*buffer = BURP_alloc (return_length);
|
||||||
|
|
||||||
if (lcount)
|
if (lcount)
|
||||||
get_block(tdgbl, p, lcount);
|
get_block(tdgbl, p, lcount);
|
||||||
|
|
||||||
@ -2153,7 +2168,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
|||||||
|
|
||||||
DB->putSlice(&status_vector, gds_trans, blob_id, blr_length, blr_buffer,
|
DB->putSlice(&status_vector, gds_trans, blob_id, blr_length, blr_buffer,
|
||||||
0, NULL, // parameters for subset of an array handling
|
0, NULL, // parameters for subset of an array handling
|
||||||
return_length, buffer);
|
return_length, *buffer);
|
||||||
if (status_vector->hasData())
|
if (status_vector->hasData())
|
||||||
{
|
{
|
||||||
BURP_print (false, 81, field->fld_name);
|
BURP_print (false, 81, field->fld_name);
|
||||||
@ -2165,10 +2180,6 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BURP_free (buffer);
|
|
||||||
if (tdgbl->gbl_sw_transportable && xdr_buffer.lstr_allocated)
|
|
||||||
BURP_free (xdr_buffer.lstr_address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3199,9 +3210,13 @@ void get_data(BurpGlobals* tdgbl, burp_rel* relation, WriteRelationReq* req)
|
|||||||
lstring data;
|
lstring data;
|
||||||
data.lstr_allocated = 0;
|
data.lstr_allocated = 0;
|
||||||
data.lstr_address = NULL;
|
data.lstr_address = NULL;
|
||||||
Array<UCHAR> dataBuffer;
|
|
||||||
RCRD_LENGTH old_length = 0;
|
|
||||||
|
|
||||||
|
Firebird::Cleanup datClean( [&] {
|
||||||
|
if (data.lstr_address)
|
||||||
|
BURP_free(data.lstr_address);
|
||||||
|
} );
|
||||||
|
|
||||||
|
ULONG old_length = 0;
|
||||||
IBatch* batch = req->getBatch();
|
IBatch* batch = req->getBatch();
|
||||||
UCHAR* sql = batch ? sql = req->getBatchMsgData() : nullptr;
|
UCHAR* sql = batch ? sql = req->getBatchMsgData() : nullptr;
|
||||||
tdgbl->batchInlineBlobLimit = batch ? req->getBatchInlineBlobLimit() : 0;
|
tdgbl->batchInlineBlobLimit = batch ? req->getBatchInlineBlobLimit() : 0;
|
||||||
@ -3247,7 +3262,9 @@ void get_data(BurpGlobals* tdgbl, burp_rel* relation, WriteRelationReq* req)
|
|||||||
if (len > data.lstr_allocated)
|
if (len > data.lstr_allocated)
|
||||||
{
|
{
|
||||||
data.lstr_allocated = len;
|
data.lstr_allocated = len;
|
||||||
data.lstr_address = dataBuffer.getBuffer(data.lstr_allocated);
|
if (data.lstr_address)
|
||||||
|
BURP_free (data.lstr_address);
|
||||||
|
data.lstr_address = BURP_alloc(data.lstr_allocated);
|
||||||
}
|
}
|
||||||
p = data.lstr_address;
|
p = data.lstr_address;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#define CLASSES_AUTO_PTR_H
|
#define CLASSES_AUTO_PTR_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace Firebird {
|
namespace Firebird {
|
||||||
|
|
||||||
@ -317,6 +318,22 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Cleanup
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Cleanup(std::function<void()> clFunc)
|
||||||
|
: clean(clFunc)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~Cleanup()
|
||||||
|
{
|
||||||
|
clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::function<void()> clean;
|
||||||
|
};
|
||||||
|
|
||||||
} //namespace Firebird
|
} //namespace Firebird
|
||||||
|
|
||||||
#endif // CLASSES_AUTO_PTR_H
|
#endif // CLASSES_AUTO_PTR_H
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "firebird.h"
|
#include "firebird.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "alloc.h"
|
#include "alloc.h"
|
||||||
|
#include "auto.h"
|
||||||
#include "../common/SimpleStatusVector.h"
|
#include "../common/SimpleStatusVector.h"
|
||||||
#include "../common/dllinst.h"
|
#include "../common/dllinst.h"
|
||||||
#include "../common/os/os_utils.h"
|
#include "../common/os/os_utils.h"
|
||||||
@ -142,17 +143,10 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef DEBUG_INIT
|
#ifndef DEBUG_INIT
|
||||||
// This class with it's single instance ensures global cleanup
|
|
||||||
class Cleanup
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
~Cleanup()
|
|
||||||
{
|
|
||||||
allClean();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Cleanup global;
|
// This instance ensures dtors run when program exits
|
||||||
|
Firebird::Cleanup global(allClean);
|
||||||
|
|
||||||
#endif //DEBUG_INIT
|
#endif //DEBUG_INIT
|
||||||
|
|
||||||
void init()
|
void init()
|
||||||
|
@ -1413,6 +1413,16 @@ static int gen_cursor_open( const act* action, const gpre_req* request, int colu
|
|||||||
// Generate insertion text for the database statement.
|
// Generate insertion text for the database statement.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
static void ifndef(const char* nm, const char* nm2 = "")
|
||||||
|
{
|
||||||
|
fprintf(gpreGlob.out_file, "\n#ifndef %s%s", nm, nm2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void endif()
|
||||||
|
{
|
||||||
|
fprintf(gpreGlob.out_file, "\n#endif");
|
||||||
|
}
|
||||||
|
|
||||||
static void gen_database(int column)
|
static void gen_database(int column)
|
||||||
{
|
{
|
||||||
if (global_first_flag)
|
if (global_first_flag)
|
||||||
@ -1427,8 +1437,10 @@ static void gen_database(int column)
|
|||||||
fprintf(gpreGlob.out_file, "#define CAST_CONST_MSG(A) (reinterpret_cast<const unsigned char*>(A))\n");
|
fprintf(gpreGlob.out_file, "#define CAST_CONST_MSG(A) (reinterpret_cast<const unsigned char*>(A))\n");
|
||||||
fprintf(gpreGlob.out_file, "#define CAST_MSG(A) (reinterpret_cast<unsigned char*>(A))\n");
|
fprintf(gpreGlob.out_file, "#define CAST_MSG(A) (reinterpret_cast<unsigned char*>(A))\n");
|
||||||
|
|
||||||
|
ifndef("fbBlobNull");
|
||||||
printa(column, "static %sISC_QUAD", CONST_STR);
|
printa(column, "static %sISC_QUAD", CONST_STR);
|
||||||
printa(column + INDENT, "fbBlobNull = {0, 0};\t/* initializer for blobs */");
|
printa(column + INDENT, "fbBlobNull = {0, 0};\t/* initializer for blobs */");
|
||||||
|
endif();
|
||||||
|
|
||||||
const TEXT* scope = "";
|
const TEXT* scope = "";
|
||||||
|
|
||||||
@ -1440,6 +1452,8 @@ static void gen_database(int column)
|
|||||||
{
|
{
|
||||||
all_static = all_static && (db->dbb_scope == DBB_STATIC);
|
all_static = all_static && (db->dbb_scope == DBB_STATIC);
|
||||||
all_extern = all_extern && (db->dbb_scope == DBB_EXTERN);
|
all_extern = all_extern && (db->dbb_scope == DBB_EXTERN);
|
||||||
|
|
||||||
|
ifndef(db->dbb_name->sym_string);
|
||||||
if (db->dbb_scope == DBB_STATIC)
|
if (db->dbb_scope == DBB_STATIC)
|
||||||
scope = "static ";
|
scope = "static ";
|
||||||
else if (db->dbb_scope == DBB_EXTERN)
|
else if (db->dbb_scope == DBB_EXTERN)
|
||||||
@ -1449,6 +1463,7 @@ static void gen_database(int column)
|
|||||||
printa(column + INDENT, "%s = 0;\t\t/* database handle */\n", db->dbb_name->sym_string);
|
printa(column + INDENT, "%s = 0;\t\t/* database handle */\n", db->dbb_name->sym_string);
|
||||||
else
|
else
|
||||||
printa(column + INDENT, "%s;\t\t/* database handle */\n", db->dbb_name->sym_string);
|
printa(column + INDENT, "%s;\t\t/* database handle */\n", db->dbb_name->sym_string);
|
||||||
|
endif();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (all_static)
|
if (all_static)
|
||||||
@ -1456,6 +1471,7 @@ static void gen_database(int column)
|
|||||||
else if (all_extern)
|
else if (all_extern)
|
||||||
scope = "extern ";
|
scope = "extern ";
|
||||||
|
|
||||||
|
ifndef(gpreGlob.transaction_name);
|
||||||
printa(column, "%sFirebird::ITransaction*", scope);
|
printa(column, "%sFirebird::ITransaction*", scope);
|
||||||
if (!all_extern)
|
if (!all_extern)
|
||||||
printa(column + INDENT, "%s = 0;\t\t/* default transaction handle */",
|
printa(column + INDENT, "%s = 0;\t\t/* default transaction handle */",
|
||||||
@ -1463,33 +1479,43 @@ static void gen_database(int column)
|
|||||||
else
|
else
|
||||||
printa(column + INDENT, "%s;\t\t/* default transaction handle */",
|
printa(column + INDENT, "%s;\t\t/* default transaction handle */",
|
||||||
gpreGlob.transaction_name);
|
gpreGlob.transaction_name);
|
||||||
|
endif();
|
||||||
|
|
||||||
|
ifndef("fbMaster");
|
||||||
printa(column, "%sFirebird::IMaster* fbMaster%s;\t\t/* master interface */",
|
printa(column, "%sFirebird::IMaster* fbMaster%s;\t\t/* master interface */",
|
||||||
scope, all_extern ? "" : " = Firebird::fb_get_master_interface()");
|
scope, all_extern ? "" : " = Firebird::fb_get_master_interface()");
|
||||||
|
endif();
|
||||||
|
|
||||||
|
ifndef("fbProvider");
|
||||||
printa(column, "%sFirebird::IProvider* fbProvider%s;\t\t/* provider interface */",
|
printa(column, "%sFirebird::IProvider* fbProvider%s;\t\t/* provider interface */",
|
||||||
scope, all_extern ? "" : " = fbMaster->getDispatcher()");
|
scope, all_extern ? "" : " = fbMaster->getDispatcher()");
|
||||||
|
endif();
|
||||||
|
|
||||||
|
ifndef(global_status_name);
|
||||||
printa(column, "%sFirebird::CheckStatusWrapper %sObj%s;\t/* status vector */",
|
printa(column, "%sFirebird::CheckStatusWrapper %sObj%s;\t/* status vector */",
|
||||||
scope, global_status_name, all_extern ? "" : "(fbMaster->getStatus())");
|
scope, global_status_name, all_extern ? "" : "(fbMaster->getStatus())");
|
||||||
printa(column, "%sFirebird::CheckStatusWrapper %s2Obj%s;\t/* status vector */",
|
|
||||||
scope, global_status_name, all_extern ? "" : "(fbMaster->getStatus())");
|
|
||||||
|
|
||||||
if (all_extern)
|
if (all_extern)
|
||||||
{
|
|
||||||
printa(column, "%sFirebird::CheckStatusWrapper* %s;\t/* status vector */",
|
printa(column, "%sFirebird::CheckStatusWrapper* %s;\t/* status vector */",
|
||||||
scope, global_status_name);
|
scope, global_status_name);
|
||||||
printa(column, "%sFirebird::CheckStatusWrapper* %s2;\t/* status vector */",
|
|
||||||
scope, global_status_name);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
printa(column, "%sFirebird::CheckStatusWrapper* %s = &%sObj;\t/* status vector */",
|
printa(column, "%sFirebird::CheckStatusWrapper* %s = &%sObj;\t/* status vector */",
|
||||||
scope, global_status_name, global_status_name);
|
scope, global_status_name, global_status_name);
|
||||||
|
endif();
|
||||||
|
|
||||||
|
ifndef(global_status_name, "2");
|
||||||
|
printa(column, "%sFirebird::CheckStatusWrapper %s2Obj%s;\t/* status vector */",
|
||||||
|
scope, global_status_name, all_extern ? "" : "(fbMaster->getStatus())");
|
||||||
|
if (all_extern)
|
||||||
|
printa(column, "%sFirebird::CheckStatusWrapper* %s2;\t/* status vector */",
|
||||||
|
scope, global_status_name);
|
||||||
|
else
|
||||||
printa(column, "%sFirebird::CheckStatusWrapper* %s2 = &%s2Obj;\t/* status vector */",
|
printa(column, "%sFirebird::CheckStatusWrapper* %s2 = &%s2Obj;\t/* status vector */",
|
||||||
scope, global_status_name, global_status_name);
|
scope, global_status_name, global_status_name);
|
||||||
}
|
endif();
|
||||||
|
|
||||||
|
ifndef("fbIStatus");
|
||||||
printa(column, "%sint fbIStatus;\t/* last completion code */", scope);
|
printa(column, "%sint fbIStatus;\t/* last completion code */", scope);
|
||||||
|
endif();
|
||||||
|
|
||||||
for (db = gpreGlob.isc_databases; db; db = db->dbb_next)
|
for (db = gpreGlob.isc_databases; db; db = db->dbb_next)
|
||||||
for (const tpb* tpb_iterator = db->dbb_tpbs; tpb_iterator;
|
for (const tpb* tpb_iterator = db->dbb_tpbs; tpb_iterator;
|
||||||
|
@ -493,6 +493,15 @@ namespace Jrd
|
|||||||
|
|
||||||
// Database::GlobalObjectHolder class implementation
|
// Database::GlobalObjectHolder class implementation
|
||||||
|
|
||||||
|
int Database::GlobalObjectHolder::release() const
|
||||||
|
{
|
||||||
|
// Release should be executed under g_mutex protection
|
||||||
|
// in order to modify reference counter & hash table atomically
|
||||||
|
MutexLockGuard guard(g_mutex, FB_FUNCTION);
|
||||||
|
|
||||||
|
return RefCounted::release();
|
||||||
|
}
|
||||||
|
|
||||||
Database::GlobalObjectHolder* Database::GlobalObjectHolder::init(const string& id,
|
Database::GlobalObjectHolder* Database::GlobalObjectHolder::init(const string& id,
|
||||||
const PathName& filename,
|
const PathName& filename,
|
||||||
RefPtr<const Config> config)
|
RefPtr<const Config> config)
|
||||||
@ -512,17 +521,18 @@ namespace Jrd
|
|||||||
|
|
||||||
Database::GlobalObjectHolder::~GlobalObjectHolder()
|
Database::GlobalObjectHolder::~GlobalObjectHolder()
|
||||||
{
|
{
|
||||||
// here we cleanup what should not be globally protected
|
// dtor is executed under g_mutex protection
|
||||||
if (m_replMgr)
|
|
||||||
m_replMgr->shutdown();
|
|
||||||
|
|
||||||
MutexLockGuard guard(g_mutex, FB_FUNCTION);
|
|
||||||
|
|
||||||
Database::GlobalObjectHolder::DbId* entry = g_hashTable->lookup(m_id);
|
Database::GlobalObjectHolder::DbId* entry = g_hashTable->lookup(m_id);
|
||||||
if (!g_hashTable->remove(m_id))
|
if (!g_hashTable->remove(m_id))
|
||||||
fb_assert(false);
|
fb_assert(false);
|
||||||
|
|
||||||
// these objects should be deleted under g_mutex protection
|
{ // scope
|
||||||
|
// here we cleanup what should not be globally protected
|
||||||
|
MutexUnlockGuard guard(g_mutex, FB_FUNCTION);
|
||||||
|
if (m_replMgr)
|
||||||
|
m_replMgr->shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
m_lockMgr = nullptr;
|
m_lockMgr = nullptr;
|
||||||
m_eventMgr = nullptr;
|
m_eventMgr = nullptr;
|
||||||
m_replMgr = nullptr;
|
m_replMgr = nullptr;
|
||||||
|
@ -306,6 +306,8 @@ class Database : public pool_alloc<type_dbb>
|
|||||||
const Firebird::PathName& filename,
|
const Firebird::PathName& filename,
|
||||||
Firebird::RefPtr<const Firebird::Config> config);
|
Firebird::RefPtr<const Firebird::Config> config);
|
||||||
|
|
||||||
|
int release() const override;
|
||||||
|
|
||||||
~GlobalObjectHolder();
|
~GlobalObjectHolder();
|
||||||
|
|
||||||
LockManager* getLockManager();
|
LockManager* getLockManager();
|
||||||
|
138
src/jrd/ThreadCollect.h
Normal file
138
src/jrd/ThreadCollect.h
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* PROGRAM: JRD threading support
|
||||||
|
* MODULE: ThreadCollect.h
|
||||||
|
* DESCRIPTION: Threads' group completion handling
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Initial
|
||||||
|
* Developer's Public License Version 1.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
* http://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed AS IS,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing rights
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code was created by Alexander Peshkov
|
||||||
|
* for the Firebird Open Source RDBMS project.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018, 2022 Alexander Peshkov <peshkoff@mail.ru>
|
||||||
|
* and all contributors signed below.
|
||||||
|
*
|
||||||
|
* All Rights Reserved.
|
||||||
|
* Contributor(s): ______________________________________.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JRD_THREADCOLLECT_H
|
||||||
|
#define JRD_THREADCOLLECT_H
|
||||||
|
|
||||||
|
#include "../common/ThreadStart.h"
|
||||||
|
#include "../common/classes/alloc.h"
|
||||||
|
#include "../common/classes/array.h"
|
||||||
|
#include "../common/classes/locks.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Jrd {
|
||||||
|
|
||||||
|
class ThreadCollect
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ThreadCollect(MemoryPool& p)
|
||||||
|
: threads(p)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void join()
|
||||||
|
{
|
||||||
|
if (!threads.hasData())
|
||||||
|
return;
|
||||||
|
|
||||||
|
waitFor(threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ending(Thread::Handle& h)
|
||||||
|
{
|
||||||
|
// put thread into completion wait queue when it finished running
|
||||||
|
Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION);
|
||||||
|
|
||||||
|
for (unsigned n = 0; n < threads.getCount(); ++n)
|
||||||
|
{
|
||||||
|
if (threads[n].hndl == h)
|
||||||
|
{
|
||||||
|
threads[n].ending = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Thrd t = {h, true};
|
||||||
|
threads.add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void running(Thread::Handle& h)
|
||||||
|
{
|
||||||
|
// put thread into completion wait queue when it starts running
|
||||||
|
Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION);
|
||||||
|
|
||||||
|
Thrd t = {h, false};
|
||||||
|
threads.add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void houseKeeping()
|
||||||
|
{
|
||||||
|
if (!threads.hasData())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// join finished threads
|
||||||
|
AllThreads t;
|
||||||
|
{ // mutex scope
|
||||||
|
Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION);
|
||||||
|
|
||||||
|
for (unsigned n = 0; n < threads.getCount(); )
|
||||||
|
{
|
||||||
|
if (threads[n].ending)
|
||||||
|
{
|
||||||
|
t.add(threads[n]);
|
||||||
|
threads.remove(n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waitFor(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Thrd
|
||||||
|
{
|
||||||
|
Thread::Handle hndl;
|
||||||
|
bool ending;
|
||||||
|
};
|
||||||
|
typedef Firebird::HalfStaticArray<Thrd, 4> AllThreads;
|
||||||
|
|
||||||
|
void waitFor(AllThreads& thr)
|
||||||
|
{
|
||||||
|
Firebird::MutexLockGuard g(threadsMutex, FB_FUNCTION);
|
||||||
|
while (thr.hasData())
|
||||||
|
{
|
||||||
|
FB_SIZE_T n = thr.getCount() - 1;
|
||||||
|
Thrd& t = thr[n];
|
||||||
|
{
|
||||||
|
Firebird::MutexUnlockGuard u(threadsMutex, FB_FUNCTION);
|
||||||
|
Thread::waitForCompletion(t.hndl);
|
||||||
|
fb_assert(t.ending);
|
||||||
|
}
|
||||||
|
thr.remove(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AllThreads threads;
|
||||||
|
Firebird::Mutex threadsMutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Jrd
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JRD_THREADCOLLECT_H
|
@ -3,16 +3,16 @@
|
|||||||
*** DO NOT EDIT ***
|
*** DO NOT EDIT ***
|
||||||
TO CHANGE ANY INFORMATION IN HERE PLEASE
|
TO CHANGE ANY INFORMATION IN HERE PLEASE
|
||||||
EDIT src/misc/writeBuildNum.sh
|
EDIT src/misc/writeBuildNum.sh
|
||||||
FORMAL BUILD NUMBER:501
|
FORMAL BUILD NUMBER:516
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PRODUCT_VER_STRING "5.0.0.501"
|
#define PRODUCT_VER_STRING "5.0.0.516"
|
||||||
#define FILE_VER_STRING "WI-T5.0.0.501"
|
#define FILE_VER_STRING "WI-T5.0.0.516"
|
||||||
#define LICENSE_VER_STRING "WI-T5.0.0.501"
|
#define LICENSE_VER_STRING "WI-T5.0.0.516"
|
||||||
#define FILE_VER_NUMBER 5, 0, 0, 501
|
#define FILE_VER_NUMBER 5, 0, 0, 516
|
||||||
#define FB_MAJOR_VER "5"
|
#define FB_MAJOR_VER "5"
|
||||||
#define FB_MINOR_VER "0"
|
#define FB_MINOR_VER "0"
|
||||||
#define FB_REV_NO "0"
|
#define FB_REV_NO "0"
|
||||||
#define FB_BUILD_NO "501"
|
#define FB_BUILD_NO "516"
|
||||||
#define FB_BUILD_TYPE "T"
|
#define FB_BUILD_TYPE "T"
|
||||||
#define FB_BUILD_SUFFIX "Firebird 5.0 Initial"
|
#define FB_BUILD_SUFFIX "Firebird 5.0 Initial"
|
||||||
|
221
src/jrd/jrd.cpp
221
src/jrd/jrd.cpp
@ -110,6 +110,7 @@
|
|||||||
#include "../yvalve/why_proto.h"
|
#include "../yvalve/why_proto.h"
|
||||||
#include "../jrd/flags.h"
|
#include "../jrd/flags.h"
|
||||||
#include "../jrd/Mapping.h"
|
#include "../jrd/Mapping.h"
|
||||||
|
#include "../jrd/ThreadCollect.h"
|
||||||
|
|
||||||
#include "../jrd/Database.h"
|
#include "../jrd/Database.h"
|
||||||
#include "../jrd/WorkerAttachment.h"
|
#include "../jrd/WorkerAttachment.h"
|
||||||
@ -127,6 +128,7 @@
|
|||||||
#include "../common/classes/ClumpletWriter.h"
|
#include "../common/classes/ClumpletWriter.h"
|
||||||
#include "../common/classes/RefMutex.h"
|
#include "../common/classes/RefMutex.h"
|
||||||
#include "../common/classes/ParsedList.h"
|
#include "../common/classes/ParsedList.h"
|
||||||
|
#include "../common/classes/semaphore.h"
|
||||||
#include "../common/utils_proto.h"
|
#include "../common/utils_proto.h"
|
||||||
#include "../jrd/DebugInterface.h"
|
#include "../jrd/DebugInterface.h"
|
||||||
#include "../jrd/CryptoManager.h"
|
#include "../jrd/CryptoManager.h"
|
||||||
@ -475,6 +477,16 @@ namespace
|
|||||||
{
|
{
|
||||||
using Jrd::Attachment;
|
using Jrd::Attachment;
|
||||||
|
|
||||||
|
// Required to sync attachment shutdown threads with provider shutdown
|
||||||
|
GlobalPtr<ThreadCollect> shutThreadCollect;
|
||||||
|
|
||||||
|
struct AttShutParams
|
||||||
|
{
|
||||||
|
Semaphore thdStartedSem;
|
||||||
|
Thread::Handle thrHandle;
|
||||||
|
AttachmentsRefHolder* attachments;
|
||||||
|
};
|
||||||
|
|
||||||
// Flag engineShutdown guarantees that no new attachment is created after setting it
|
// Flag engineShutdown guarantees that no new attachment is created after setting it
|
||||||
// and helps avoid more than 1 shutdown threads running simultaneously.
|
// and helps avoid more than 1 shutdown threads running simultaneously.
|
||||||
bool engineShutdown = false;
|
bool engineShutdown = false;
|
||||||
@ -1329,7 +1341,7 @@ static JAttachment* initAttachment(thread_db*, const PathName&, const PathName&,
|
|||||||
const DatabaseOptions&, RefMutexUnlock&, IPluginConfig*, JProvider*);
|
const DatabaseOptions&, RefMutexUnlock&, IPluginConfig*, JProvider*);
|
||||||
static JAttachment* create_attachment(const PathName&, Database*, JProvider* provider, const DatabaseOptions&, bool newDb);
|
static JAttachment* create_attachment(const PathName&, Database*, JProvider* provider, const DatabaseOptions&, bool newDb);
|
||||||
static void prepare_tra(thread_db*, jrd_tra*, USHORT, const UCHAR*);
|
static void prepare_tra(thread_db*, jrd_tra*, USHORT, const UCHAR*);
|
||||||
static void release_attachment(thread_db*, Attachment*);
|
static void release_attachment(thread_db*, Attachment*, XThreadEnsureUnlock* = nullptr);
|
||||||
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 rollback(thread_db*, jrd_tra*, const bool);
|
static void rollback(thread_db*, jrd_tra*, const bool);
|
||||||
@ -1541,7 +1553,7 @@ static void trace_warning(thread_db* tdbb, FbStatusVector* userStatus, const cha
|
|||||||
|
|
||||||
|
|
||||||
static void trace_failed_attach(TraceManager* traceManager, const char* filename,
|
static void trace_failed_attach(TraceManager* traceManager, const char* filename,
|
||||||
const DatabaseOptions& options, bool create, FbStatusVector* status)
|
const DatabaseOptions& options, bool create, FbStatusVector* status, ICryptKeyCallback* callback)
|
||||||
{
|
{
|
||||||
// Report to Trace API that attachment has not been created
|
// Report to Trace API that attachment has not been created
|
||||||
const char* origFilename = filename;
|
const char* origFilename = filename;
|
||||||
@ -1556,15 +1568,24 @@ static void trace_failed_attach(TraceManager* traceManager, const char* filename
|
|||||||
ITracePlugin::RESULT_UNAUTHORIZED : ITracePlugin::RESULT_FAILED;
|
ITracePlugin::RESULT_UNAUTHORIZED : ITracePlugin::RESULT_FAILED;
|
||||||
const char* func = create ? "JProvider::createDatabase" : "JProvider::attachDatabase";
|
const char* func = create ? "JProvider::createDatabase" : "JProvider::attachDatabase";
|
||||||
|
|
||||||
|
Attachment* att = traceManager ? traceManager->getAttachment() : nullptr;
|
||||||
|
if (traceManager && (! traceManager->isActive()))
|
||||||
|
traceManager = nullptr;
|
||||||
|
|
||||||
if (!traceManager)
|
if (!traceManager)
|
||||||
{
|
{
|
||||||
TraceManager tempMgr(origFilename);
|
if (!options.dpb_map_attach)
|
||||||
|
{
|
||||||
|
EngineCheckout guard(att, FB_FUNCTION, true);
|
||||||
|
|
||||||
if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ATTACH))
|
TraceManager tempMgr(origFilename, callback);
|
||||||
tempMgr.event_attach(&conn, create, result);
|
|
||||||
|
|
||||||
if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ERROR))
|
if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ATTACH))
|
||||||
tempMgr.event_error(&conn, &traceStatus, func);
|
tempMgr.event_attach(&conn, create, result);
|
||||||
|
|
||||||
|
if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ERROR))
|
||||||
|
tempMgr.event_error(&conn, &traceStatus, func);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1696,7 +1717,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
|
|||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
ex.stuffException(user_status);
|
ex.stuffException(user_status);
|
||||||
trace_failed_attach(NULL, filename, options, false, user_status);
|
trace_failed_attach(NULL, filename, options, false, user_status, cryptCallback);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1704,7 +1725,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
|
|||||||
const VdnResult vdn = verifyDatabaseName(expanded_name, tdbb->tdbb_status_vector, is_alias);
|
const VdnResult vdn = verifyDatabaseName(expanded_name, tdbb->tdbb_status_vector, is_alias);
|
||||||
if (!is_alias && vdn == VDN_FAIL)
|
if (!is_alias && vdn == VDN_FAIL)
|
||||||
{
|
{
|
||||||
trace_failed_attach(NULL, filename, options, false, tdbb->tdbb_status_vector);
|
trace_failed_attach(NULL, filename, options, false, tdbb->tdbb_status_vector, cryptCallback);
|
||||||
status_exception::raise(tdbb->tdbb_status_vector);
|
status_exception::raise(tdbb->tdbb_status_vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2275,9 +2296,8 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
trace_failed_attach(attachment && attachment->att_trace_manager &&
|
trace_failed_attach(attachment ? attachment->att_trace_manager : NULL,
|
||||||
attachment->att_trace_manager->isActive() ? attachment->att_trace_manager : NULL,
|
filename, options, false, user_status, cryptCallback);
|
||||||
filename, options, false, user_status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mapping.clearMainHandle();
|
mapping.clearMainHandle();
|
||||||
@ -2878,7 +2898,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
|
|||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
ex.stuffException(user_status);
|
ex.stuffException(user_status);
|
||||||
trace_failed_attach(NULL, filename, options, true, user_status);
|
trace_failed_attach(NULL, filename, options, true, user_status, cryptCallback);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2886,7 +2906,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
|
|||||||
const VdnResult vdn = verifyDatabaseName(expanded_name, tdbb->tdbb_status_vector, is_alias);
|
const VdnResult vdn = verifyDatabaseName(expanded_name, tdbb->tdbb_status_vector, is_alias);
|
||||||
if (!is_alias && vdn == VDN_FAIL)
|
if (!is_alias && vdn == VDN_FAIL)
|
||||||
{
|
{
|
||||||
trace_failed_attach(NULL, filename, options, true, tdbb->tdbb_status_vector);
|
trace_failed_attach(NULL, filename, options, true, tdbb->tdbb_status_vector, cryptCallback);
|
||||||
status_exception::raise(tdbb->tdbb_status_vector);
|
status_exception::raise(tdbb->tdbb_status_vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3213,9 +3233,8 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
|
|||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
ex.stuffException(user_status);
|
ex.stuffException(user_status);
|
||||||
trace_failed_attach(attachment && attachment->att_trace_manager &&
|
trace_failed_attach(attachment ? attachment->att_trace_manager : NULL,
|
||||||
attachment->att_trace_manager->isActive() ? attachment->att_trace_manager : NULL,
|
filename, options, true, user_status, cryptCallback);
|
||||||
filename, options, true, user_status);
|
|
||||||
|
|
||||||
mapping.clearMainHandle();
|
mapping.clearMainHandle();
|
||||||
unwindAttach(tdbb, ex, user_status, false);
|
unwindAttach(tdbb, ex, user_status, false);
|
||||||
@ -3425,6 +3444,7 @@ void JAttachment::internalDropDatabase(CheckStatusWrapper* user_status)
|
|||||||
// Prepare to set ODS to 0
|
// Prepare to set ODS to 0
|
||||||
WIN window(HEADER_PAGE_NUMBER);
|
WIN window(HEADER_PAGE_NUMBER);
|
||||||
Ods::header_page* header = NULL;
|
Ods::header_page* header = NULL;
|
||||||
|
XThreadEnsureUnlock threadGuard(dbb->dbb_thread_mutex, FB_FUNCTION);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -3450,6 +3470,13 @@ void JAttachment::internalDropDatabase(CheckStatusWrapper* user_status)
|
|||||||
ERR_post(Arg::Gds(isc_att_shutdown));
|
ERR_post(Arg::Gds(isc_att_shutdown));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// try to block special threads before taking exclusive lock on database
|
||||||
|
if (!threadGuard.tryEnter())
|
||||||
|
{
|
||||||
|
ERR_post(Arg::Gds(isc_no_meta_update) <<
|
||||||
|
Arg::Gds(isc_obj_in_use) << Arg::Str("DATABASE"));
|
||||||
|
}
|
||||||
|
|
||||||
if (!CCH_exclusive(tdbb, LCK_PW, WAIT_PERIOD, NULL))
|
if (!CCH_exclusive(tdbb, LCK_PW, WAIT_PERIOD, NULL))
|
||||||
{
|
{
|
||||||
ERR_post(Arg::Gds(isc_lock_timeout) <<
|
ERR_post(Arg::Gds(isc_lock_timeout) <<
|
||||||
@ -3505,7 +3532,7 @@ void JAttachment::internalDropDatabase(CheckStatusWrapper* user_status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unlink attachment from database
|
// Unlink attachment from database
|
||||||
release_attachment(tdbb, attachment);
|
release_attachment(tdbb, attachment, &threadGuard);
|
||||||
att = NULL;
|
att = NULL;
|
||||||
attachment = NULL;
|
attachment = NULL;
|
||||||
guard.leave();
|
guard.leave();
|
||||||
@ -4581,62 +4608,66 @@ void JProvider::shutdown(CheckStatusWrapper* status, unsigned int timeout, const
|
|||||||
**************************************/
|
**************************************/
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MutexLockGuard guard(shutdownMutex, FB_FUNCTION);
|
|
||||||
|
|
||||||
if (engineShutdown)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
{ // scope
|
{ // scope
|
||||||
MutexLockGuard guard(newAttachmentMutex, FB_FUNCTION);
|
MutexLockGuard guard(shutdownMutex, FB_FUNCTION);
|
||||||
engineShutdown = true;
|
|
||||||
|
if (engineShutdown)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
{ // scope
|
||||||
|
MutexLockGuard guard(newAttachmentMutex, FB_FUNCTION);
|
||||||
|
engineShutdown = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadContextHolder tdbb;
|
||||||
|
WorkerAttachment::shutdown();
|
||||||
|
EDS::Manager::shutdown();
|
||||||
|
|
||||||
|
ULONG attach_count, database_count, svc_count;
|
||||||
|
JRD_enum_attachments(NULL, attach_count, database_count, svc_count);
|
||||||
|
|
||||||
|
if (attach_count > 0 || svc_count > 0)
|
||||||
|
{
|
||||||
|
gds__log("Shutting down the server with %d active connection(s) to %d database(s), "
|
||||||
|
"%d active service(s)",
|
||||||
|
attach_count, database_count, svc_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reason == fb_shutrsn_exit_called)
|
||||||
|
{
|
||||||
|
// Starting threads may fail when task is going to close.
|
||||||
|
// This happens at least with some microsoft C runtimes.
|
||||||
|
// If people wish to have timeout, they should better call fb_shutdown() themselves.
|
||||||
|
// Therefore:
|
||||||
|
timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout)
|
||||||
|
{
|
||||||
|
Semaphore shutdown_semaphore;
|
||||||
|
|
||||||
|
Thread::Handle h;
|
||||||
|
Thread::start(shutdown_thread, &shutdown_semaphore, THREAD_medium, &h);
|
||||||
|
|
||||||
|
if (!shutdown_semaphore.tryEnter(0, timeout))
|
||||||
|
waitForShutdown(shutdown_semaphore);
|
||||||
|
|
||||||
|
Thread::waitForCompletion(h);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shutdown_thread(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not put it into separate shutdown thread - during shutdown of TraceManager
|
||||||
|
// PluginManager wants to lock a mutex, which is sometimes already locked in current thread
|
||||||
|
TraceManager::shutdown();
|
||||||
|
Mapping::shutdownIpc();
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadContextHolder tdbb;
|
// Wait for completion of all attacment shutdown threads
|
||||||
|
shutThreadCollect->join();
|
||||||
WorkerAttachment::shutdown();
|
|
||||||
EDS::Manager::shutdown();
|
|
||||||
|
|
||||||
ULONG attach_count, database_count, svc_count;
|
|
||||||
JRD_enum_attachments(NULL, attach_count, database_count, svc_count);
|
|
||||||
|
|
||||||
if (attach_count > 0 || svc_count > 0)
|
|
||||||
{
|
|
||||||
gds__log("Shutting down the server with %d active connection(s) to %d database(s), "
|
|
||||||
"%d active service(s)",
|
|
||||||
attach_count, database_count, svc_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reason == fb_shutrsn_exit_called)
|
|
||||||
{
|
|
||||||
// Starting threads may fail when task is going to close.
|
|
||||||
// This happens at least with some microsoft C runtimes.
|
|
||||||
// If people wish to have timeout, they should better call fb_shutdown() themselves.
|
|
||||||
// Therefore:
|
|
||||||
timeout = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout)
|
|
||||||
{
|
|
||||||
Semaphore shutdown_semaphore;
|
|
||||||
|
|
||||||
Thread::Handle h;
|
|
||||||
Thread::start(shutdown_thread, &shutdown_semaphore, THREAD_medium, &h);
|
|
||||||
|
|
||||||
if (!shutdown_semaphore.tryEnter(0, timeout))
|
|
||||||
waitForShutdown(shutdown_semaphore);
|
|
||||||
|
|
||||||
Thread::waitForCompletion(h);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
shutdown_thread(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do not put it into separate shutdown thread - during shutdown of TraceManager
|
|
||||||
// PluginManager wants to lock a mutex, which is sometimes already locked in current thread
|
|
||||||
TraceManager::shutdown();
|
|
||||||
Mapping::shutdownIpc();
|
|
||||||
}
|
}
|
||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
@ -7605,7 +7636,7 @@ static void prepare_tra(thread_db* tdbb, jrd_tra* transaction, USHORT length, co
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment, XThreadEnsureUnlock* dropGuard)
|
||||||
{
|
{
|
||||||
/**************************************
|
/**************************************
|
||||||
*
|
*
|
||||||
@ -7686,8 +7717,14 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
|||||||
Sync sync(&dbb->dbb_sync, "jrd.cpp: release_attachment");
|
Sync sync(&dbb->dbb_sync, "jrd.cpp: release_attachment");
|
||||||
|
|
||||||
// avoid races with special threads
|
// avoid races with special threads
|
||||||
|
// take into an account lock earlier taken in DROP DATABASE
|
||||||
XThreadEnsureUnlock threadGuard(dbb->dbb_thread_mutex, FB_FUNCTION);
|
XThreadEnsureUnlock threadGuard(dbb->dbb_thread_mutex, FB_FUNCTION);
|
||||||
threadGuard.enter();
|
XThreadEnsureUnlock* activeThreadGuard = dropGuard;
|
||||||
|
if (!activeThreadGuard)
|
||||||
|
{
|
||||||
|
threadGuard.enter();
|
||||||
|
activeThreadGuard = &threadGuard;
|
||||||
|
}
|
||||||
|
|
||||||
sync.lock(SYNC_EXCLUSIVE);
|
sync.lock(SYNC_EXCLUSIVE);
|
||||||
|
|
||||||
@ -7721,7 +7758,7 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Notify special threads
|
// Notify special threads
|
||||||
threadGuard.leave();
|
activeThreadGuard->leave();
|
||||||
|
|
||||||
// Sync with special threads
|
// Sync with special threads
|
||||||
if (!other)
|
if (!other)
|
||||||
@ -8725,22 +8762,26 @@ namespace
|
|||||||
ThreadModuleRef thdRef(attachmentShutdownThread, &engineShutdown);
|
ThreadModuleRef thdRef(attachmentShutdownThread, &engineShutdown);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
AttShutParams* params = static_cast<AttShutParams*>(arg);
|
||||||
|
AttachmentsRefHolder* attachments = params->attachments;
|
||||||
|
Thread::Handle th = params->thrHandle;
|
||||||
|
fb_assert(th);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MutexLockGuard guard(shutdownMutex, FB_FUNCTION);
|
shutThreadCollect->running(th);
|
||||||
if (engineShutdown)
|
params->thdStartedSem.release();
|
||||||
{
|
|
||||||
// Shutdown was done, all attachmnets are gone
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
shutdownAttachments(static_cast<AttachmentsRefHolder*>(arg), isc_att_shut_db_down);
|
MutexLockGuard guard(shutdownMutex, FB_FUNCTION);
|
||||||
|
if (!engineShutdown)
|
||||||
|
shutdownAttachments(attachments, isc_att_shut_db_down);
|
||||||
}
|
}
|
||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
iscLogException("attachmentShutdownThread", ex);
|
iscLogException("attachmentShutdownThread", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shutThreadCollect->ending(th);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
@ -9527,13 +9568,18 @@ void JRD_shutdown_attachment(Attachment* attachment)
|
|||||||
fb_assert(attachment->att_flags & ATT_shutdown);
|
fb_assert(attachment->att_flags & ATT_shutdown);
|
||||||
|
|
||||||
MemoryPool& pool = *getDefaultMemoryPool();
|
MemoryPool& pool = *getDefaultMemoryPool();
|
||||||
AttachmentsRefHolder* queue = FB_NEW_POOL(pool) AttachmentsRefHolder(pool);
|
AutoPtr<AttachmentsRefHolder> queue(FB_NEW_POOL(pool) AttachmentsRefHolder(pool));
|
||||||
|
|
||||||
fb_assert(attachment->getStable());
|
fb_assert(attachment->getStable());
|
||||||
attachment->getStable()->addRef();
|
attachment->getStable()->addRef();
|
||||||
queue->add(attachment->getStable());
|
queue->add(attachment->getStable());
|
||||||
|
|
||||||
Thread::start(attachmentShutdownThread, queue, THREAD_high);
|
AttShutParams params;
|
||||||
|
params.attachments = queue;
|
||||||
|
Thread::start(attachmentShutdownThread, ¶ms, THREAD_high, ¶ms.thrHandle);
|
||||||
|
queue.release();
|
||||||
|
shutThreadCollect->houseKeeping();
|
||||||
|
params.thdStartedSem.enter();
|
||||||
}
|
}
|
||||||
catch (const Exception&)
|
catch (const Exception&)
|
||||||
{} // no-op
|
{} // no-op
|
||||||
@ -9582,7 +9628,14 @@ void JRD_shutdown_attachments(Database* dbb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (queue.hasData())
|
if (queue.hasData())
|
||||||
Thread::start(attachmentShutdownThread, queue.release(), THREAD_high);
|
{
|
||||||
|
AttShutParams params;
|
||||||
|
params.attachments = queue;
|
||||||
|
Thread::start(attachmentShutdownThread, ¶ms, THREAD_high, ¶ms.thrHandle);
|
||||||
|
queue.release();
|
||||||
|
shutThreadCollect->houseKeeping();
|
||||||
|
params.thdStartedSem.enter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (const Exception&)
|
catch (const Exception&)
|
||||||
{} // no-op
|
{} // no-op
|
||||||
|
@ -1092,10 +1092,10 @@ namespace Jrd {
|
|||||||
m_ref->getSync()->leave();
|
m_ref->getSync()->leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
EngineCheckout(Attachment* att, const char* from)
|
EngineCheckout(Attachment* att, const char* from, bool optional = false)
|
||||||
: m_tdbb(nullptr), m_from(from)
|
: m_tdbb(nullptr), m_from(from)
|
||||||
{
|
{
|
||||||
fb_assert(att);
|
fb_assert(optional || att);
|
||||||
|
|
||||||
if (att && att->att_use_count)
|
if (att && att->att_use_count)
|
||||||
{
|
{
|
||||||
|
@ -200,7 +200,7 @@ Sort::Sort(Database* dbb,
|
|||||||
m_longs = record_size >> SHIFTLONG;
|
m_longs = record_size >> SHIFTLONG;
|
||||||
|
|
||||||
m_min_alloc_size = record_size * MIN_RECORDS_TO_ALLOC;
|
m_min_alloc_size = record_size * MIN_RECORDS_TO_ALLOC;
|
||||||
m_max_alloc_size = MAX(record_size * MIN_RECORDS_TO_ALLOC, MAX_SORT_BUFFER_SIZE);
|
m_max_alloc_size = MAX(m_min_alloc_size, MAX_SORT_BUFFER_SIZE);
|
||||||
|
|
||||||
m_dup_callback = call_back;
|
m_dup_callback = call_back;
|
||||||
m_dup_callback_arg = user_arg;
|
m_dup_callback_arg = user_arg;
|
||||||
@ -619,6 +619,7 @@ void Sort::allocateBuffer(MemoryPool& pool)
|
|||||||
// The sort buffer cache has at least one big block, let's use it
|
// The sort buffer cache has at least one big block, let's use it
|
||||||
m_size_memory = MAX_SORT_BUFFER_SIZE;
|
m_size_memory = MAX_SORT_BUFFER_SIZE;
|
||||||
m_memory = m_dbb->dbb_sort_buffers.pop();
|
m_memory = m_dbb->dbb_sort_buffers.pop();
|
||||||
|
m_flags |= scb_reuse_buffer;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -635,6 +636,10 @@ void Sort::allocateBuffer(MemoryPool& pool)
|
|||||||
{
|
{
|
||||||
m_size_memory = m_max_alloc_size;
|
m_size_memory = m_max_alloc_size;
|
||||||
m_memory = FB_NEW_POOL(*m_dbb->dbb_permanent) UCHAR[m_size_memory];
|
m_memory = FB_NEW_POOL(*m_dbb->dbb_permanent) UCHAR[m_size_memory];
|
||||||
|
|
||||||
|
// Mark the buffer as cacheable for future reuse
|
||||||
|
if (m_size_memory == MAX_SORT_BUFFER_SIZE)
|
||||||
|
m_flags |= scb_reuse_buffer;
|
||||||
}
|
}
|
||||||
catch (const BadAlloc&)
|
catch (const BadAlloc&)
|
||||||
{
|
{
|
||||||
@ -646,6 +651,7 @@ void Sort::allocateBuffer(MemoryPool& pool)
|
|||||||
{
|
{
|
||||||
m_size_memory /= 2;
|
m_size_memory /= 2;
|
||||||
m_memory = FB_NEW_POOL(pool) UCHAR[m_size_memory];
|
m_memory = FB_NEW_POOL(pool) UCHAR[m_size_memory];
|
||||||
|
m_flags &= ~scb_reuse_buffer;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (const BadAlloc&)
|
catch (const BadAlloc&)
|
||||||
@ -666,13 +672,17 @@ void Sort::releaseBuffer()
|
|||||||
|
|
||||||
SyncLockGuard guard(&m_dbb->dbb_sortbuf_sync, SYNC_EXCLUSIVE, "Sort::releaseBuffer");
|
SyncLockGuard guard(&m_dbb->dbb_sortbuf_sync, SYNC_EXCLUSIVE, "Sort::releaseBuffer");
|
||||||
|
|
||||||
if (m_size_memory == MAX_SORT_BUFFER_SIZE &&
|
if ((m_flags & scb_reuse_buffer) &&
|
||||||
m_dbb->dbb_sort_buffers.getCount() < MAX_CACHED_SORT_BUFFERS)
|
m_dbb->dbb_sort_buffers.getCount() < MAX_CACHED_SORT_BUFFERS)
|
||||||
{
|
{
|
||||||
|
fb_assert(m_size_memory == MAX_SORT_BUFFER_SIZE);
|
||||||
|
|
||||||
m_dbb->dbb_sort_buffers.push(m_memory);
|
m_dbb->dbb_sort_buffers.push(m_memory);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
delete[] m_memory;
|
delete[] m_memory;
|
||||||
|
|
||||||
|
m_flags &= ~scb_reuse_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -270,7 +270,8 @@ typedef bool (*FPTR_REJECT_DUP_CALLBACK)(const UCHAR*, const UCHAR*, void*);
|
|||||||
|
|
||||||
// flags as set in m_flags
|
// flags as set in m_flags
|
||||||
|
|
||||||
const int scb_sorted = 1; // stream has been sorted
|
const int scb_sorted = 1; // stream has been sorted
|
||||||
|
const int scb_reuse_buffer = 2; // reuse buffer if possible
|
||||||
|
|
||||||
class Sort
|
class Sort
|
||||||
{
|
{
|
||||||
|
@ -74,6 +74,7 @@
|
|||||||
#include "../utilities/nbackup/nbkswi.h"
|
#include "../utilities/nbackup/nbkswi.h"
|
||||||
#include "../jrd/trace/traceswi.h"
|
#include "../jrd/trace/traceswi.h"
|
||||||
#include "../jrd/val_proto.h"
|
#include "../jrd/val_proto.h"
|
||||||
|
#include "../jrd/ThreadCollect.h"
|
||||||
|
|
||||||
// Service threads
|
// Service threads
|
||||||
#include "../burp/burp_proto.h"
|
#include "../burp/burp_proto.h"
|
||||||
@ -120,6 +121,7 @@ int main_gstat(Firebird::UtilSvc* uSvc);
|
|||||||
|
|
||||||
|
|
||||||
using namespace Firebird;
|
using namespace Firebird;
|
||||||
|
using namespace Jrd;
|
||||||
|
|
||||||
const int SVC_user_dba = 2;
|
const int SVC_user_dba = 2;
|
||||||
const int SVC_user_any = 1;
|
const int SVC_user_any = 1;
|
||||||
@ -138,64 +140,9 @@ namespace {
|
|||||||
GlobalPtr<Mutex> globalServicesMutex;
|
GlobalPtr<Mutex> globalServicesMutex;
|
||||||
|
|
||||||
// All that we need to shutdown service threads when shutdown in progress
|
// All that we need to shutdown service threads when shutdown in progress
|
||||||
typedef Array<Jrd::Service*> AllServices;
|
typedef Array<Service*> AllServices;
|
||||||
GlobalPtr<AllServices> allServices; // protected by globalServicesMutex
|
GlobalPtr<AllServices> allServices; // protected by globalServicesMutex
|
||||||
volatile bool svcShutdown = false;
|
volatile bool svcShutdown = false;
|
||||||
|
|
||||||
class ThreadCollect
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ThreadCollect(MemoryPool& p)
|
|
||||||
: threads(p)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void join()
|
|
||||||
{
|
|
||||||
// join threads to be sure they are gone when shutdown is complete
|
|
||||||
// no need locking something cause this is expected to run when services are closing
|
|
||||||
waitFor(threads);
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(const Thread::Handle& h)
|
|
||||||
{
|
|
||||||
// put thread into completion wait queue when it finished running
|
|
||||||
MutexLockGuard g(threadsMutex, FB_FUNCTION);
|
|
||||||
fb_assert(h);
|
|
||||||
threads.add(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void houseKeeping()
|
|
||||||
{
|
|
||||||
if (!threads.hasData())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// join finished threads
|
|
||||||
AllThreads t;
|
|
||||||
{ // mutex scope
|
|
||||||
MutexLockGuard g(threadsMutex, FB_FUNCTION);
|
|
||||||
t.assign(threads);
|
|
||||||
threads.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
waitFor(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef Array<Thread::Handle> AllThreads;
|
|
||||||
|
|
||||||
static void waitFor(AllThreads& thr)
|
|
||||||
{
|
|
||||||
while (thr.hasData())
|
|
||||||
{
|
|
||||||
Thread::Handle h(thr.pop());
|
|
||||||
Thread::waitForCompletion(h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AllThreads threads;
|
|
||||||
Mutex threadsMutex;
|
|
||||||
};
|
|
||||||
|
|
||||||
GlobalPtr<ThreadCollect> threadCollect;
|
GlobalPtr<ThreadCollect> threadCollect;
|
||||||
|
|
||||||
void spbVersionError()
|
void spbVersionError()
|
||||||
@ -207,8 +154,6 @@ namespace {
|
|||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
using namespace Jrd;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const serv_entry services[] =
|
const serv_entry services[] =
|
||||||
{
|
{
|
||||||
@ -1975,7 +1920,7 @@ THREAD_ENTRY_DECLARE Service::run(THREAD_ENTRY_PARAM arg)
|
|||||||
svc->unblockQueryGet();
|
svc->unblockQueryGet();
|
||||||
svc->finish(SVC_finished);
|
svc->finish(SVC_finished);
|
||||||
|
|
||||||
threadCollect->add(thrHandle);
|
threadCollect->ending(thrHandle);
|
||||||
}
|
}
|
||||||
catch (const Exception& ex)
|
catch (const Exception& ex)
|
||||||
{
|
{
|
||||||
|
@ -4061,13 +4061,17 @@ void jrd_tra::checkBlob(thread_db* tdbb, const bid* blob_id, jrd_fld* fld, bool
|
|||||||
vec<jrd_rel*>* vector = tra_attachment->att_relations;
|
vec<jrd_rel*>* vector = tra_attachment->att_relations;
|
||||||
jrd_rel* blb_relation;
|
jrd_rel* blb_relation;
|
||||||
|
|
||||||
if (rel_id < vector->count() && (blb_relation = (*vector)[rel_id]))
|
if ((rel_id < vector->count() && (blb_relation = (*vector)[rel_id])) ||
|
||||||
|
(blb_relation = MET_relation(tdbb, rel_id)))
|
||||||
{
|
{
|
||||||
const MetaName security_name = fld ?
|
MetaName security_name = (fld && fld->fld_security_name.hasData()) ?
|
||||||
fld->fld_security_name : blb_relation->rel_security_name;
|
fld->fld_security_name : blb_relation->rel_security_name;
|
||||||
|
|
||||||
if (security_name.isEmpty())
|
if (security_name.isEmpty())
|
||||||
|
{
|
||||||
MET_scan_relation(tdbb, blb_relation);
|
MET_scan_relation(tdbb, blb_relation);
|
||||||
|
security_name = blb_relation->rel_security_name;
|
||||||
|
}
|
||||||
|
|
||||||
SecurityClass* s_class = SCL_get_class(tdbb, security_name.c_str());
|
SecurityClass* s_class = SCL_get_class(tdbb, security_name.c_str());
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ TraceManager::TraceManager(Attachment* in_att) :
|
|||||||
attachment(in_att),
|
attachment(in_att),
|
||||||
service(NULL),
|
service(NULL),
|
||||||
filename(NULL),
|
filename(NULL),
|
||||||
|
callback(NULL),
|
||||||
trace_sessions(*in_att->att_pool),
|
trace_sessions(*in_att->att_pool),
|
||||||
active(false)
|
active(false)
|
||||||
{
|
{
|
||||||
@ -98,16 +99,18 @@ TraceManager::TraceManager(Service* in_svc) :
|
|||||||
attachment(NULL),
|
attachment(NULL),
|
||||||
service(in_svc),
|
service(in_svc),
|
||||||
filename(NULL),
|
filename(NULL),
|
||||||
|
callback(NULL),
|
||||||
trace_sessions(in_svc->getPool()),
|
trace_sessions(in_svc->getPool()),
|
||||||
active(true)
|
active(true)
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceManager::TraceManager(const char* in_filename) :
|
TraceManager::TraceManager(const char* in_filename, ICryptKeyCallback* cb) :
|
||||||
attachment(NULL),
|
attachment(NULL),
|
||||||
service(NULL),
|
service(NULL),
|
||||||
filename(in_filename),
|
filename(in_filename),
|
||||||
|
callback(cb),
|
||||||
trace_sessions(*getDefaultMemoryPool()),
|
trace_sessions(*getDefaultMemoryPool()),
|
||||||
active(true)
|
active(true)
|
||||||
{
|
{
|
||||||
@ -251,7 +254,8 @@ void TraceManager::update_session(const TraceSession& session)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if this session is not from administrator, it may trace connections
|
// if this session is not from administrator, it may trace connections
|
||||||
// only created by the same user
|
// only created by the same user, or when it has TRACE_ANY_ATTACHMENT
|
||||||
|
// privilege in current context
|
||||||
if (!(session.ses_flags & (trs_admin | trs_system)))
|
if (!(session.ses_flags & (trs_admin | trs_system)))
|
||||||
{
|
{
|
||||||
const char* curr_user = nullptr;
|
const char* curr_user = nullptr;
|
||||||
@ -265,10 +269,11 @@ void TraceManager::update_session(const TraceSession& session)
|
|||||||
|
|
||||||
if (attachment)
|
if (attachment)
|
||||||
{
|
{
|
||||||
if ((!attachment->att_user) || (attachment->att_flags & ATT_mapping))
|
if (attachment->att_flags & ATT_mapping)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
curr_user = attachment->getUserName().c_str();
|
if (attachment->att_user)
|
||||||
|
curr_user = attachment->att_user->getUserName().c_str();
|
||||||
|
|
||||||
if (session.ses_auth.hasData())
|
if (session.ses_auth.hasData())
|
||||||
{
|
{
|
||||||
@ -290,7 +295,7 @@ void TraceManager::update_session(const TraceSession& session)
|
|||||||
}
|
}
|
||||||
else if (service)
|
else if (service)
|
||||||
{
|
{
|
||||||
curr_user = service->getUserName().c_str();
|
curr_user = service->getUserName().nullStr();
|
||||||
|
|
||||||
if (session.ses_auth.hasData())
|
if (session.ses_auth.hasData())
|
||||||
{
|
{
|
||||||
@ -308,6 +313,26 @@ void TraceManager::update_session(const TraceSession& session)
|
|||||||
mapResult = mapping.mapUser(s_user, t_role);
|
mapResult = mapping.mapUser(s_user, t_role);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (filename)
|
||||||
|
{
|
||||||
|
if (session.ses_auth.hasData())
|
||||||
|
{
|
||||||
|
Mapping mapping(Mapping::MAP_NO_FLAGS, callback);
|
||||||
|
mapping.needSystemPrivileges(priv);
|
||||||
|
mapping.setAuthBlock(session.ses_auth);
|
||||||
|
mapping.setSqlRole(session.ses_role);
|
||||||
|
|
||||||
|
RefPtr<const Config> config;
|
||||||
|
PathName org_filename(filename), expanded_name;
|
||||||
|
if (! expandDatabaseName(org_filename, expanded_name, &config))
|
||||||
|
expanded_name = filename;
|
||||||
|
|
||||||
|
mapping.setSecurityDbAlias(config->getSecurityDatabase(), expanded_name.c_str());
|
||||||
|
mapping.setDb(filename, expanded_name.c_str(), nullptr);
|
||||||
|
|
||||||
|
mapResult = mapping.mapUser(s_user, t_role);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// failed attachment attempts traced by admin trace only
|
// failed attachment attempts traced by admin trace only
|
||||||
@ -327,7 +352,7 @@ void TraceManager::update_session(const TraceSession& session)
|
|||||||
|
|
||||||
t_role.upper();
|
t_role.upper();
|
||||||
if (s_user != DBA_USER_NAME && t_role != ADMIN_ROLE &&
|
if (s_user != DBA_USER_NAME && t_role != ADMIN_ROLE &&
|
||||||
s_user != curr_user && (!priv.test(TRACE_ANY_ATTACHMENT)))
|
((!curr_user) || (s_user != curr_user)) && (!priv.test(TRACE_ANY_ATTACHMENT)))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,12 @@
|
|||||||
#include "../../jrd/trace/TraceConfigStorage.h"
|
#include "../../jrd/trace/TraceConfigStorage.h"
|
||||||
#include "../../jrd/trace/TraceSession.h"
|
#include "../../jrd/trace/TraceSession.h"
|
||||||
|
|
||||||
|
namespace Firebird {
|
||||||
|
|
||||||
|
class ICryptKeyCallback;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace Jrd {
|
namespace Jrd {
|
||||||
|
|
||||||
class Database;
|
class Database;
|
||||||
@ -52,7 +58,7 @@ public:
|
|||||||
/* Initializes plugins. */
|
/* Initializes plugins. */
|
||||||
explicit TraceManager(Attachment* in_att);
|
explicit TraceManager(Attachment* in_att);
|
||||||
explicit TraceManager(Service* in_svc);
|
explicit TraceManager(Service* in_svc);
|
||||||
explicit TraceManager(const char* in_filename);
|
TraceManager(const char* in_filename, Firebird::ICryptKeyCallback* callback);
|
||||||
|
|
||||||
/* Finalize plugins. Called when database is closed by the engine */
|
/* Finalize plugins. Called when database is closed by the engine */
|
||||||
~TraceManager();
|
~TraceManager();
|
||||||
@ -142,6 +148,12 @@ public:
|
|||||||
return active;
|
return active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// external access to stored attachment
|
||||||
|
Attachment* getAttachment()
|
||||||
|
{
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
|
||||||
/* DSQL-friendly routines to call Trace API hooks.
|
/* DSQL-friendly routines to call Trace API hooks.
|
||||||
Needed because DSQL cannot include JRD for the current engine */
|
Needed because DSQL cannot include JRD for the current engine */
|
||||||
static bool need_dsql_prepare(Attachment* att);
|
static bool need_dsql_prepare(Attachment* att);
|
||||||
@ -163,6 +175,7 @@ private:
|
|||||||
Attachment* attachment;
|
Attachment* attachment;
|
||||||
Service* service;
|
Service* service;
|
||||||
const char* filename;
|
const char* filename;
|
||||||
|
Firebird::ICryptKeyCallback* callback;
|
||||||
NotificationNeeds trace_needs, new_needs;
|
NotificationNeeds trace_needs, new_needs;
|
||||||
|
|
||||||
// This structure should be POD-like to be stored in Array
|
// This structure should be POD-like to be stored in Array
|
||||||
|
@ -9,7 +9,7 @@ BuildType=T
|
|||||||
MajorVer=5
|
MajorVer=5
|
||||||
MinorVer=0
|
MinorVer=0
|
||||||
RevNo=0
|
RevNo=0
|
||||||
BuildNum=501
|
BuildNum=516
|
||||||
|
|
||||||
NowAt=`pwd`
|
NowAt=`pwd`
|
||||||
cd `dirname $0`
|
cd `dirname $0`
|
||||||
|
@ -66,6 +66,10 @@ public:
|
|||||||
void deprecatedDisconnect(CheckStatusWrapper* status);
|
void deprecatedDisconnect(CheckStatusWrapper* status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void internalCommit(CheckStatusWrapper* status);
|
||||||
|
void internalRollback(CheckStatusWrapper* status);
|
||||||
|
void internalDisconnect(CheckStatusWrapper* status);
|
||||||
|
|
||||||
typedef HalfStaticArray<ITransaction*, 8> SubArray;
|
typedef HalfStaticArray<ITransaction*, 8> SubArray;
|
||||||
typedef HalfStaticArray<UCHAR, 1024> TdrBuffer;
|
typedef HalfStaticArray<UCHAR, 1024> TdrBuffer;
|
||||||
SubArray sub;
|
SubArray sub;
|
||||||
@ -248,7 +252,7 @@ void DTransaction::prepare(CheckStatusWrapper* status,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DTransaction::commit(CheckStatusWrapper* status)
|
void DTransaction::internalCommit(CheckStatusWrapper* status)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -309,7 +313,7 @@ void DTransaction::commitRetaining(CheckStatusWrapper* status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DTransaction::rollback(CheckStatusWrapper* status)
|
void DTransaction::internalRollback(CheckStatusWrapper* status)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -361,7 +365,7 @@ void DTransaction::rollbackRetaining(CheckStatusWrapper* status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DTransaction::disconnect(CheckStatusWrapper* status)
|
void DTransaction::internalDisconnect(CheckStatusWrapper* status)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -392,17 +396,38 @@ void DTransaction::disconnect(CheckStatusWrapper* status)
|
|||||||
|
|
||||||
void DTransaction::deprecatedCommit(CheckStatusWrapper* status)
|
void DTransaction::deprecatedCommit(CheckStatusWrapper* status)
|
||||||
{
|
{
|
||||||
commit(status);
|
internalCommit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DTransaction::deprecatedRollback(CheckStatusWrapper* status)
|
void DTransaction::deprecatedRollback(CheckStatusWrapper* status)
|
||||||
{
|
{
|
||||||
rollback(status);
|
internalRollback(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DTransaction::deprecatedDisconnect(CheckStatusWrapper* status)
|
void DTransaction::deprecatedDisconnect(CheckStatusWrapper* status)
|
||||||
{
|
{
|
||||||
disconnect(status);
|
internalDisconnect(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DTransaction::disconnect(CheckStatusWrapper* status)
|
||||||
|
{
|
||||||
|
internalDisconnect(status);
|
||||||
|
if (status->isEmpty())
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DTransaction::rollback(CheckStatusWrapper* status)
|
||||||
|
{
|
||||||
|
internalRollback(status);
|
||||||
|
if (status->isEmpty())
|
||||||
|
release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DTransaction::commit(CheckStatusWrapper* status)
|
||||||
|
{
|
||||||
|
internalCommit(status);
|
||||||
|
if (status->isEmpty())
|
||||||
|
release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5432,8 +5432,6 @@ YTransaction* YTransaction::enterDtc(CheckStatusWrapper* status)
|
|||||||
YEntry<YTransaction> entry(status, this);
|
YEntry<YTransaction> entry(status, this);
|
||||||
|
|
||||||
YTransaction* copy = FB_NEW YTransaction(this);
|
YTransaction* copy = FB_NEW YTransaction(this);
|
||||||
// copy is created with zero handle
|
|
||||||
copy->addRef();
|
|
||||||
copy->addRef();
|
copy->addRef();
|
||||||
next->addRef(); // We use NoIncr in YTransaction ctor
|
next->addRef(); // We use NoIncr in YTransaction ctor
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user