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 fbTrans 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 gds_status (&tdgbl->status_vector)
|
||||
|
||||
// unused
|
||||
#define fbProvider
|
||||
#define fbStatus2
|
||||
|
||||
DATABASE DB = STATIC FILENAME "yachts.lnk";
|
||||
|
||||
|
||||
void detectRuntimeODS()
|
||||
{
|
||||
|
@ -72,8 +72,6 @@ using namespace Burp;
|
||||
// GPRE. This is to avoid multiple threading problems with module
|
||||
// level statics.
|
||||
|
||||
DATABASE DB = STATIC FILENAME "yachts.lnk" RUNTIME * dbb_file;
|
||||
|
||||
#define DB tdgbl->db_handle
|
||||
#define fbTrans 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 gds_status (&tdgbl->status_vector)
|
||||
|
||||
// unused
|
||||
#define fbProvider
|
||||
#define fbStatus2
|
||||
|
||||
DATABASE DB = STATIC FILENAME "yachts.lnk" RUNTIME * dbb_file;
|
||||
|
||||
namespace // unnamed, private
|
||||
{
|
||||
|
||||
|
@ -73,8 +73,6 @@ using namespace Burp;
|
||||
// GPRE. This is to avoid multiple threading problems with module
|
||||
// level statics.
|
||||
|
||||
DATABASE DB = STATIC FILENAME "yachts.lnk";
|
||||
|
||||
#define DB tdgbl->db_handle
|
||||
#define fbTrans 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 gds_status (&tdgbl->status_vector)
|
||||
|
||||
// unused
|
||||
#define fbProvider
|
||||
#define fbStatus2
|
||||
|
||||
DATABASE DB = STATIC FILENAME "yachts.lnk";
|
||||
|
||||
|
||||
namespace // unnamed, private
|
||||
{
|
||||
@ -1682,16 +1686,22 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
||||
burp_fld* field = NULL;
|
||||
FbLocalStatus status_vector;
|
||||
USHORT count, field_number, field_length = 0;
|
||||
UCHAR* buffer = NULL;
|
||||
UCHAR** buffer = NULL;
|
||||
UCHAR* p = NULL;
|
||||
UCHAR blr_buffer[200]; // enough for a sdl with 16 dimensions
|
||||
lstring xdr_slice;
|
||||
|
||||
// don't free something you don't allocate
|
||||
lstring xdr_buffer;
|
||||
xdr_buffer.lstr_allocated = 0;
|
||||
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
|
||||
SLONG fld_ranges[2 * MAX_DIMENSION];
|
||||
SLONG slice_length = 0;
|
||||
@ -1990,7 +2000,6 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
||||
|
||||
if (data_at == 0)
|
||||
{
|
||||
buffer = BURP_alloc (return_length);
|
||||
SLONG lcount = 0;
|
||||
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) << 16;
|
||||
lcount |= get(tdgbl) << 24;
|
||||
|
||||
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_address = buffer;
|
||||
p = xdr_buffer.lstr_address;
|
||||
buffer = &xdr_slice.lstr_address;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p = buffer;
|
||||
buffer = &p;
|
||||
lcount = return_length;
|
||||
}
|
||||
|
||||
fb_assert(buffer);
|
||||
*buffer = BURP_alloc(return_length);
|
||||
|
||||
if (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,
|
||||
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())
|
||||
{
|
||||
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;
|
||||
|
||||
buffer = BURP_alloc (return_length);
|
||||
SLONG lcount = 0;
|
||||
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) << 24;
|
||||
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_address = buffer;
|
||||
p = xdr_buffer.lstr_address;
|
||||
buffer = &xdr_slice.lstr_address;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p = buffer;
|
||||
buffer = &p;
|
||||
lcount = return_length;
|
||||
}
|
||||
|
||||
fb_assert(buffer);
|
||||
*buffer = BURP_alloc (return_length);
|
||||
|
||||
if (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,
|
||||
0, NULL, // parameters for subset of an array handling
|
||||
return_length, buffer);
|
||||
return_length, *buffer);
|
||||
if (status_vector->hasData())
|
||||
{
|
||||
BURP_print (false, 81, field->fld_name);
|
||||
@ -2165,10 +2180,6 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
|
||||
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;
|
||||
data.lstr_allocated = 0;
|
||||
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();
|
||||
UCHAR* sql = batch ? sql = req->getBatchMsgData() : nullptr;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define CLASSES_AUTO_PTR_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <functional>
|
||||
|
||||
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
|
||||
|
||||
#endif // CLASSES_AUTO_PTR_H
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "firebird.h"
|
||||
#include "init.h"
|
||||
#include "alloc.h"
|
||||
#include "auto.h"
|
||||
#include "../common/SimpleStatusVector.h"
|
||||
#include "../common/dllinst.h"
|
||||
#include "../common/os/os_utils.h"
|
||||
@ -142,17 +143,10 @@ namespace
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
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.
|
||||
//
|
||||
|
||||
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)
|
||||
{
|
||||
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_MSG(A) (reinterpret_cast<unsigned char*>(A))\n");
|
||||
|
||||
ifndef("fbBlobNull");
|
||||
printa(column, "static %sISC_QUAD", CONST_STR);
|
||||
printa(column + INDENT, "fbBlobNull = {0, 0};\t/* initializer for blobs */");
|
||||
endif();
|
||||
|
||||
const TEXT* scope = "";
|
||||
|
||||
@ -1440,6 +1452,8 @@ static void gen_database(int column)
|
||||
{
|
||||
all_static = all_static && (db->dbb_scope == DBB_STATIC);
|
||||
all_extern = all_extern && (db->dbb_scope == DBB_EXTERN);
|
||||
|
||||
ifndef(db->dbb_name->sym_string);
|
||||
if (db->dbb_scope == DBB_STATIC)
|
||||
scope = "static ";
|
||||
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);
|
||||
else
|
||||
printa(column + INDENT, "%s;\t\t/* database handle */\n", db->dbb_name->sym_string);
|
||||
endif();
|
||||
}
|
||||
|
||||
if (all_static)
|
||||
@ -1456,6 +1471,7 @@ static void gen_database(int column)
|
||||
else if (all_extern)
|
||||
scope = "extern ";
|
||||
|
||||
ifndef(gpreGlob.transaction_name);
|
||||
printa(column, "%sFirebird::ITransaction*", scope);
|
||||
if (!all_extern)
|
||||
printa(column + INDENT, "%s = 0;\t\t/* default transaction handle */",
|
||||
@ -1463,33 +1479,43 @@ static void gen_database(int column)
|
||||
else
|
||||
printa(column + INDENT, "%s;\t\t/* default transaction handle */",
|
||||
gpreGlob.transaction_name);
|
||||
endif();
|
||||
|
||||
ifndef("fbMaster");
|
||||
printa(column, "%sFirebird::IMaster* fbMaster%s;\t\t/* master interface */",
|
||||
scope, all_extern ? "" : " = Firebird::fb_get_master_interface()");
|
||||
endif();
|
||||
|
||||
ifndef("fbProvider");
|
||||
printa(column, "%sFirebird::IProvider* fbProvider%s;\t\t/* provider interface */",
|
||||
scope, all_extern ? "" : " = fbMaster->getDispatcher()");
|
||||
endif();
|
||||
|
||||
ifndef(global_status_name);
|
||||
printa(column, "%sFirebird::CheckStatusWrapper %sObj%s;\t/* status vector */",
|
||||
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)
|
||||
{
|
||||
printa(column, "%sFirebird::CheckStatusWrapper* %s;\t/* status vector */",
|
||||
scope, global_status_name);
|
||||
printa(column, "%sFirebird::CheckStatusWrapper* %s2;\t/* status vector */",
|
||||
scope, global_status_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
printa(column, "%sFirebird::CheckStatusWrapper* %s = &%sObj;\t/* status vector */",
|
||||
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 */",
|
||||
scope, global_status_name, global_status_name);
|
||||
}
|
||||
endif();
|
||||
|
||||
ifndef("fbIStatus");
|
||||
printa(column, "%sint fbIStatus;\t/* last completion code */", scope);
|
||||
endif();
|
||||
|
||||
for (db = gpreGlob.isc_databases; db; db = db->dbb_next)
|
||||
for (const tpb* tpb_iterator = db->dbb_tpbs; tpb_iterator;
|
||||
|
@ -493,6 +493,15 @@ namespace Jrd
|
||||
|
||||
// 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,
|
||||
const PathName& filename,
|
||||
RefPtr<const Config> config)
|
||||
@ -512,17 +521,18 @@ namespace Jrd
|
||||
|
||||
Database::GlobalObjectHolder::~GlobalObjectHolder()
|
||||
{
|
||||
// here we cleanup what should not be globally protected
|
||||
if (m_replMgr)
|
||||
m_replMgr->shutdown();
|
||||
|
||||
MutexLockGuard guard(g_mutex, FB_FUNCTION);
|
||||
|
||||
// dtor is executed under g_mutex protection
|
||||
Database::GlobalObjectHolder::DbId* entry = g_hashTable->lookup(m_id);
|
||||
if (!g_hashTable->remove(m_id))
|
||||
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_eventMgr = nullptr;
|
||||
m_replMgr = nullptr;
|
||||
|
@ -306,6 +306,8 @@ class Database : public pool_alloc<type_dbb>
|
||||
const Firebird::PathName& filename,
|
||||
Firebird::RefPtr<const Firebird::Config> config);
|
||||
|
||||
int release() const override;
|
||||
|
||||
~GlobalObjectHolder();
|
||||
|
||||
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 ***
|
||||
TO CHANGE ANY INFORMATION IN HERE PLEASE
|
||||
EDIT src/misc/writeBuildNum.sh
|
||||
FORMAL BUILD NUMBER:501
|
||||
FORMAL BUILD NUMBER:516
|
||||
*/
|
||||
|
||||
#define PRODUCT_VER_STRING "5.0.0.501"
|
||||
#define FILE_VER_STRING "WI-T5.0.0.501"
|
||||
#define LICENSE_VER_STRING "WI-T5.0.0.501"
|
||||
#define FILE_VER_NUMBER 5, 0, 0, 501
|
||||
#define PRODUCT_VER_STRING "5.0.0.516"
|
||||
#define FILE_VER_STRING "WI-T5.0.0.516"
|
||||
#define LICENSE_VER_STRING "WI-T5.0.0.516"
|
||||
#define FILE_VER_NUMBER 5, 0, 0, 516
|
||||
#define FB_MAJOR_VER "5"
|
||||
#define FB_MINOR_VER "0"
|
||||
#define FB_REV_NO "0"
|
||||
#define FB_BUILD_NO "501"
|
||||
#define FB_BUILD_NO "516"
|
||||
#define FB_BUILD_TYPE "T"
|
||||
#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 "../jrd/flags.h"
|
||||
#include "../jrd/Mapping.h"
|
||||
#include "../jrd/ThreadCollect.h"
|
||||
|
||||
#include "../jrd/Database.h"
|
||||
#include "../jrd/WorkerAttachment.h"
|
||||
@ -127,6 +128,7 @@
|
||||
#include "../common/classes/ClumpletWriter.h"
|
||||
#include "../common/classes/RefMutex.h"
|
||||
#include "../common/classes/ParsedList.h"
|
||||
#include "../common/classes/semaphore.h"
|
||||
#include "../common/utils_proto.h"
|
||||
#include "../jrd/DebugInterface.h"
|
||||
#include "../jrd/CryptoManager.h"
|
||||
@ -475,6 +477,16 @@ namespace
|
||||
{
|
||||
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
|
||||
// and helps avoid more than 1 shutdown threads running simultaneously.
|
||||
bool engineShutdown = false;
|
||||
@ -1329,7 +1341,7 @@ static JAttachment* initAttachment(thread_db*, const PathName&, const PathName&,
|
||||
const DatabaseOptions&, RefMutexUnlock&, IPluginConfig*, JProvider*);
|
||||
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 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,
|
||||
Jrd::Attachment* attachment, unsigned int tpb_length, const UCHAR* tpb);
|
||||
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,
|
||||
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
|
||||
const char* origFilename = filename;
|
||||
@ -1556,15 +1568,24 @@ static void trace_failed_attach(TraceManager* traceManager, const char* filename
|
||||
ITracePlugin::RESULT_UNAUTHORIZED : ITracePlugin::RESULT_FAILED;
|
||||
const char* func = create ? "JProvider::createDatabase" : "JProvider::attachDatabase";
|
||||
|
||||
Attachment* att = traceManager ? traceManager->getAttachment() : nullptr;
|
||||
if (traceManager && (! traceManager->isActive()))
|
||||
traceManager = nullptr;
|
||||
|
||||
if (!traceManager)
|
||||
{
|
||||
TraceManager tempMgr(origFilename);
|
||||
if (!options.dpb_map_attach)
|
||||
{
|
||||
EngineCheckout guard(att, FB_FUNCTION, true);
|
||||
|
||||
if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ATTACH))
|
||||
tempMgr.event_attach(&conn, create, result);
|
||||
TraceManager tempMgr(origFilename, callback);
|
||||
|
||||
if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ERROR))
|
||||
tempMgr.event_error(&conn, &traceStatus, func);
|
||||
if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ATTACH))
|
||||
tempMgr.event_attach(&conn, create, result);
|
||||
|
||||
if (tempMgr.needs(ITraceFactory::TRACE_EVENT_ERROR))
|
||||
tempMgr.event_error(&conn, &traceStatus, func);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1696,7 +1717,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
ex.stuffException(user_status);
|
||||
trace_failed_attach(NULL, filename, options, false, user_status);
|
||||
trace_failed_attach(NULL, filename, options, false, user_status, cryptCallback);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2275,9 +2296,8 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
|
||||
}
|
||||
else
|
||||
{
|
||||
trace_failed_attach(attachment && attachment->att_trace_manager &&
|
||||
attachment->att_trace_manager->isActive() ? attachment->att_trace_manager : NULL,
|
||||
filename, options, false, user_status);
|
||||
trace_failed_attach(attachment ? attachment->att_trace_manager : NULL,
|
||||
filename, options, false, user_status, cryptCallback);
|
||||
}
|
||||
|
||||
mapping.clearMainHandle();
|
||||
@ -2878,7 +2898,7 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
ex.stuffException(user_status);
|
||||
trace_failed_attach(NULL, filename, options, true, user_status);
|
||||
trace_failed_attach(NULL, filename, options, true, user_status, cryptCallback);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -3213,9 +3233,8 @@ JAttachment* JProvider::createDatabase(CheckStatusWrapper* user_status, const ch
|
||||
catch (const Exception& ex)
|
||||
{
|
||||
ex.stuffException(user_status);
|
||||
trace_failed_attach(attachment && attachment->att_trace_manager &&
|
||||
attachment->att_trace_manager->isActive() ? attachment->att_trace_manager : NULL,
|
||||
filename, options, true, user_status);
|
||||
trace_failed_attach(attachment ? attachment->att_trace_manager : NULL,
|
||||
filename, options, true, user_status, cryptCallback);
|
||||
|
||||
mapping.clearMainHandle();
|
||||
unwindAttach(tdbb, ex, user_status, false);
|
||||
@ -3425,6 +3444,7 @@ void JAttachment::internalDropDatabase(CheckStatusWrapper* user_status)
|
||||
// Prepare to set ODS to 0
|
||||
WIN window(HEADER_PAGE_NUMBER);
|
||||
Ods::header_page* header = NULL;
|
||||
XThreadEnsureUnlock threadGuard(dbb->dbb_thread_mutex, FB_FUNCTION);
|
||||
|
||||
try
|
||||
{
|
||||
@ -3450,6 +3470,13 @@ void JAttachment::internalDropDatabase(CheckStatusWrapper* user_status)
|
||||
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))
|
||||
{
|
||||
ERR_post(Arg::Gds(isc_lock_timeout) <<
|
||||
@ -3505,7 +3532,7 @@ void JAttachment::internalDropDatabase(CheckStatusWrapper* user_status)
|
||||
}
|
||||
|
||||
// Unlink attachment from database
|
||||
release_attachment(tdbb, attachment);
|
||||
release_attachment(tdbb, attachment, &threadGuard);
|
||||
att = NULL;
|
||||
attachment = NULL;
|
||||
guard.leave();
|
||||
@ -4581,62 +4608,66 @@ void JProvider::shutdown(CheckStatusWrapper* status, unsigned int timeout, const
|
||||
**************************************/
|
||||
try
|
||||
{
|
||||
MutexLockGuard guard(shutdownMutex, FB_FUNCTION);
|
||||
|
||||
if (engineShutdown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
{ // scope
|
||||
MutexLockGuard guard(newAttachmentMutex, FB_FUNCTION);
|
||||
engineShutdown = true;
|
||||
MutexLockGuard guard(shutdownMutex, FB_FUNCTION);
|
||||
|
||||
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;
|
||||
|
||||
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();
|
||||
// Wait for completion of all attacment shutdown threads
|
||||
shutThreadCollect->join();
|
||||
}
|
||||
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");
|
||||
|
||||
// avoid races with special threads
|
||||
// take into an account lock earlier taken in DROP DATABASE
|
||||
XThreadEnsureUnlock threadGuard(dbb->dbb_thread_mutex, FB_FUNCTION);
|
||||
threadGuard.enter();
|
||||
XThreadEnsureUnlock* activeThreadGuard = dropGuard;
|
||||
if (!activeThreadGuard)
|
||||
{
|
||||
threadGuard.enter();
|
||||
activeThreadGuard = &threadGuard;
|
||||
}
|
||||
|
||||
sync.lock(SYNC_EXCLUSIVE);
|
||||
|
||||
@ -7721,7 +7758,7 @@ void release_attachment(thread_db* tdbb, Jrd::Attachment* attachment)
|
||||
}
|
||||
|
||||
// Notify special threads
|
||||
threadGuard.leave();
|
||||
activeThreadGuard->leave();
|
||||
|
||||
// Sync with special threads
|
||||
if (!other)
|
||||
@ -8725,22 +8762,26 @@ namespace
|
||||
ThreadModuleRef thdRef(attachmentShutdownThread, &engineShutdown);
|
||||
#endif
|
||||
|
||||
AttShutParams* params = static_cast<AttShutParams*>(arg);
|
||||
AttachmentsRefHolder* attachments = params->attachments;
|
||||
Thread::Handle th = params->thrHandle;
|
||||
fb_assert(th);
|
||||
|
||||
try
|
||||
{
|
||||
MutexLockGuard guard(shutdownMutex, FB_FUNCTION);
|
||||
if (engineShutdown)
|
||||
{
|
||||
// Shutdown was done, all attachmnets are gone
|
||||
return 0;
|
||||
}
|
||||
shutThreadCollect->running(th);
|
||||
params->thdStartedSem.release();
|
||||
|
||||
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)
|
||||
{
|
||||
iscLogException("attachmentShutdownThread", ex);
|
||||
}
|
||||
|
||||
shutThreadCollect->ending(th);
|
||||
return 0;
|
||||
}
|
||||
} // anonymous namespace
|
||||
@ -9527,13 +9568,18 @@ void JRD_shutdown_attachment(Attachment* attachment)
|
||||
fb_assert(attachment->att_flags & ATT_shutdown);
|
||||
|
||||
MemoryPool& pool = *getDefaultMemoryPool();
|
||||
AttachmentsRefHolder* queue = FB_NEW_POOL(pool) AttachmentsRefHolder(pool);
|
||||
AutoPtr<AttachmentsRefHolder> queue(FB_NEW_POOL(pool) AttachmentsRefHolder(pool));
|
||||
|
||||
fb_assert(attachment->getStable());
|
||||
attachment->getStable()->addRef();
|
||||
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&)
|
||||
{} // no-op
|
||||
@ -9582,7 +9628,14 @@ void JRD_shutdown_attachments(Database* dbb)
|
||||
}
|
||||
|
||||
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&)
|
||||
{} // no-op
|
||||
|
@ -1092,10 +1092,10 @@ namespace Jrd {
|
||||
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)
|
||||
{
|
||||
fb_assert(att);
|
||||
fb_assert(optional || att);
|
||||
|
||||
if (att && att->att_use_count)
|
||||
{
|
||||
|
@ -200,7 +200,7 @@ Sort::Sort(Database* dbb,
|
||||
m_longs = record_size >> SHIFTLONG;
|
||||
|
||||
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_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
|
||||
m_size_memory = MAX_SORT_BUFFER_SIZE;
|
||||
m_memory = m_dbb->dbb_sort_buffers.pop();
|
||||
m_flags |= scb_reuse_buffer;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -635,6 +636,10 @@ void Sort::allocateBuffer(MemoryPool& pool)
|
||||
{
|
||||
m_size_memory = m_max_alloc_size;
|
||||
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&)
|
||||
{
|
||||
@ -646,6 +651,7 @@ void Sort::allocateBuffer(MemoryPool& pool)
|
||||
{
|
||||
m_size_memory /= 2;
|
||||
m_memory = FB_NEW_POOL(pool) UCHAR[m_size_memory];
|
||||
m_flags &= ~scb_reuse_buffer;
|
||||
break;
|
||||
}
|
||||
catch (const BadAlloc&)
|
||||
@ -666,13 +672,17 @@ void 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)
|
||||
{
|
||||
fb_assert(m_size_memory == MAX_SORT_BUFFER_SIZE);
|
||||
|
||||
m_dbb->dbb_sort_buffers.push(m_memory);
|
||||
}
|
||||
else
|
||||
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
|
||||
|
||||
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
|
||||
{
|
||||
|
@ -74,6 +74,7 @@
|
||||
#include "../utilities/nbackup/nbkswi.h"
|
||||
#include "../jrd/trace/traceswi.h"
|
||||
#include "../jrd/val_proto.h"
|
||||
#include "../jrd/ThreadCollect.h"
|
||||
|
||||
// Service threads
|
||||
#include "../burp/burp_proto.h"
|
||||
@ -120,6 +121,7 @@ int main_gstat(Firebird::UtilSvc* uSvc);
|
||||
|
||||
|
||||
using namespace Firebird;
|
||||
using namespace Jrd;
|
||||
|
||||
const int SVC_user_dba = 2;
|
||||
const int SVC_user_any = 1;
|
||||
@ -138,64 +140,9 @@ namespace {
|
||||
GlobalPtr<Mutex> globalServicesMutex;
|
||||
|
||||
// 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
|
||||
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;
|
||||
|
||||
void spbVersionError()
|
||||
@ -207,8 +154,6 @@ namespace {
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
using namespace Jrd;
|
||||
|
||||
namespace {
|
||||
const serv_entry services[] =
|
||||
{
|
||||
@ -1975,7 +1920,7 @@ THREAD_ENTRY_DECLARE Service::run(THREAD_ENTRY_PARAM arg)
|
||||
svc->unblockQueryGet();
|
||||
svc->finish(SVC_finished);
|
||||
|
||||
threadCollect->add(thrHandle);
|
||||
threadCollect->ending(thrHandle);
|
||||
}
|
||||
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;
|
||||
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;
|
||||
|
||||
if (security_name.isEmpty())
|
||||
{
|
||||
MET_scan_relation(tdbb, blb_relation);
|
||||
security_name = blb_relation->rel_security_name;
|
||||
}
|
||||
|
||||
SecurityClass* s_class = SCL_get_class(tdbb, security_name.c_str());
|
||||
|
||||
|
@ -88,6 +88,7 @@ TraceManager::TraceManager(Attachment* in_att) :
|
||||
attachment(in_att),
|
||||
service(NULL),
|
||||
filename(NULL),
|
||||
callback(NULL),
|
||||
trace_sessions(*in_att->att_pool),
|
||||
active(false)
|
||||
{
|
||||
@ -98,16 +99,18 @@ TraceManager::TraceManager(Service* in_svc) :
|
||||
attachment(NULL),
|
||||
service(in_svc),
|
||||
filename(NULL),
|
||||
callback(NULL),
|
||||
trace_sessions(in_svc->getPool()),
|
||||
active(true)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
TraceManager::TraceManager(const char* in_filename) :
|
||||
TraceManager::TraceManager(const char* in_filename, ICryptKeyCallback* cb) :
|
||||
attachment(NULL),
|
||||
service(NULL),
|
||||
filename(in_filename),
|
||||
callback(cb),
|
||||
trace_sessions(*getDefaultMemoryPool()),
|
||||
active(true)
|
||||
{
|
||||
@ -251,7 +254,8 @@ void TraceManager::update_session(const TraceSession& session)
|
||||
}
|
||||
|
||||
// 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)))
|
||||
{
|
||||
const char* curr_user = nullptr;
|
||||
@ -265,10 +269,11 @@ void TraceManager::update_session(const TraceSession& session)
|
||||
|
||||
if (attachment)
|
||||
{
|
||||
if ((!attachment->att_user) || (attachment->att_flags & ATT_mapping))
|
||||
if (attachment->att_flags & ATT_mapping)
|
||||
return;
|
||||
|
||||
curr_user = attachment->getUserName().c_str();
|
||||
if (attachment->att_user)
|
||||
curr_user = attachment->att_user->getUserName().c_str();
|
||||
|
||||
if (session.ses_auth.hasData())
|
||||
{
|
||||
@ -290,7 +295,7 @@ void TraceManager::update_session(const TraceSession& session)
|
||||
}
|
||||
else if (service)
|
||||
{
|
||||
curr_user = service->getUserName().c_str();
|
||||
curr_user = service->getUserName().nullStr();
|
||||
|
||||
if (session.ses_auth.hasData())
|
||||
{
|
||||
@ -308,6 +313,26 @@ void TraceManager::update_session(const TraceSession& session)
|
||||
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
|
||||
{
|
||||
// failed attachment attempts traced by admin trace only
|
||||
@ -327,7 +352,7 @@ void TraceManager::update_session(const TraceSession& session)
|
||||
|
||||
t_role.upper();
|
||||
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;
|
||||
}
|
||||
|
@ -39,6 +39,12 @@
|
||||
#include "../../jrd/trace/TraceConfigStorage.h"
|
||||
#include "../../jrd/trace/TraceSession.h"
|
||||
|
||||
namespace Firebird {
|
||||
|
||||
class ICryptKeyCallback;
|
||||
|
||||
}
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
class Database;
|
||||
@ -52,7 +58,7 @@ public:
|
||||
/* Initializes plugins. */
|
||||
explicit TraceManager(Attachment* in_att);
|
||||
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 */
|
||||
~TraceManager();
|
||||
@ -142,6 +148,12 @@ public:
|
||||
return active;
|
||||
}
|
||||
|
||||
// external access to stored attachment
|
||||
Attachment* getAttachment()
|
||||
{
|
||||
return attachment;
|
||||
}
|
||||
|
||||
/* DSQL-friendly routines to call Trace API hooks.
|
||||
Needed because DSQL cannot include JRD for the current engine */
|
||||
static bool need_dsql_prepare(Attachment* att);
|
||||
@ -163,6 +175,7 @@ private:
|
||||
Attachment* attachment;
|
||||
Service* service;
|
||||
const char* filename;
|
||||
Firebird::ICryptKeyCallback* callback;
|
||||
NotificationNeeds trace_needs, new_needs;
|
||||
|
||||
// This structure should be POD-like to be stored in Array
|
||||
|
@ -9,7 +9,7 @@ BuildType=T
|
||||
MajorVer=5
|
||||
MinorVer=0
|
||||
RevNo=0
|
||||
BuildNum=501
|
||||
BuildNum=516
|
||||
|
||||
NowAt=`pwd`
|
||||
cd `dirname $0`
|
||||
|
@ -66,6 +66,10 @@ public:
|
||||
void deprecatedDisconnect(CheckStatusWrapper* status);
|
||||
|
||||
private:
|
||||
void internalCommit(CheckStatusWrapper* status);
|
||||
void internalRollback(CheckStatusWrapper* status);
|
||||
void internalDisconnect(CheckStatusWrapper* status);
|
||||
|
||||
typedef HalfStaticArray<ITransaction*, 8> SubArray;
|
||||
typedef HalfStaticArray<UCHAR, 1024> TdrBuffer;
|
||||
SubArray sub;
|
||||
@ -248,7 +252,7 @@ void DTransaction::prepare(CheckStatusWrapper* status,
|
||||
}
|
||||
}
|
||||
|
||||
void DTransaction::commit(CheckStatusWrapper* status)
|
||||
void DTransaction::internalCommit(CheckStatusWrapper* status)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -309,7 +313,7 @@ void DTransaction::commitRetaining(CheckStatusWrapper* status)
|
||||
}
|
||||
}
|
||||
|
||||
void DTransaction::rollback(CheckStatusWrapper* status)
|
||||
void DTransaction::internalRollback(CheckStatusWrapper* status)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -361,7 +365,7 @@ void DTransaction::rollbackRetaining(CheckStatusWrapper* status)
|
||||
}
|
||||
}
|
||||
|
||||
void DTransaction::disconnect(CheckStatusWrapper* status)
|
||||
void DTransaction::internalDisconnect(CheckStatusWrapper* status)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -392,17 +396,38 @@ void DTransaction::disconnect(CheckStatusWrapper* status)
|
||||
|
||||
void DTransaction::deprecatedCommit(CheckStatusWrapper* status)
|
||||
{
|
||||
commit(status);
|
||||
internalCommit(status);
|
||||
}
|
||||
|
||||
void DTransaction::deprecatedRollback(CheckStatusWrapper* status)
|
||||
{
|
||||
rollback(status);
|
||||
internalRollback(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);
|
||||
|
||||
YTransaction* copy = FB_NEW YTransaction(this);
|
||||
// copy is created with zero handle
|
||||
copy->addRef();
|
||||
copy->addRef();
|
||||
next->addRef(); // We use NoIncr in YTransaction ctor
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user