8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 18:43:02 +01:00

Wipe out multi-file database support (#8047)

* Wipe out multi-file database support

* Fix (fingers crossed) Windows build, some more cleanup and code simplification

* Fix gstat build on Windows and also Android/MacOS builds
This commit is contained in:
Dmitry Yemanov 2024-12-28 09:27:34 +03:00 committed by GitHub
parent 125140103d
commit f0740d2a32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 384 additions and 1504 deletions

View File

@ -4204,9 +4204,9 @@ bool get_files(BurpGlobals* tdgbl)
att_type attribute; att_type attribute;
scan_attr_t scan_next_attr; scan_attr_t scan_next_attr;
STORE (REQUEST_HANDLE tdgbl->handles_get_files_req_handle1) BASED_ON RDB$FILES.RDB$FILE_NAME filename = "";
X IN RDB$FILES SSHORT flags = 0, sequence = 0, number = 0;
X.RDB$FILE_FLAGS = 0; SLONG start = 0, length = 0;
skip_init(&scan_next_attr); skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end) while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_end)
@ -4214,31 +4214,29 @@ bool get_files(BurpGlobals* tdgbl)
switch (attribute) switch (attribute)
{ {
case att_file_filename: case att_file_filename:
GET_TEXT(X.RDB$FILE_NAME); GET_TEXT(filename);
BURP_verbose (116, X.RDB$FILE_NAME);
// msg 116 restoring file %s
break; break;
case att_file_sequence: case att_file_sequence:
X.RDB$FILE_SEQUENCE = (USHORT) get_int32(tdgbl); sequence = (SSHORT) get_int32(tdgbl);
break; break;
case att_file_start: case att_file_start:
X.RDB$FILE_START = get_int32(tdgbl); start = get_int32(tdgbl);
break; break;
case att_file_length: case att_file_length:
X.RDB$FILE_LENGTH = get_int32(tdgbl); length = get_int32(tdgbl);
break; break;
case att_file_flags: case att_file_flags:
X.RDB$FILE_FLAGS |= get_int32(tdgbl); flags |= (SSHORT) get_int32(tdgbl);
break; break;
case att_shadow_number: case att_shadow_number:
X.RDB$SHADOW_NUMBER = (USHORT) get_int32(tdgbl); number = (SSHORT) get_int32(tdgbl);
if (tdgbl->gbl_sw_kill && X.RDB$SHADOW_NUMBER) if (tdgbl->gbl_sw_kill && number)
X.RDB$FILE_FLAGS |= FILE_inactive; flags |= FILE_inactive;
break; break;
default: default:
@ -4247,10 +4245,44 @@ bool get_files(BurpGlobals* tdgbl)
break; break;
} }
} }
const bool multiFileSupport = (tdgbl->runtimeODS <= DB_VERSION_DDL13_1);
if ((multiFileSupport || !sequence) && filename[0])
{
BURP_verbose (116, filename);
// msg 116 restoring file %s
STORE (REQUEST_HANDLE tdgbl->handles_get_files_req_handle1)
X IN RDB$FILES
strncpy(X.RDB$FILE_NAME, filename, sizeof(X.RDB$FILE_NAME));
X.RDB$FILE_FLAGS = flags;
X.RDB$SHADOW_NUMBER = number;
if (multiFileSupport)
{
X.RDB$FILE_SEQUENCE.NULL = FALSE;
X.RDB$FILE_SEQUENCE = sequence;
X.RDB$FILE_START.NULL = FALSE;
X.RDB$FILE_START = start;
X.RDB$FILE_LENGTH.NULL = FALSE;
X.RDB$FILE_LENGTH = length;
}
else
{
X.RDB$FILE_SEQUENCE.NULL = TRUE;
X.RDB$FILE_START.NULL = TRUE;
X.RDB$FILE_LENGTH.NULL = TRUE;
}
END_STORE; END_STORE;
ON_ERROR ON_ERROR
general_on_error (); general_on_error ();
END_ERROR; END_ERROR;
}
return true; return true;
} }

View File

@ -80,9 +80,6 @@ static void defineComputed(DsqlCompilerScratch* dsqlScratch, RelationSourceNode*
dsql_fld* field, ValueSourceClause* clause, string& source, BlrDebugWriter::BlrData& value); dsql_fld* field, ValueSourceClause* clause, string& source, BlrDebugWriter::BlrData& value);
static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction, static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction,
const MetaName& relationName, const MetaName& constraintName, const MetaName& indexName); const MetaName& relationName, const MetaName& constraintName, const MetaName& indexName);
static void defineFile(thread_db* tdbb, jrd_tra* transaction, SLONG shadowNumber, bool manualShadow,
bool conditionalShadow, SLONG& dbAlloc,
const PathName& name, SLONG start, SLONG length);
static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& relationName, static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& relationName,
const MetaName& fieldName); const MetaName& fieldName);
static bool isItSqlRole(thread_db* tdbb, jrd_tra* transaction, const MetaName& inputName, static bool isItSqlRole(thread_db* tdbb, jrd_tra* transaction, const MetaName& inputName,
@ -490,46 +487,6 @@ static void deleteKeyConstraint(thread_db* tdbb, jrd_tra* transaction,
} }
} }
// Define a database or shadow file.
static void defineFile(thread_db* tdbb, jrd_tra* transaction, SLONG shadowNumber, bool manualShadow,
bool conditionalShadow, SLONG& dbAlloc, const PathName& name, SLONG start, SLONG length)
{
PathName expandedName = name;
if (!ISC_expand_filename(expandedName, false))
status_exception::raise(Arg::PrivateDyn(231)); // File name is invalid.
if (tdbb->getDatabase()->dbb_filename == expandedName)
status_exception::raise(Arg::PrivateDyn(166));
AutoCacheRequest request(tdbb, drq_l_files, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
FIRST 1 X IN RDB$FILES
WITH X.RDB$FILE_NAME EQ expandedName.c_str()
{
status_exception::raise(Arg::PrivateDyn(166));
}
END_FOR
request.reset(tdbb, drq_s_files, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$FILES
{
expandedName.copyTo(X.RDB$FILE_NAME, sizeof(X.RDB$FILE_NAME));
X.RDB$SHADOW_NUMBER = shadowNumber;
X.RDB$FILE_FLAGS = (manualShadow ? FILE_manual : 0) |
(conditionalShadow ? FILE_conditional : 0);
dbAlloc = MAX(dbAlloc, start);
X.RDB$FILE_START = dbAlloc;
X.RDB$FILE_LENGTH = length;
dbAlloc += length;
}
END_STORE
}
// Checks to see if the given field already exists in a relation. // Checks to see if the given field already exists in a relation.
static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& relationName, static bool fieldExists(thread_db* tdbb, jrd_tra* transaction, const MetaName& relationName,
const MetaName& fieldName) const MetaName& fieldName)
@ -10462,7 +10419,7 @@ string CreateShadowNode::internalPrint(NodePrinter& printer) const
NODE_PRINT(printer, number); NODE_PRINT(printer, number);
NODE_PRINT(printer, manual); NODE_PRINT(printer, manual);
NODE_PRINT(printer, conditional); NODE_PRINT(printer, conditional);
NODE_PRINT(printer, files); NODE_PRINT(printer, fileName);
return "CreateShadowNode"; return "CreateShadowNode";
} }
@ -10486,7 +10443,7 @@ void CreateShadowNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScrat
// run all statements under savepoint control // run all statements under savepoint control
AutoSavePoint savePoint(tdbb, transaction); AutoSavePoint savePoint(tdbb, transaction);
// If a shadow set identified by the shadow number already exists return error. // If a shadow set identified by the shadow number already exists return error
AutoCacheRequest request(tdbb, drq_l_shadow, DYN_REQUESTS); AutoCacheRequest request(tdbb, drq_l_shadow, DYN_REQUESTS);
@ -10502,25 +10459,34 @@ void CreateShadowNode::execute(thread_db* tdbb, DsqlCompilerScratch* /*dsqlScrat
} }
END_FOR END_FOR
SLONG start = 0; PathName expandedName = fileName.ToPathName();
for (NestConst<DbFileClause>* i = files.begin(); i != files.end(); ++i) if (!ISC_expand_filename(expandedName, false))
status_exception::raise(Arg::PrivateDyn(231)); // File name is invalid
if (tdbb->getDatabase()->dbb_filename == expandedName)
status_exception::raise(Arg::PrivateDyn(166));
request.reset(tdbb, drq_l_files, DYN_REQUESTS);
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
FIRST 1 X IN RDB$FILES
WITH X.RDB$FILE_NAME EQ expandedName.c_str()
{ {
bool first = i == files.begin(); status_exception::raise(Arg::PrivateDyn(166));
DbFileClause* file = *i; }
END_FOR
if (!first && i[-1]->length == 0 && file->start == 0) request.reset(tdbb, drq_s_files, DYN_REQUESTS);
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE transaction)
X IN RDB$FILES
{ {
// Preceding file did not specify length, so %s must include starting page number expandedName.copyTo(X.RDB$FILE_NAME, sizeof(X.RDB$FILE_NAME));
status_exception::raise( X.RDB$SHADOW_NUMBER = number;
Arg::Gds(isc_sqlerr) << Arg::Num(-607) << X.RDB$FILE_FLAGS = (manual ? FILE_manual : 0) | (conditional ? FILE_conditional : 0);
Arg::Gds(isc_dsql_command_err) <<
Arg::Gds(isc_dsql_file_length_err) << file->name);
}
defineFile(tdbb, transaction, number, manual && first, conditional && first,
start, file->name.c_str(), file->start, file->length);
} }
END_STORE
savePoint.release(); // everything is ok savePoint.release(); // everything is ok
} }
@ -12742,13 +12708,11 @@ string AlterDatabaseNode::internalPrint(NodePrinter& printer) const
DdlNode::internalPrint(printer); DdlNode::internalPrint(printer);
NODE_PRINT(printer, create); NODE_PRINT(printer, create);
NODE_PRINT(printer, createLength);
NODE_PRINT(printer, linger); NODE_PRINT(printer, linger);
NODE_PRINT(printer, clauses); NODE_PRINT(printer, clauses);
NODE_PRINT(printer, differenceFile); NODE_PRINT(printer, differenceFile);
NODE_PRINT(printer, setDefaultCharSet); NODE_PRINT(printer, setDefaultCharSet);
NODE_PRINT(printer, setDefaultCollation); NODE_PRINT(printer, setDefaultCollation);
NODE_PRINT(printer, files);
NODE_PRINT(printer, cryptPlugin); NODE_PRINT(printer, cryptPlugin);
NODE_PRINT(printer, keyName); NODE_PRINT(printer, keyName);
@ -12924,18 +12888,6 @@ void AlterDatabaseNode::execute(thread_db* tdbb, DsqlCompilerScratch* dsqlScratc
} }
} }
SLONG dbAlloc = PageSpace::maxAlloc(tdbb->getDatabase());
SLONG start = create ? createLength + 1 : 0;
for (NestConst<DbFileClause>* i = files.begin(); i != files.end(); ++i)
{
DbFileClause* file = *i;
start = MAX(start, file->start);
defineFile(tdbb, transaction, 0, false, false, dbAlloc,
file->name.c_str(), start, file->length);
start += file->length;
}
if (differenceFile.hasData()) if (differenceFile.hasData())
defineDifference(tdbb, transaction, differenceFile.c_str()); defineDifference(tdbb, transaction, differenceFile.c_str());
@ -13064,7 +13016,6 @@ void AlterDatabaseNode::changeBackupMode(thread_db* tdbb, jrd_tra* transaction,
X IN RDB$FILES X IN RDB$FILES
{ {
X.RDB$FILE_FLAGS = FILE_difference | FILE_backing_up; X.RDB$FILE_FLAGS = FILE_difference | FILE_backing_up;
X.RDB$FILE_START = 0;
} }
END_STORE END_STORE
@ -13116,7 +13067,6 @@ void AlterDatabaseNode::defineDifference(thread_db* tdbb, jrd_tra* transaction,
strcpy(FIL.RDB$FILE_NAME, file.c_str()); strcpy(FIL.RDB$FILE_NAME, file.c_str());
FIL.RDB$FILE_FLAGS = FILE_difference; FIL.RDB$FILE_FLAGS = FILE_difference;
FIL.RDB$FILE_START = 0;
} }
END_STORE END_STORE
} }

View File

@ -101,40 +101,6 @@ public:
}; };
class DbFileClause : public Printable
{
public:
DbFileClause(MemoryPool& p, const DbFileClause& o)
: name(p, o.name),
start(o.start),
length(o.length)
{
}
explicit DbFileClause(MemoryPool& p, const Firebird::string& aName)
: name(p, aName),
start(0),
length(0)
{
}
public:
virtual Firebird::string internalPrint(NodePrinter& printer) const
{
NODE_PRINT(printer, name);
NODE_PRINT(printer, start);
NODE_PRINT(printer, length);
return "DbFileClause";
}
public:
Firebird::string name; // File name
SLONG start; // Starting page
SLONG length; // File length in pages
};
class ExternalClause : public Printable class ExternalClause : public Printable
{ {
public: public:
@ -1967,12 +1933,13 @@ public:
class CreateShadowNode : public DdlNode class CreateShadowNode : public DdlNode
{ {
public: public:
CreateShadowNode(MemoryPool& p, const SSHORT aNumber) CreateShadowNode(MemoryPool& p, SSHORT aNumber, bool aManual, bool aConditional,
const Firebird::string& aFileName)
: DdlNode(p), : DdlNode(p),
number(aNumber), number(aNumber),
manual(false), manual(aManual),
conditional(false), conditional(aConditional),
files(p) fileName(p, aFileName)
{ {
} }
@ -1996,7 +1963,7 @@ public:
SSHORT number; SSHORT number;
bool manual; bool manual;
bool conditional; bool conditional;
Firebird::Array<NestConst<DbFileClause> > files; Firebird::string fileName;
bool createIfNotExistsOnly = false; bool createIfNotExistsOnly = false;
}; };
@ -2425,14 +2392,9 @@ public:
public: public:
AlterDatabaseNode(MemoryPool& p) AlterDatabaseNode(MemoryPool& p)
: DdlNode(p), : DdlNode(p),
create(false),
createLength(0),
linger(-1),
clauses(0),
differenceFile(p), differenceFile(p),
setDefaultCharSet(p), setDefaultCharSet(p),
setDefaultCollation(p), setDefaultCollation(p),
files(p),
cryptPlugin(p), cryptPlugin(p),
keyName(p), keyName(p),
pubTables(p) pubTables(p)
@ -2468,13 +2430,12 @@ private:
void checkClauses(thread_db* tdbb); void checkClauses(thread_db* tdbb);
public: public:
bool create; // Is the node created with a CREATE DATABASE command? bool create = false; // Is the node created with a CREATE DATABASE command?
SLONG createLength, linger; SLONG linger = -1;
unsigned clauses; unsigned clauses = 0;
Firebird::string differenceFile; Firebird::string differenceFile;
MetaName setDefaultCharSet; MetaName setDefaultCharSet;
MetaName setDefaultCollation; MetaName setDefaultCollation;
Firebird::Array<NestConst<DbFileClause> > files;
MetaName cryptPlugin; MetaName cryptPlugin;
MetaName keyName; MetaName keyName;
Firebird::TriState ssDefiner; Firebird::TriState ssDefiner;

View File

@ -767,8 +767,6 @@ using namespace Firebird;
Firebird::string* stringPtr; Firebird::string* stringPtr;
Jrd::IntlString* intlStringPtr; Jrd::IntlString* intlStringPtr;
Jrd::Lim64String* lim64ptr; Jrd::Lim64String* lim64ptr;
Jrd::DbFileClause* dbFileClause;
Firebird::Array<NestConst<Jrd::DbFileClause> >* dbFilesClause;
Jrd::ExternalClause* externalClause; Jrd::ExternalClause* externalClause;
Firebird::NonPooledPair<Jrd::MetaName*, Jrd::ValueExprNode*>* namedArgument; Firebird::NonPooledPair<Jrd::MetaName*, Jrd::ValueExprNode*>* namedArgument;
Firebird::NonPooledPair<Firebird::ObjectsArray<Jrd::MetaName>*, Jrd::ValueListNode*>* namedArguments; Firebird::NonPooledPair<Firebird::ObjectsArray<Jrd::MetaName>*, Jrd::ValueListNode*>* namedArguments;
@ -1807,16 +1805,8 @@ index_condition_opt
// CREATE SHADOW // CREATE SHADOW
%type <createShadowNode> shadow_clause %type <createShadowNode> shadow_clause
shadow_clause shadow_clause
: pos_short_integer manual_auto conditional utf_string first_file_length : pos_short_integer manual_auto conditional utf_string
{ { $$ = newNode<CreateShadowNode>($1, $2, $3, *$4); }
$$ = newNode<CreateShadowNode>($1);
$$->manual = $2;
$$->conditional = $3;
$$->files.add(newNode<DbFileClause>(*$4));
$$->files.front()->length = $5;
}
sec_shadow_files(NOTRIAL(&$6->files))
{ $$ = $6; }
; ;
%type <boolVal> manual_auto %type <boolVal> manual_auto
@ -1832,24 +1822,6 @@ conditional
| CONDITIONAL { $$ = true; } | CONDITIONAL { $$ = true; }
; ;
%type <int32Val> first_file_length
first_file_length
: /* nothing */ { $$ = 0; }
| LENGTH equals long_integer page_noise { $$ = $3; }
;
%type sec_shadow_files(<dbFilesClause>)
sec_shadow_files($dbFilesClause)
: // nothing
| db_file_list($dbFilesClause)
;
%type db_file_list(<dbFilesClause>)
db_file_list($dbFilesClause)
: db_file { $dbFilesClause->add($1); }
| db_file_list db_file { $dbFilesClause->add($2); }
;
// CREATE DOMAIN // CREATE DOMAIN
@ -2279,8 +2251,6 @@ db_initial_option($alterDatabaseNode)
| ROLE utf_string | ROLE utf_string
| PASSWORD utf_string | PASSWORD utf_string
| SET NAMES utf_string | SET NAMES utf_string
| LENGTH equals long_integer page_noise
{ $alterDatabaseNode->createLength = $3; }
; ;
%type db_rem_desc1(<alterDatabaseNode>) %type db_rem_desc1(<alterDatabaseNode>)
@ -2297,9 +2267,7 @@ db_rem_desc($alterDatabaseNode)
%type db_rem_option(<alterDatabaseNode>) %type db_rem_option(<alterDatabaseNode>)
db_rem_option($alterDatabaseNode) db_rem_option($alterDatabaseNode)
: db_file : DEFAULT CHARACTER SET symbol_character_set_name
{ $alterDatabaseNode->files.add($1); }
| DEFAULT CHARACTER SET symbol_character_set_name
{ $alterDatabaseNode->setDefaultCharSet = *$4; } { $alterDatabaseNode->setDefaultCharSet = *$4; }
| DEFAULT CHARACTER SET symbol_character_set_name COLLATION symbol_collation_name | DEFAULT CHARACTER SET symbol_character_set_name COLLATION symbol_collation_name
{ {
@ -2310,49 +2278,6 @@ db_rem_option($alterDatabaseNode)
{ $alterDatabaseNode->differenceFile = *$3; } { $alterDatabaseNode->differenceFile = *$3; }
; ;
%type <dbFileClause> db_file
db_file
: FILE utf_string
{
DbFileClause* clause = newNode<DbFileClause>(*$2);
$$ = clause;
}
file_desc1($3)
{ $$ = $3; }
;
%type file_desc1(<dbFileClause>)
file_desc1($dbFileClause)
: // nothing
| file_desc($dbFileClause)
;
%type file_desc(<dbFileClause>)
file_desc($dbFileClause)
: file_clause($dbFileClause)
| file_desc file_clause($dbFileClause)
;
%type file_clause(<dbFileClause>)
file_clause($dbFileClause)
: STARTING file_clause_noise long_integer
{ $dbFileClause->start = $3; }
| LENGTH equals long_integer page_noise
{ $dbFileClause->length = $3; }
;
file_clause_noise
: // nothing
| AT
| AT PAGE
;
page_noise
: // nothing
| PAGE
| PAGES
;
// CREATE TABLE // CREATE TABLE
@ -4770,8 +4695,7 @@ alter_db($alterDatabaseNode)
%type db_alter_clause(<alterDatabaseNode>) %type db_alter_clause(<alterDatabaseNode>)
db_alter_clause($alterDatabaseNode) db_alter_clause($alterDatabaseNode)
: ADD db_file_list(NOTRIAL(&$alterDatabaseNode->files)) : ADD DIFFERENCE FILE utf_string
| ADD DIFFERENCE FILE utf_string
{ $alterDatabaseNode->differenceFile = *$4; } { $alterDatabaseNode->differenceFile = *$4; }
| DROP DIFFERENCE FILE | DROP DIFFERENCE FILE
{ $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_DROP_DIFFERENCE; } { $alterDatabaseNode->clauses |= AlterDatabaseNode::CLAUSE_DROP_DIFFERENCE; }

View File

@ -2489,15 +2489,6 @@ bool CCH_write_all_shadows(thread_db* tdbb, Shadow* shadow, BufferDesc* bdb, Ods
PAG_add_header_entry(tdbb, header, HDR_root_file_name, PAG_add_header_entry(tdbb, header, HDR_root_file_name,
(USHORT) strlen((const char*) q), q); (USHORT) strlen((const char*) q), q);
jrd_file* next_file = shadow_file->fil_next;
if (next_file)
{
q = (UCHAR *) next_file->fil_string;
const SLONG last = next_file->fil_min_page - 1;
PAG_add_header_entry(tdbb, header, HDR_file, (USHORT) strlen((const char*) q), q);
PAG_add_header_entry(tdbb, header, HDR_last_page, sizeof(last), (const UCHAR*) &last);
}
header->hdr_flags |= hdr_active_shadow; header->hdr_flags |= hdr_active_shadow;
header->hdr_header.pag_pageno = bdb->bdb_page.getPageNum(); header->hdr_header.pag_pageno = bdb->bdb_page.getPageNum();
} }

View File

@ -56,7 +56,7 @@
* BUGCHECK(291) took place. To avoid that issue, it was decided not to modify data * BUGCHECK(291) took place. To avoid that issue, it was decided not to modify data
* in system transaction. An exception is RDB$FORMATS relation, which is always modified * in system transaction. An exception is RDB$FORMATS relation, which is always modified
* by transaction zero. Also an aspect of 'dirty' access from system transaction was * by transaction zero. Also an aspect of 'dirty' access from system transaction was
* taken into an account in add_file(), make_version() and create_index(). * taken into an account in make_version() and create_index().
* *
*/ */
@ -449,7 +449,6 @@ private:
* *
*================================================================== *==================================================================
*/ */
static bool add_file(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool add_shadow(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool add_shadow(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool delete_shadow(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool delete_shadow(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
static bool compute_security(thread_db*, SSHORT, DeferredWork*, jrd_tra*); static bool compute_security(thread_db*, SSHORT, DeferredWork*, jrd_tra*);
@ -1272,7 +1271,6 @@ namespace
static const deferred_task task_table[] = static const deferred_task task_table[] =
{ {
{ dfw_add_file, add_file },
{ dfw_add_shadow, add_shadow }, { dfw_add_shadow, add_shadow },
{ dfw_delete_index, modify_index }, { dfw_delete_index, modify_index },
{ dfw_delete_rfr, delete_rfr }, { dfw_delete_rfr, delete_rfr },
@ -1876,133 +1874,6 @@ void DFW_update_index(const TEXT* name, USHORT id, const SelectivityList& select
} }
static bool add_file(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction)
{
/**************************************
*
* a d d _ f i l e
*
**************************************
*
* Functional description
* Add a file to a database.
* This file could be a regular database
* file or a shadow file. Either way we
* require exclusive access to the database.
*
**************************************/
USHORT section, shadow_number;
SLONG start, min_start;
SET_TDBB(tdbb);
Database* const dbb = tdbb->getDatabase();
switch (phase)
{
case 0:
CCH_release_exclusive(tdbb);
return false;
case 1:
case 2:
return true;
case 3:
if (!CCH_exclusive(tdbb, LCK_EX, WAIT_PERIOD, NULL))
raiseDatabaseInUseError(true);
return true;
case 4:
CCH_flush(tdbb, FLUSH_FINI, 0);
start = PageSpace::maxAlloc(dbb) + 1;
AutoRequest handle;
AutoRequest handle2;
// Check the file name for node name. This has already
// been done for shadows in add_shadow()
if (work->dfw_type != dfw_add_shadow) {
check_filename(work->dfw_name, true);
}
// User transaction may be safely used instead of system, cause
// we requested and got exclusive database access. AP-2008.
// get any files to extend into
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$FILES
WITH X.RDB$FILE_NAME EQ work->dfw_name.c_str()
// First expand the file name This has already been done
// for shadows in add_shadow ())
if (work->dfw_type != dfw_add_shadow)
{
MODIFY X USING
ISC_expand_filename(X.RDB$FILE_NAME, 0,
X.RDB$FILE_NAME, sizeof(X.RDB$FILE_NAME), false);
END_MODIFY
}
// Check the previous file length
FOR(REQUEST_HANDLE handle2 TRANSACTION_HANDLE transaction)
FIRST 1 Y IN RDB$FILES
WITH Y.RDB$SHADOW_NUMBER EQ X.RDB$SHADOW_NUMBER
AND Y.RDB$FILE_SEQUENCE NOT MISSING
SORTED BY DESCENDING Y.RDB$FILE_SEQUENCE
{
if (!Y.RDB$FILE_START.NULL && !Y.RDB$FILE_LENGTH.NULL)
{
min_start = Y.RDB$FILE_START + (Y.RDB$FILE_LENGTH ? Y.RDB$FILE_LENGTH : 1);
start = MAX(min_start, start);
}
}
END_FOR
// If there is no starting position specified, or if it is
// too low a value, raise the error.
if (X.RDB$FILE_START < start)
{
ERR_post(Arg::Gds(isc_file_starting_page_err) <<
Arg::Str(X.RDB$FILE_NAME) << Arg::Num(start));
}
start = X.RDB$FILE_START;
shadow_number = X.RDB$SHADOW_NUMBER;
if ((shadow_number &&
(section = SDW_add_file(tdbb, X.RDB$FILE_NAME, start, shadow_number))) ||
(section = PAG_add_file(tdbb, X.RDB$FILE_NAME, start)))
{
MODIFY X USING
X.RDB$FILE_SEQUENCE = section;
X.RDB$FILE_START = start;
END_MODIFY
}
END_FOR
if (section)
{
handle.reset();
section--;
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) X IN RDB$FILES
WITH X.RDB$FILE_SEQUENCE EQ section
AND X.RDB$SHADOW_NUMBER EQ shadow_number
{
MODIFY X USING
X.RDB$FILE_LENGTH = start - X.RDB$FILE_START;
END_MODIFY
}
END_FOR
}
CCH_release_exclusive(tdbb);
break;
}
return false;
}
static bool add_shadow(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction) static bool add_shadow(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tra* transaction)
{ {
/************************************** /**************************************
@ -2053,11 +1924,11 @@ static bool add_shadow(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr
finished = false; finished = false;
handle.reset(); handle.reset();
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction)
F IN RDB$FILES F IN RDB$FILES WITH F.RDB$FILE_NAME EQ work->dfw_name.c_str()
WITH F.RDB$FILE_NAME EQ work->dfw_name.c_str() {
expanded_fname = F.RDB$FILE_NAME; expanded_fname = F.RDB$FILE_NAME;
ISC_expand_filename(expanded_fname, false); ISC_expand_filename(expanded_fname, false);
MODIFY F USING MODIFY F USING
expanded_fname.copyTo(F.RDB$FILE_NAME, sizeof(F.RDB$FILE_NAME)); expanded_fname.copyTo(F.RDB$FILE_NAME, sizeof(F.RDB$FILE_NAME));
END_MODIFY END_MODIFY
@ -2066,94 +1937,34 @@ static bool add_shadow(thread_db* tdbb, SSHORT phase, DeferredWork* work, jrd_tr
{ {
if ((F.RDB$SHADOW_NUMBER == shadow->sdw_number) && !(shadow->sdw_flags & SDW_IGNORE)) if ((F.RDB$SHADOW_NUMBER == shadow->sdw_number) && !(shadow->sdw_flags & SDW_IGNORE))
{ {
if (F.RDB$FILE_FLAGS & FILE_shadow) if (!(F.RDB$FILE_FLAGS & FILE_shadow))
{
// This is the case of a bogus duplicate posted
// work when we added a multi-file shadow
finished = true;
}
else if (shadow->sdw_flags & (SDW_dumped))
{
/* Case of adding a file to a currently active
* shadow set.
* Note: as of 1995-January-31 there is
* no SQL syntax that supports this, but there
* may be GDML
*/
add_file(tdbb, 3, work, transaction);
add_file(tdbb, 4, work, transaction);
finished = true;
}
else
{ {
// We cannot add a file to a shadow that is still // We cannot add a file to a shadow that is still
// in the process of being created. // in the process of being created.
raiseDatabaseInUseError(false); raiseDatabaseInUseError(false);
} }
// This is the case of a bogus duplicate posted
// work when we added a multi-file shadow
finished = true;
break; break;
} }
} }
}
END_FOR END_FOR
if (finished) if (finished)
return false; return false;
// this file is part of a new shadow, so get all files for the shadow
// in order of the starting page for the file
// Note that for a multi-file shadow, we have several pieces of
// work posted (one dfw_add_shadow for each file). Rather than
// trying to cancel the other pieces of work we ignore them
// when they arrive in this routine.
sequence = 0;
min_page = 0;
shadow = NULL;
handle.reset(); handle.reset();
FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction) FOR(REQUEST_HANDLE handle TRANSACTION_HANDLE transaction)
X IN RDB$FILES CROSS F IN RDB$FILES WITH F.RDB$FILE_NAME EQ expanded_fname.c_str()
Y IN RDB$FILES
OVER RDB$SHADOW_NUMBER
WITH X.RDB$FILE_NAME EQ expanded_fname.c_str()
SORTED BY Y.RDB$FILE_START
{ {
// for the first file, create a brand new shadow; for secondary SDW_add(tdbb, F.RDB$FILE_NAME, F.RDB$SHADOW_NUMBER, F.RDB$FILE_FLAGS);
// files that have a starting page specified, add a file
if (!sequence)
SDW_add(tdbb, Y.RDB$FILE_NAME, Y.RDB$SHADOW_NUMBER, Y.RDB$FILE_FLAGS);
else if (Y.RDB$FILE_START)
{
if (!shadow)
{
for (shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next)
{
if ((Y.RDB$SHADOW_NUMBER == shadow->sdw_number) &&
!(shadow->sdw_flags & SDW_IGNORE))
{
break;
}
}
}
if (!shadow) MODIFY F
BUGCHECK(203); // msg 203 shadow block not found for extend file F.RDB$FILE_FLAGS |= FILE_shadow;
min_page = MAX((min_page + 1), (ULONG) Y.RDB$FILE_START);
add_sequence = SDW_add_file(tdbb, Y.RDB$FILE_NAME, min_page, Y.RDB$SHADOW_NUMBER);
}
// update the sequence number and bless the file entry as being good
if (!sequence || (Y.RDB$FILE_START && add_sequence))
{
MODIFY Y
Y.RDB$FILE_FLAGS |= FILE_shadow;
Y.RDB$FILE_SEQUENCE = sequence;
Y.RDB$FILE_START = min_page;
END_MODIFY END_MODIFY
sequence++;
}
} }
END_FOR END_FOR

View File

@ -1301,7 +1301,7 @@ private:
static void check_database(thread_db* tdbb, bool async = false); static void check_database(thread_db* tdbb, bool async = false);
static void commit(thread_db*, jrd_tra*, const bool); static void commit(thread_db*, jrd_tra*, const bool);
static bool drop_files(const jrd_file*); static bool drop_file(Database*, const jrd_file*);
static void find_intl_charset(thread_db*, Jrd::Attachment*, const DatabaseOptions*); static void find_intl_charset(thread_db*, Jrd::Attachment*, const DatabaseOptions*);
static void init_database_lock(thread_db*); static void init_database_lock(thread_db*);
static void run_commit_triggers(thread_db* tdbb, jrd_tra* transaction); static void run_commit_triggers(thread_db* tdbb, jrd_tra* transaction);
@ -1831,7 +1831,7 @@ JAttachment* JProvider::internalAttach(CheckStatusWrapper* user_status, const ch
dbb->dbb_crypto_manager = FB_NEW_POOL(*dbb->dbb_permanent) CryptoManager(tdbb); dbb->dbb_crypto_manager = FB_NEW_POOL(*dbb->dbb_permanent) CryptoManager(tdbb);
dbb->dbb_monitoring_data = FB_NEW_POOL(*dbb->dbb_permanent) MonitoringData(dbb); dbb->dbb_monitoring_data = FB_NEW_POOL(*dbb->dbb_permanent) MonitoringData(dbb);
PAG_init2(tdbb, 0); PAG_init2(tdbb);
PAG_header(tdbb, false, newForceWrite); PAG_header(tdbb, false, newForceWrite);
dbb->dbb_page_manager.initTempPageSpace(tdbb); dbb->dbb_page_manager.initTempPageSpace(tdbb);
dbb->dbb_crypto_manager->attach(tdbb, attachment); dbb->dbb_crypto_manager->attach(tdbb, attachment);
@ -3552,11 +3552,9 @@ void JAttachment::internalDropDatabase(CheckStatusWrapper* user_status)
// This point on database is useless // This point on database is useless
// drop the files here // drop the files here
bool err = drop_files(file); bool err = drop_file(dbb, file);
for (; shadow; shadow = shadow->sdw_next) for (; shadow; shadow = shadow->sdw_next)
{ err = drop_file(dbb, shadow->sdw_file) || err;
err = drop_files(shadow->sdw_file) || err;
}
tdbb->setDatabase(NULL); tdbb->setDatabase(NULL);
Database::destroy(dbb); Database::destroy(dbb);
@ -6797,32 +6795,29 @@ static void commit(thread_db* tdbb, jrd_tra* transaction, const bool retaining_f
} }
static bool drop_files(const jrd_file* file) static bool drop_file(Database* dbb, const jrd_file* file)
{ {
/************************************** /**************************************
* *
* d r o p _ f i l e s * d r o p _ f i l e
* *
************************************** **************************************
* *
* Functional description * Functional description
* drop a linked list of files * Drop a file.
* *
**************************************/ **************************************/
FbLocalStatus status; FbLocalStatus status;
for (; file; file = file->fil_next)
{
if (unlink(file->fil_string)) if (unlink(file->fil_string))
{ {
ERR_build_status(&status, Arg::Gds(isc_io_error) << Arg::Str("unlink") << ERR_build_status(&status, Arg::Gds(isc_io_error) << Arg::Str("unlink") <<
Arg::Str(file->fil_string) << Arg::Str(file->fil_string) <<
Arg::Gds(isc_io_delete_err) << SYS_ERR(errno)); Arg::Gds(isc_io_delete_err) << SYS_ERR(errno));
Database* dbb = GET_DBB();
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
iscDbLogStatus(pageSpace->file->fil_string, &status); iscDbLogStatus(pageSpace->file->fil_string, &status);
} }
}
return status->getState() & IStatus::STATE_ERRORS ? true : false; return status->getState() & IStatus::STATE_ERRORS ? true : false;
} }

View File

@ -1782,7 +1782,6 @@ void MET_get_shadow_files(thread_db* tdbb, bool delete_files)
FOR(REQUEST_HANDLE handle) X IN RDB$FILES FOR(REQUEST_HANDLE handle) X IN RDB$FILES
WITH X.RDB$SHADOW_NUMBER NOT MISSING WITH X.RDB$SHADOW_NUMBER NOT MISSING
AND X.RDB$SHADOW_NUMBER NE 0 AND X.RDB$SHADOW_NUMBER NE 0
AND X.RDB$FILE_SEQUENCE EQ 0
{ {
if ((X.RDB$FILE_FLAGS & FILE_shadow) && !(X.RDB$FILE_FLAGS & FILE_inactive)) if ((X.RDB$FILE_FLAGS & FILE_shadow) && !(X.RDB$FILE_FLAGS & FILE_inactive))
{ {

View File

@ -531,8 +531,8 @@ static_assert(offsetof(struct header_page, hdr_data) == 128, "hdr_data offset mi
inline constexpr UCHAR HDR_end = 0; inline constexpr UCHAR HDR_end = 0;
inline constexpr UCHAR HDR_root_file_name = 1; // Original name of root file inline constexpr UCHAR HDR_root_file_name = 1; // Original name of root file
inline constexpr UCHAR HDR_file = 2; // Secondary file //inline constexpr UCHAR HDR_file = 2; // Secondary file
inline constexpr UCHAR HDR_last_page = 3; // Last logical page number of file //inline constexpr UCHAR HDR_last_page = 3; // Last logical page number of file
inline constexpr UCHAR HDR_sweep_interval = 4; // Transactions between sweeps inline constexpr UCHAR HDR_sweep_interval = 4; // Transactions between sweeps
inline constexpr UCHAR HDR_crypt_checksum = 5; // Checksum of critical crypt parameters inline constexpr UCHAR HDR_crypt_checksum = 5; // Checksum of critical crypt parameters
inline constexpr UCHAR HDR_difference_file = 6; // Delta file that is used during backup lock inline constexpr UCHAR HDR_difference_file = 6; // Delta file that is used during backup lock

View File

@ -41,11 +41,6 @@ namespace Jrd {
class jrd_file : public pool_alloc_rpt<SCHAR, type_fil> class jrd_file : public pool_alloc_rpt<SCHAR, type_fil>
{ {
public: public:
jrd_file* fil_next; // Next file in database
ULONG fil_min_page; // Minimum page number in file
ULONG fil_max_page; // Maximum page number in file
USHORT fil_sequence; // Sequence number of file
USHORT fil_fudge; // Fudge factor for page relocation
int fil_desc; int fil_desc;
Firebird::Mutex fil_mutex; Firebird::Mutex fil_mutex;
USHORT fil_flags; USHORT fil_flags;
@ -69,11 +64,6 @@ public:
delete fil_ext_lock; delete fil_ext_lock;
} }
jrd_file* fil_next; // Next file in database
ULONG fil_min_page; // Minimum page number in file
ULONG fil_max_page; // Maximum page number in file
USHORT fil_sequence; // Sequence number of file
USHORT fil_fudge; // Fudge factor for page relocation
HANDLE fil_desc; // File descriptor HANDLE fil_desc; // File descriptor
Firebird::RWLock* fil_ext_lock; // file extend lock Firebird::RWLock* fil_ext_lock; // file extend lock
USHORT fil_flags; USHORT fil_flags;

View File

@ -36,7 +36,6 @@ namespace Ods {
struct pag; struct pag;
} }
int PIO_add_file(Jrd::thread_db*, Jrd::jrd_file*, const Firebird::PathName&, SLONG);
void PIO_close(Jrd::jrd_file*); void PIO_close(Jrd::jrd_file*);
Jrd::jrd_file* PIO_create(Jrd::thread_db*, const Firebird::PathName&, Jrd::jrd_file* PIO_create(Jrd::thread_db*, const Firebird::PathName&,
const bool, const bool); const bool, const bool);

View File

@ -132,7 +132,7 @@ using namespace Firebird;
static const mode_t MASK = 0660; static const mode_t MASK = 0660;
static jrd_file* seek_file(jrd_file*, BufferDesc*, FB_UINT64*, FbStatusVector*); static bool seek_file(jrd_file*, BufferDesc*, FB_UINT64*, FbStatusVector*);
static jrd_file* setup_file(Database*, const PathName&, int, USHORT); static jrd_file* setup_file(Database*, const PathName&, int, USHORT);
static void lockDatabaseFile(int& desc, const bool shareMode, const bool temporary, static void lockDatabaseFile(int& desc, const bool shareMode, const bool temporary,
const char* fileName, ISC_STATUS operation); const char* fileName, ISC_STATUS operation);
@ -149,42 +149,8 @@ static int raw_devices_unlink_database (const PathName&);
static int openFile(const Firebird::PathName&, const bool, const bool, const bool); static int openFile(const Firebird::PathName&, const bool, const bool, const bool);
static void maybeCloseFile(int&); static void maybeCloseFile(int&);
int PIO_add_file(thread_db* tdbb, jrd_file* main_file, const PathName& file_name, SLONG start)
{
/**************************************
*
* P I O _ a d d _ f i l e
*
**************************************
*
* Functional description
* Add a file to an existing database. Return the sequence
* number of the new file. If anything goes wrong, return a
* sequence of 0.
* NOTE: This routine does not lock any mutexes on
* its own behalf. It is assumed that mutexes will
* have been locked before entry.
*
**************************************/
jrd_file* new_file = PIO_create(tdbb, file_name, false, false);
if (!new_file)
return 0;
new_file->fil_min_page = start; void PIO_close(jrd_file* file)
USHORT sequence = 1;
jrd_file* file;
for (file = main_file; file->fil_next; file = file->fil_next)
++sequence;
file->fil_max_page = start - 1;
file->fil_next = new_file;
return sequence;
}
void PIO_close(jrd_file* main_file)
{ {
/************************************** /**************************************
* *
@ -199,14 +165,11 @@ void PIO_close(jrd_file* main_file)
* *
**************************************/ **************************************/
for (jrd_file* file = main_file; file; file = file->fil_next)
{
if (file->fil_desc && file->fil_desc != -1) if (file->fil_desc && file->fil_desc != -1)
{ {
close(file->fil_desc); close(file->fil_desc);
file->fil_desc = -1; file->fil_desc = -1;
} }
}
} }
@ -336,7 +299,7 @@ bool PIO_expand(const TEXT* file_name, USHORT file_length, TEXT* expanded_name,
} }
void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, const USHORT pageSize) void PIO_extend(thread_db* tdbb, jrd_file* file, const ULONG extPages, const USHORT pageSize)
{ {
/************************************** /**************************************
* *
@ -348,23 +311,17 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons
* Extend file by extPages pages of pageSize size. * Extend file by extPages pages of pageSize size.
* *
**************************************/ **************************************/
fb_assert(extPages);
#if defined(HAVE_LINUX_FALLOC_H) && defined(HAVE_FALLOCATE) #if defined(HAVE_LINUX_FALLOC_H) && defined(HAVE_FALLOCATE)
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY); EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
ULONG leftPages = extPages;
for (jrd_file* file = main_file; file && leftPages; file = file->fil_next)
{
const ULONG filePages = PIO_get_number_of_pages(file, pageSize);
const ULONG fileMaxPages = (file->fil_max_page == MAX_ULONG) ?
MAX_ULONG : file->fil_max_page - file->fil_min_page + 1;
if (filePages < fileMaxPages)
{
if (file->fil_flags & FIL_no_fast_extend) if (file->fil_flags & FIL_no_fast_extend)
return; return;
const ULONG extendBy = MIN(fileMaxPages - filePages + file->fil_fudge, leftPages); const ULONG filePages = PIO_get_number_of_pages(file, pageSize);
const ULONG extendBy = MIN(MAX_ULONG - filePages, extPages);
int r; int r;
for (r = 0; r < IO_RETRY; r++) for (r = 0; r < IO_RETRY; r++)
@ -392,12 +349,8 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons
#endif #endif
unix_error("fallocate_retry", file, isc_io_write_err); unix_error("fallocate_retry", file, isc_io_write_err);
} }
leftPages -= extendBy;
}
}
#else #else
main_file->fil_flags |= FIL_no_fast_extend; file->fil_flags |= FIL_no_fast_extend;
#endif // fallocate present #endif // fallocate present
// not implemented // not implemented
@ -405,7 +358,7 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons
} }
void PIO_flush(thread_db* tdbb, jrd_file* main_file) void PIO_flush(thread_db* tdbb, jrd_file* file)
{ {
/************************************** /**************************************
* *
@ -422,16 +375,13 @@ void PIO_flush(thread_db* tdbb, jrd_file* main_file)
#ifndef SUPERSERVER_V2 #ifndef SUPERSERVER_V2
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY); EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
MutexLockGuard guard(main_file->fil_mutex, FB_FUNCTION); MutexLockGuard guard(file->fil_mutex, FB_FUNCTION);
for (jrd_file* file = main_file; file; file = file->fil_next)
{
if (file->fil_desc != -1) if (file->fil_desc != -1)
{ {
// This really should be an error // This really should be an error
fsync(file->fil_desc); fsync(file->fil_desc);
} }
}
#endif #endif
} }
@ -615,7 +565,7 @@ void PIO_header(thread_db* tdbb, UCHAR* address, int length)
static Firebird::InitInstance<ZeroBuffer> zeros; static Firebird::InitInstance<ZeroBuffer> zeros;
USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* status_vector, USHORT PIO_init_data(thread_db* tdbb, jrd_file* file, FbStatusVector* status_vector,
ULONG startPage, USHORT initPages) ULONG startPage, USHORT initPages)
{ {
/************************************** /**************************************
@ -642,16 +592,14 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY); EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
jrd_file* file = seek_file(main_file, &bdb, &offset, status_vector); if (!seek_file(file, &bdb, &offset, status_vector))
if (!file)
return 0; return 0;
if (file->fil_min_page + 8 > startPage) if (startPage < 8)
return 0; return 0;
USHORT leftPages = initPages; USHORT leftPages = initPages;
const ULONG initBy = MIN(file->fil_max_page - startPage, leftPages); const ULONG initBy = MIN(MAX_ULONG - startPage, leftPages);
if (initBy < leftPages) if (initBy < leftPages)
leftPages = initBy; leftPages = initBy;
@ -667,15 +615,16 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
for (int r = 0; r < IO_RETRY; r++) for (int r = 0; r < IO_RETRY; r++)
{ {
if (!(file = seek_file(file, &bdb, &offset, status_vector))) if (!seek_file(file, &bdb, &offset, status_vector))
return false; return 0;
if ((written = os_utils::pwrite(file->fil_desc, zero_buff, to_write, LSEEK_OFFSET_CAST offset)) == to_write) if ((written = os_utils::pwrite(file->fil_desc, zero_buff, to_write, LSEEK_OFFSET_CAST offset)) == to_write)
break; break;
if (written < 0 && !SYSCALL_INTERRUPTED(errno)) if (written < 0 && !SYSCALL_INTERRUPTED(errno))
return unix_error("write", file, isc_io_write_err, status_vector); return unix_error("write", file, isc_io_write_err, status_vector);
} }
leftPages -= write_pages; leftPages -= write_pages;
i += write_pages; i += write_pages;
} }
@ -812,7 +761,7 @@ bool PIO_read(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
for (i = 0; i < IO_RETRY; i++) for (i = 0; i < IO_RETRY; i++)
{ {
if (!(file = seek_file(file, bdb, &offset, status_vector))) if (!seek_file(file, bdb, &offset, status_vector))
return false; return false;
if ((bytes = os_utils::pread(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size) if ((bytes = os_utils::pread(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size)
@ -864,7 +813,7 @@ bool PIO_write(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
for (i = 0; i < IO_RETRY; i++) for (i = 0; i < IO_RETRY; i++)
{ {
if (!(file = seek_file(file, bdb, &offset, status_vector))) if (!seek_file(file, bdb, &offset, status_vector))
return false; return false;
if ((bytes = os_utils::pwrite(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size) if ((bytes = os_utils::pwrite(file->fil_desc, page, size, LSEEK_OFFSET_CAST offset)) == size)
@ -881,7 +830,7 @@ bool PIO_write(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
} }
static jrd_file* seek_file(jrd_file* file, BufferDesc* bdb, FB_UINT64* offset, static bool seek_file(jrd_file* file, BufferDesc* bdb, FB_UINT64* offset,
FbStatusVector* status_vector) FbStatusVector* status_vector)
{ {
/************************************** /**************************************
@ -891,43 +840,29 @@ static jrd_file* seek_file(jrd_file* file, BufferDesc* bdb, FB_UINT64* offset,
************************************** **************************************
* *
* Functional description * Functional description
* Given a buffer descriptor block, find the appropriate * Given a buffer descriptor block, seek to the proper page in that file.
* file block and seek to the proper page in that file.
* *
**************************************/ **************************************/
BufferControl* bcb = bdb->bdb_bcb; BufferControl* const bcb = bdb->bdb_bcb;
Database* dbb = bcb->bcb_database; const ULONG page = bdb->bdb_page.getPageNum();
ULONG page = bdb->bdb_page.getPageNum();
for (;; file = file->fil_next)
{
if (!file) {
CORRUPT(158); // msg 158 database file not available
}
else if (page >= file->fil_min_page && page <= file->fil_max_page)
break;
}
if (file->fil_desc == -1) if (file->fil_desc == -1)
{ {
unix_error("lseek", file, isc_io_access_err, status_vector); unix_error("lseek", file, isc_io_access_err, status_vector);
return 0; return false;
} }
page -= file->fil_min_page - file->fil_fudge;
FB_UINT64 lseek_offset = page; FB_UINT64 lseek_offset = page;
lseek_offset *= dbb->dbb_page_size; lseek_offset *= bcb->bcb_page_size;
if (lseek_offset != (FB_UINT64) LSEEK_OFFSET_CAST lseek_offset) if (lseek_offset != (FB_UINT64) LSEEK_OFFSET_CAST lseek_offset)
{ {
unix_error("lseek", file, isc_io_32bit_exceeded_err, status_vector); unix_error("lseek", file, isc_io_32bit_exceeded_err, status_vector);
return 0; return false;
} }
*offset = lseek_offset; *offset = lseek_offset;
return true;
return file;
} }
@ -999,7 +934,6 @@ static jrd_file* setup_file(Database* dbb, const PathName& file_name, int desc,
{ {
file = FB_NEW_RPT(*dbb->dbb_permanent, file_name.length() + 1) jrd_file(); file = FB_NEW_RPT(*dbb->dbb_permanent, file_name.length() + 1) jrd_file();
file->fil_desc = desc; file->fil_desc = desc;
file->fil_max_page = MAX_ULONG;
file->fil_flags = flags; file->fil_flags = flags;
strcpy(file->fil_string, file_name.c_str()); strcpy(file->fil_string, file_name.c_str());
} }

View File

@ -106,7 +106,7 @@ using namespace Firebird;
#define TEXT SCHAR #define TEXT SCHAR
static bool maybeCloseFile(HANDLE&); static bool maybeCloseFile(HANDLE&);
static jrd_file* seek_file(jrd_file*, BufferDesc*, OVERLAPPED*); static bool seek_file(jrd_file*, BufferDesc*, OVERLAPPED*);
static jrd_file* setup_file(Database*, const Firebird::PathName&, HANDLE, USHORT); static jrd_file* setup_file(Database*, const Firebird::PathName&, HANDLE, USHORT);
static bool nt_error(const TEXT*, const jrd_file*, ISC_STATUS, FbStatusVector* const); static bool nt_error(const TEXT*, const jrd_file*, ISC_STATUS, FbStatusVector* const);
@ -121,39 +121,7 @@ static const DWORD g_dwExtraTempFlags = FILE_ATTRIBUTE_TEMPORARY |
FILE_FLAG_DELETE_ON_CLOSE; FILE_FLAG_DELETE_ON_CLOSE;
int PIO_add_file(thread_db* tdbb, jrd_file* main_file, const Firebird::PathName& file_name, SLONG start) void PIO_close(jrd_file* file)
{
/**************************************
*
* P I O _ a d d _ f i l e
*
**************************************
*
* Functional description
* Add a file to an existing database. Return the sequence
* number of the new file. If anything goes wrong, return a
* sequence of 0.
*
**************************************/
jrd_file* const new_file = PIO_create(tdbb, file_name, false, false);
if (!new_file)
return 0;
new_file->fil_min_page = start;
USHORT sequence = 1;
jrd_file* file;
for (file = main_file; file->fil_next; file = file->fil_next)
++sequence;
file->fil_max_page = start - 1;
file->fil_next = new_file;
return sequence;
}
void PIO_close(jrd_file* main_file)
{ {
/************************************** /**************************************
* *
@ -164,10 +132,7 @@ void PIO_close(jrd_file* main_file)
* Functional description * Functional description
* *
**************************************/ **************************************/
for (jrd_file* file = main_file; file; file = file->fil_next)
{
maybeCloseFile(file->fil_desc); maybeCloseFile(file->fil_desc);
}
} }
@ -251,7 +216,7 @@ bool PIO_expand(const TEXT* file_name, USHORT file_length, TEXT* expanded_name,
} }
void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, const USHORT pageSize) void PIO_extend(thread_db* tdbb, jrd_file* file, const ULONG extPages, const USHORT pageSize)
{ {
/************************************** /**************************************
* *
@ -263,6 +228,8 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons
* Extend file by extPages pages of pageSize size. * Extend file by extPages pages of pageSize size.
* *
**************************************/ **************************************/
fb_assert(extPages);
// hvlad: prevent other reading\writing threads from changing file pointer. // hvlad: prevent other reading\writing threads from changing file pointer.
// As we open file without FILE_FLAG_OVERLAPPED, ReadFile\WriteFile calls // As we open file without FILE_FLAG_OVERLAPPED, ReadFile\WriteFile calls
// will change file pointer we set here and file truncation instead of file // will change file pointer we set here and file truncation instead of file
@ -271,42 +238,30 @@ void PIO_extend(thread_db* tdbb, jrd_file* main_file, const ULONG extPages, cons
// and read\write activity performed simultaneously) // and read\write activity performed simultaneously)
// if file have no extend lock it is better to not extend file than corrupt it // if file have no extend lock it is better to not extend file than corrupt it
if (!main_file->fil_ext_lock) if (!file->fil_ext_lock)
return; return;
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY); EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
FileExtendLockGuard extLock(main_file->fil_ext_lock, true); FileExtendLockGuard extLock(file->fil_ext_lock, true);
ULONG leftPages = extPages;
for (jrd_file* file = main_file; file && leftPages; file = file->fil_next)
{
const ULONG filePages = PIO_get_number_of_pages(file, pageSize); const ULONG filePages = PIO_get_number_of_pages(file, pageSize);
const ULONG fileMaxPages = (file->fil_max_page == MAX_ULONG) ? const ULONG extendBy = MIN(MAX_ULONG - filePages, extPages);
MAX_ULONG : file->fil_max_page - file->fil_min_page + 1;
if (filePages < fileMaxPages)
{
const ULONG extendBy = MIN(fileMaxPages - filePages + file->fil_fudge, leftPages);
HANDLE hFile = file->fil_desc; const HANDLE hFile = file->fil_desc;
LARGE_INTEGER newSize; LARGE_INTEGER newSize;
newSize.QuadPart = ((ULONGLONG) filePages + extendBy) * pageSize; newSize.QuadPart = ((ULONGLONG) filePages + extendBy) * pageSize;
const DWORD ret = SetFilePointer(hFile, newSize.LowPart, &newSize.HighPart, FILE_BEGIN); const DWORD ret = SetFilePointer(hFile, newSize.LowPart, &newSize.HighPart, FILE_BEGIN);
if (ret == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { if (ret == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
nt_error("SetFilePointer", file, isc_io_write_err, NULL); nt_error("SetFilePointer", file, isc_io_write_err, NULL);
}
if (!SetEndOfFile(hFile)) {
nt_error("SetEndOfFile", file, isc_io_write_err, NULL);
}
leftPages -= extendBy; if (!SetEndOfFile(hFile))
} nt_error("SetEndOfFile", file, isc_io_write_err, NULL);
}
} }
void PIO_flush(thread_db* tdbb, jrd_file* main_file) void PIO_flush(thread_db* tdbb, jrd_file* file)
{ {
/************************************** /**************************************
* *
@ -320,7 +275,7 @@ void PIO_flush(thread_db* tdbb, jrd_file* main_file)
**************************************/ **************************************/
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY); EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
for (jrd_file* file = main_file; file; file = file->fil_next) if (file->fil_desc != INVALID_HANDLE_VALUE)
FlushFileBuffers(file->fil_desc); FlushFileBuffers(file->fil_desc);
} }
@ -417,7 +372,7 @@ void PIO_header(thread_db* tdbb, UCHAR* address, int length)
static Firebird::InitInstance<ZeroBuffer> zeros; static Firebird::InitInstance<ZeroBuffer> zeros;
USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* status_vector, USHORT PIO_init_data(thread_db* tdbb, jrd_file* file, FbStatusVector* status_vector,
ULONG startPage, USHORT initPages) ULONG startPage, USHORT initPages)
{ {
/************************************** /**************************************
@ -436,7 +391,7 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
Database* const dbb = tdbb->getDatabase(); Database* const dbb = tdbb->getDatabase();
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY); EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
FileExtendLockGuard extLock(main_file->fil_ext_lock, false); FileExtendLockGuard extLock(file->fil_ext_lock, false);
// Fake buffer, used in seek_file. Page space ID doesn't matter there // Fake buffer, used in seek_file. Page space ID doesn't matter there
// as we already know file to work with // as we already know file to work with
@ -444,16 +399,14 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
bdb.bdb_page = PageNumber(0, startPage); bdb.bdb_page = PageNumber(0, startPage);
OVERLAPPED overlapped; OVERLAPPED overlapped;
jrd_file* file = seek_file(main_file, &bdb, &overlapped); if (!seek_file(file, &bdb, &overlapped))
if (!file)
return 0; return 0;
if (file->fil_min_page + 8 > startPage) if (startPage < 8)
return 0; return 0;
USHORT leftPages = initPages; USHORT leftPages = initPages;
const ULONG initBy = MIN(file->fil_max_page - startPage, leftPages); const ULONG initBy = MIN(MAX_ULONG - startPage, leftPages);
if (initBy < leftPages) if (initBy < leftPages)
leftPages = initBy; leftPages = initBy;
@ -464,8 +417,8 @@ USHORT PIO_init_data(thread_db* tdbb, jrd_file* main_file, FbStatusVector* statu
if (write_pages > leftPages) if (write_pages > leftPages)
write_pages = leftPages; write_pages = leftPages;
jrd_file* file1 = seek_file(main_file, &bdb, &overlapped); if (!seek_file(file, &bdb, &overlapped))
fb_assert(file1 == file); return 0;
const DWORD to_write = (DWORD) write_pages * dbb->dbb_page_size; const DWORD to_write = (DWORD) write_pages * dbb->dbb_page_size;
DWORD written; DWORD written;
@ -590,7 +543,7 @@ bool PIO_read(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
FileExtendLockGuard extLock(file->fil_ext_lock, false); FileExtendLockGuard extLock(file->fil_ext_lock, false);
OVERLAPPED overlapped; OVERLAPPED overlapped;
if (!(file = seek_file(file, bdb, &overlapped))) if (!seek_file(file, bdb, &overlapped))
return false; return false;
HANDLE desc = file->fil_desc; HANDLE desc = file->fil_desc;
@ -625,14 +578,12 @@ bool PIO_read_ahead(thread_db* tdbb,
************************************** **************************************
* *
* Functional description * Functional description
* Read a contiguous set of pages. The only * Read a contiguous set of pages.
* tricky part is to segment the I/O when crossing
* file boundaries.
* *
**************************************/ **************************************/
OVERLAPPED overlapped, *overlapped_ptr; OVERLAPPED overlapped, *overlapped_ptr;
Database* const dbb = tdbb->getDatabase(); const auto dbb = tdbb->getDatabase();
EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY); EngineCheckout cout(tdbb, FB_FUNCTION, EngineCheckout::UNNECESSARY);
@ -647,39 +598,27 @@ bool PIO_read_ahead(thread_db* tdbb,
piob->piob_flags = 0; piob->piob_flags = 0;
} }
// Setup up a dummy buffer descriptor block for seeking file
BufferDesc bdb; BufferDesc bdb;
while (pages)
{
// Setup up a dummy buffer descriptor block for seeking file.
bdb.bdb_dbb = dbb; bdb.bdb_dbb = dbb;
bdb.bdb_page = start_page; bdb.bdb_page = start_page;
jrd_file* file = seek_file(dbb->dbb_file, &bdb, status_vector, overlapped_ptr, &overlapped_ptr); const jrd_file* const file = dbb->dbb_file;
if (!file)
if (!seek_file(file, &bdb, status_vector, overlapped_ptr, &overlapped_ptr))
return false; return false;
// Check that every page within the set resides in the same database const HANDLE desc = file->fil_desc;
// file. If not read what you can and loop back for the rest. const DWORD length = pages * dbb->dbb_page_size;
DWORD segmented_length = 0;
while (pages && start_page >= file->fil_min_page && start_page <= file->fil_max_page)
{
segmented_length += dbb->dbb_page_size;
++start_page;
--pages;
}
HANDLE desc = file->fil_desc;
DWORD actual_length; DWORD actual_length;
if (ReadFile(desc, buffer, segmented_length, &actual_length, overlapped_ptr) && if (ReadFile(desc, buffer, length, &actual_length, overlapped_ptr) &&
actual_length == segmented_length) actual_length == length)
{ {
if (piob && !pages) if (piob)
piob->piob_flags = PIOB_success; piob->piob_flags = PIOB_success;
} }
else if (piob && !pages) else if (piob)
{ {
piob->piob_flags = PIOB_pending; piob->piob_flags = PIOB_pending;
piob->piob_desc = reinterpret_cast<SLONG>(desc); piob->piob_desc = reinterpret_cast<SLONG>(desc);
@ -687,7 +626,7 @@ bool PIO_read_ahead(thread_db* tdbb,
piob->piob_io_length = segmented_length; piob->piob_io_length = segmented_length;
} }
else if (!GetOverlappedResult(desc, overlapped_ptr, &actual_length, TRUE) || else if (!GetOverlappedResult(desc, overlapped_ptr, &actual_length, TRUE) ||
actual_length != segmented_length) actual_length != length)
{ {
if (piob) if (piob)
piob->piob_flags = PIOB_error; piob->piob_flags = PIOB_error;
@ -699,9 +638,6 @@ bool PIO_read_ahead(thread_db* tdbb,
if (!piob || (piob->piob_flags & (PIOB_success | PIOB_error))) if (!piob || (piob->piob_flags & (PIOB_success | PIOB_error)))
release_io_event(file, overlapped_ptr); release_io_event(file, overlapped_ptr);
buffer += segmented_length;
}
return true; return true;
} }
#endif #endif
@ -767,8 +703,7 @@ bool PIO_write(thread_db* tdbb, jrd_file* file, BufferDesc* bdb, Ods::pag* page,
FileExtendLockGuard extLock(file->fil_ext_lock, false); FileExtendLockGuard extLock(file->fil_ext_lock, false);
OVERLAPPED overlapped; OVERLAPPED overlapped;
file = seek_file(file, bdb, &overlapped); if (!seek_file(file, bdb, &overlapped))
if (!file)
return false; return false;
HANDLE desc = file->fil_desc; HANDLE desc = file->fil_desc;
@ -813,9 +748,7 @@ ULONG PIO_get_number_of_pages(const jrd_file* file, const USHORT pagesize)
} }
static jrd_file* seek_file(jrd_file* file, static bool seek_file(jrd_file* file, BufferDesc* bdb, OVERLAPPED* overlapped)
BufferDesc* bdb,
OVERLAPPED* overlapped)
{ {
/************************************** /**************************************
* *
@ -824,24 +757,11 @@ static jrd_file* seek_file(jrd_file* file,
************************************** **************************************
* *
* Functional description * Functional description
* Given a buffer descriptor block, find the appropriate * Given a buffer descriptor block, seek to the proper page in that file.
* file block and seek to the proper page in that file.
* *
**************************************/ **************************************/
BufferControl *bcb = bdb->bdb_bcb; BufferControl* const bcb = bdb->bdb_bcb;
ULONG page = bdb->bdb_page.getPageNum(); const ULONG page = bdb->bdb_page.getPageNum();
for (;; file = file->fil_next)
{
if (!file) {
CORRUPT(158); // msg 158 database file not available
}
else if (page >= file->fil_min_page && page <= file->fil_max_page) {
break;
}
}
page -= file->fil_min_page - file->fil_fudge;
LARGE_INTEGER liOffset; LARGE_INTEGER liOffset;
liOffset.QuadPart = UInt32x32To64((DWORD) page, (DWORD) bcb->bcb_page_size); liOffset.QuadPart = UInt32x32To64((DWORD) page, (DWORD) bcb->bcb_page_size);
@ -854,7 +774,7 @@ static jrd_file* seek_file(jrd_file* file,
ThreadSync* thd = ThreadSync::getThread(FB_FUNCTION); ThreadSync* thd = ThreadSync::getThread(FB_FUNCTION);
overlapped->hEvent = thd->getIOEvent(); overlapped->hEvent = thd->getIOEvent();
return file; return true;
} }
@ -876,7 +796,6 @@ static jrd_file* setup_file(Database* dbb, const Firebird::PathName& file_name,
{ {
file = FB_NEW_RPT(*dbb->dbb_permanent, file_name.length() + 1) jrd_file(); file = FB_NEW_RPT(*dbb->dbb_permanent, file_name.length() + 1) jrd_file();
file->fil_desc = desc; file->fil_desc = desc;
file->fil_max_page = MAX_ULONG;
file->fil_flags = flags; file->fil_flags = flags;
strcpy(file->fil_string, file_name.c_str()); strcpy(file->fil_string, file_name.c_str());

View File

@ -364,115 +364,6 @@ namespace
} // namespace } // namespace
USHORT PAG_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start)
{
/**************************************
*
* P A G _ a d d _ f i l e
*
**************************************
*
* Functional description
* Add a file to the current database. Return the sequence number for the new file.
*
**************************************/
SET_TDBB(tdbb);
ensureDbWritable(tdbb);
const auto dbb = tdbb->getDatabase();
// Find current last file
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
jrd_file* file = pageSpace->file;
while (file->fil_next) {
file = file->fil_next;
}
// Verify database file path against DatabaseAccess entry of firebird.conf
if (!JRD_verify_database_access(file_name))
{
string fileName(file_name);
ISC_systemToUtf8(fileName);
ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("additional database file") <<
Arg::Str(fileName));
}
// Create the file. If the sequence number comes back zero, it didn't work, so punt
const USHORT sequence = PIO_add_file(tdbb, pageSpace->file, file_name, start);
if (!sequence)
return 0;
// Create header page for new file
jrd_file* next = file->fil_next;
WIN window(DB_PAGE_SPACE, next->fil_min_page);
header_page* header = (header_page*) CCH_fake(tdbb, &window, 1);
header->hdr_header.pag_type = pag_header;
header->hdr_sequence = sequence;
header->hdr_page_size = dbb->dbb_page_size;
header->hdr_data[0] = HDR_end;
header->hdr_end = HDR_SIZE;
next->fil_sequence = sequence;
#ifdef SUPPORT_RAW_DEVICES
// The following lines (taken from PAG_format_header) are needed to identify
// this file in raw_devices_validate_database as a valid database attachment.
*(ISC_TIMESTAMP*) header->hdr_creation_date = TimeZoneUtil::getCurrentGmtTimeStamp().utc_timestamp;
// should we include milliseconds or not?
//TimeStamp::round_time(header->hdr_creation_date->timestamp_time, 0);
header->hdr_ods_version = ODS_VERSION | ODS_FIREBIRD_FLAG;
DbImplementation::current.store(header);
header->hdr_ods_minor = ODS_CURRENT;
if (dbb->dbb_flags & DBB_DB_SQL_dialect_3)
header->hdr_flags |= hdr_SQL_dialect_3;
#endif
header->hdr_header.pag_pageno = window.win_page.getPageNum();
// It's header, never encrypted
PIO_write(tdbb, pageSpace->file, window.win_bdb, window.win_buffer, tdbb->tdbb_status_vector);
CCH_RELEASE(tdbb, &window);
next->fil_fudge = 1;
// Update the previous header page to point to new file
file->fil_fudge = 0;
window.win_page = file->fil_min_page;
header = (header_page*) CCH_FETCH(tdbb, &window, LCK_write, pag_header);
if (!file->fil_min_page)
CCH_MARK_MUST_WRITE(tdbb, &window);
else
CCH_MARK(tdbb, &window);
--start;
if (file->fil_min_page)
{
PAG_add_header_entry(tdbb, header, HDR_file, static_cast<USHORT>(strlen(file_name)),
reinterpret_cast<const UCHAR*>(file_name));
PAG_add_header_entry(tdbb, header, HDR_last_page, sizeof(SLONG), (UCHAR*) &start);
}
else
{
storeClump(tdbb, HDR_file, static_cast<USHORT>(strlen(file_name)),
reinterpret_cast<const UCHAR*>(file_name));
storeClump(tdbb, HDR_last_page, sizeof(SLONG), (UCHAR*) &start);
}
header->hdr_header.pag_pageno = window.win_page.getPageNum();
// It's header, never encrypted
PIO_write(tdbb, pageSpace->file, window.win_bdb, window.win_buffer, tdbb->tdbb_status_vector);
CCH_RELEASE(tdbb, &window);
if (file->fil_min_page)
file->fil_fudge = 1;
return sequence;
}
void PAG_add_header_entry(thread_db* tdbb, header_page* header, void PAG_add_header_entry(thread_db* tdbb, header_page* header,
USHORT type, USHORT len, const UCHAR* entry) USHORT type, USHORT len, const UCHAR* entry)
{ {
@ -1136,8 +1027,7 @@ void PAG_header(thread_db* tdbb, bool info, const TriState newForceWrite)
// Ensure the file-level FW mode matches the actual FW mode in the database // Ensure the file-level FW mode matches the actual FW mode in the database
const auto pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); const auto pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
for (jrd_file* file = pageSpace->file; file; file = file->fil_next) PIO_force_write(pageSpace->file, forceWrite && !readOnly);
PIO_force_write(file, forceWrite && !readOnly);
if (dbb->dbb_backup_manager->getState() != Ods::hdr_nbak_normal) if (dbb->dbb_backup_manager->getState() != Ods::hdr_nbak_normal)
dbb->dbb_backup_manager->setForcedWrites(forceWrite); dbb->dbb_backup_manager->setForcedWrites(forceWrite);
@ -1327,7 +1217,7 @@ void PAG_init(thread_db* tdbb)
} }
void PAG_init2(thread_db* tdbb, USHORT shadow_number) void PAG_init2(thread_db* tdbb)
{ {
/************************************** /**************************************
* *
@ -1336,87 +1226,19 @@ void PAG_init2(thread_db* tdbb, USHORT shadow_number)
************************************** **************************************
* *
* Functional description * Functional description
* Perform second phase of page initialization -- the eternal * Read and apply the database header options.
* search for additional files.
* *
**************************************/ **************************************/
SET_TDBB(tdbb); SET_TDBB(tdbb);
const auto dbb = tdbb->getDatabase(); const auto dbb = tdbb->getDatabase();
FbStatusVector* status = tdbb->tdbb_status_vector; WIN window(HEADER_PAGE_NUMBER);
const auto header = (header_page*) CCH_FETCH(tdbb, &window, LCK_read, pag_header);
// allocate a spare buffer which is large enough,
// and set up to release it in case of error. Align
// the temporary page buffer for raw disk access.
Array<UCHAR> temp;
UCHAR* const temp_page = temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize());
PageSpace* const pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
jrd_file* file = pageSpace->file;
if (shadow_number)
{
Shadow* shadow = dbb->dbb_shadow;
for (; shadow; shadow = shadow->sdw_next)
{
if (shadow->sdw_number == shadow_number)
{
file = shadow->sdw_file;
break;
}
}
if (!shadow)
BUGCHECK(161); // msg 161 shadow block not found
}
USHORT sequence = 1;
WIN window(DB_PAGE_SPACE, -1);
// Loop thru files and header pages until everything is open
while (true)
{
window.win_page = file->fil_min_page;
ULONG last_page = 0;
BufferDesc temp_bdb(dbb->dbb_bcb);
// note that we do not have to get a read lock on
// the header page (except for header page 0) because
// the only time it will be modified is when adding a file,
// which must be done with an exclusive lock on the database --
// if this changes, this policy will have to be reevaluated;
// at any rate there is a problem with getting a read lock
// because the corresponding page in the main database file may not exist
if (!file->fil_min_page)
CCH_FETCH(tdbb, &window, LCK_read, pag_header);
header_page* header = (header_page*) temp_page;
temp_bdb.bdb_buffer = (pag*) header;
temp_bdb.bdb_page = window.win_page;
// Read the required page into the local buffer
// It's header, never encrypted
PIO_read(tdbb, file, &temp_bdb, (PAG) header, status);
if (shadow_number && !file->fil_min_page)
CCH_RELEASE(tdbb, &window);
PathName nextFileName;
for (const UCHAR* p = header->hdr_data; *p != HDR_end; p += 2 + p[1]) for (const UCHAR* p = header->hdr_data; *p != HDR_end; p += 2 + p[1])
{ {
switch (*p) switch (*p)
{ {
case HDR_file:
nextFileName.assign(p + 2, p[1]);
break;
case HDR_last_page:
fb_assert(p[1] == sizeof(last_page));
memcpy(&last_page, p + 2, sizeof(last_page));
break;
case HDR_sweep_interval: case HDR_sweep_interval:
fb_assert(p[1] == sizeof(SLONG)); fb_assert(p[1] == sizeof(SLONG));
memcpy(&dbb->dbb_sweep_interval, p + 2, sizeof(SLONG)); memcpy(&dbb->dbb_sweep_interval, p + 2, sizeof(SLONG));
@ -1431,33 +1253,13 @@ void PAG_init2(thread_db* tdbb, USHORT shadow_number)
fb_assert(p[1] == sizeof(FB_UINT64)); fb_assert(p[1] == sizeof(FB_UINT64));
memcpy(&dbb->dbb_repl_sequence, p + 2, sizeof(FB_UINT64)); memcpy(&dbb->dbb_repl_sequence, p + 2, sizeof(FB_UINT64));
break; break;
}
}
if (!shadow_number && !file->fil_min_page) default:
CCH_RELEASE(tdbb, &window);
if (file->fil_min_page)
file->fil_fudge = 1;
if (nextFileName.isEmpty())
break; break;
}
// Verify database file path against DatabaseAccess entry of firebird.conf
if (!JRD_verify_database_access(nextFileName))
{
ISC_systemToUtf8(nextFileName);
ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("additional database file") <<
Arg::Str(nextFileName));
} }
file->fil_next = PIO_open(tdbb, nextFileName, nextFileName); CCH_RELEASE(tdbb, &window);
file->fil_max_page = last_page;
file = file->fil_next;
file->fil_min_page = last_page + 1;
file->fil_sequence = sequence++;
}
} }
@ -1644,14 +1446,10 @@ void PAG_set_force_write(thread_db* tdbb, bool flag)
CCH_RELEASE(tdbb, &window); CCH_RELEASE(tdbb, &window);
PageSpace* const pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); PageSpace* const pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
for (jrd_file* file = pageSpace->file; file; file = file->fil_next) PIO_force_write(pageSpace->file, flag);
PIO_force_write(file, flag);
for (Shadow* shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next) for (Shadow* shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next)
{ PIO_force_write(shadow->sdw_file, flag);
for (jrd_file* file = shadow->sdw_file; file; file = file->fil_next)
PIO_force_write(file, flag);
}
if (dbb->dbb_backup_manager->getState() != Ods::hdr_nbak_normal) if (dbb->dbb_backup_manager->getState() != Ods::hdr_nbak_normal)
dbb->dbb_backup_manager->setForcedWrites(flag); dbb->dbb_backup_manager->setForcedWrites(flag);
@ -1917,13 +1715,7 @@ PageSpace::~PageSpace()
if (file) if (file)
{ {
PIO_close(file); PIO_close(file);
while (file)
{
jrd_file* next = file->fil_next;
delete file; delete file;
file = next;
}
} }
} }
@ -1936,15 +1728,7 @@ ULONG PageSpace::actAlloc()
* *
**************************************/ **************************************/
// Traverse the linked list of files and add up the return PIO_get_number_of_pages(file, dbb->dbb_page_size);
// number of pages in each file
const USHORT pageSize = dbb->dbb_page_size;
ULONG tot_pages = 0;
for (const jrd_file* f = file; f != NULL; f = f->fil_next) {
tot_pages += PIO_get_number_of_pages(f, pageSize);
}
return tot_pages;
} }
ULONG PageSpace::actAlloc(const Database* dbb) ULONG PageSpace::actAlloc(const Database* dbb)
@ -1961,17 +1745,7 @@ ULONG PageSpace::maxAlloc()
* Compute last physically allocated page of database. * Compute last physically allocated page of database.
* *
**************************************/ **************************************/
const USHORT pageSize = dbb->dbb_page_size; const ULONG nPages = PIO_get_number_of_pages(file, dbb->dbb_page_size);
const jrd_file* f = file;
ULONG nPages = PIO_get_number_of_pages(f, pageSize);
while (f->fil_next && nPages == f->fil_max_page - f->fil_min_page + 1 + f->fil_fudge)
{
f = f->fil_next;
nPages = PIO_get_number_of_pages(f, pageSize);
}
nPages += f->fil_min_page - f->fil_fudge;
if (maxPageNumber < nPages) if (maxPageNumber < nPages)
maxPageNumber = nPages; maxPageNumber = nPages;
@ -1987,15 +1761,7 @@ ULONG PageSpace::maxAlloc(const Database* dbb)
bool PageSpace::onRawDevice() const bool PageSpace::onRawDevice() const
{ {
#ifdef SUPPORT_RAW_DEVICES return (file->fil_flags & FIL_raw_device) != 0;
for (const jrd_file* f = file; f != NULL; f = f->fil_next)
{
if (f->fil_flags & FIL_raw_device)
return true;
}
#endif
return false;
} }
ULONG PageSpace::lastUsedPage() ULONG PageSpace::lastUsedPage()

View File

@ -37,7 +37,6 @@ namespace Ods {
struct header_page; struct header_page;
} }
USHORT PAG_add_file(Jrd::thread_db* tdbb, const TEXT*, SLONG);
void PAG_add_header_entry(Jrd::thread_db* tdbb, Ods::header_page*, USHORT, USHORT, const UCHAR*); void PAG_add_header_entry(Jrd::thread_db* tdbb, Ods::header_page*, USHORT, USHORT, const UCHAR*);
bool PAG_replace_entry_first(Jrd::thread_db* tdbb, Ods::header_page*, USHORT, USHORT, const UCHAR*); bool PAG_replace_entry_first(Jrd::thread_db* tdbb, Ods::header_page*, USHORT, USHORT, const UCHAR*);
Ods::pag* PAG_allocate_pages(Jrd::thread_db* tdbb, Jrd::win* window, unsigned cntAlloc, bool aligned); Ods::pag* PAG_allocate_pages(Jrd::thread_db* tdbb, Jrd::win* window, unsigned cntAlloc, bool aligned);
@ -49,7 +48,7 @@ bool PAG_get_clump(Jrd::thread_db*, USHORT, USHORT*, UCHAR*);
void PAG_header(Jrd::thread_db*, bool, const Firebird::TriState newForceWrite = Firebird::TriState()); void PAG_header(Jrd::thread_db*, bool, const Firebird::TriState newForceWrite = Firebird::TriState());
void PAG_header_init(Jrd::thread_db*); void PAG_header_init(Jrd::thread_db*);
void PAG_init(Jrd::thread_db*); void PAG_init(Jrd::thread_db*);
void PAG_init2(Jrd::thread_db*, USHORT); void PAG_init2(Jrd::thread_db*);
SLONG PAG_last_page(Jrd::thread_db* tdbb); SLONG PAG_last_page(Jrd::thread_db* tdbb);
void PAG_release_page(Jrd::thread_db* tdbb, const Jrd::PageNumber&, const Jrd::PageNumber&); void PAG_release_page(Jrd::thread_db* tdbb, const Jrd::PageNumber&, const Jrd::PageNumber&);
void PAG_release_pages(Jrd::thread_db* tdbb, USHORT pageSpaceID, int cntRelease, void PAG_release_pages(Jrd::thread_db* tdbb, USHORT pageSpaceID, int cntRelease,

View File

@ -64,7 +64,6 @@ static bool check_for_file(thread_db* tdbb, const SCHAR*, USHORT);
#ifdef NOT_USED_OR_REPLACED #ifdef NOT_USED_OR_REPLACED
static void check_if_got_ast(thread_db* tdbb, jrd_file*); static void check_if_got_ast(thread_db* tdbb, jrd_file*);
#endif #endif
static void copy_header(thread_db* tdbb);
static void update_dbb_to_sdw(Database*); static void update_dbb_to_sdw(Database*);
@ -112,147 +111,6 @@ void SDW_add(thread_db* tdbb, const TEXT* file_name, USHORT shadow_number, USHOR
} }
int SDW_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start, USHORT shadow_number)
{
/**************************************
*
* S D W _ a d d _ f i l e
*
**************************************
*
* Functional description
* Add a file to a shadow set.
* Return the sequence number for the new file.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase();
SyncLockGuard guard(&dbb->dbb_shadow_sync, SYNC_EXCLUSIVE, "SDW_add_file");
// Find the file to be extended
jrd_file* shadow_file = 0;
Shadow* shadow;
for (shadow = dbb->dbb_shadow; shadow; shadow = shadow->sdw_next)
{
if ((shadow->sdw_number == shadow_number) &&
!(shadow->sdw_flags & (SDW_IGNORE | SDW_rollover)))
{
shadow_file = shadow->sdw_file;
break;
}
}
if (!shadow) {
return 0;
}
// find the last file in the list, open the new file
jrd_file* file = shadow_file;
while (file->fil_next) {
file = file->fil_next;
}
// Verify shadow file path against DatabaseAccess entry of firebird.conf
if (!JRD_verify_database_access(file_name))
{
ERR_post(Arg::Gds(isc_conf_access_denied) << Arg::Str("database shadow") <<
Arg::Str(file_name));
}
const SLONG sequence = PIO_add_file(tdbb, shadow_file, file_name, start);
if (!sequence)
return 0;
jrd_file* next = file->fil_next;
// Always write the header page, even for a conditional
// shadow that hasn't been activated.
// allocate a spare buffer which is large enough,
// and set up to release it in case of error. Align
// the spare page buffer for raw disk access.
Array<UCHAR> temp;
UCHAR* const spare_page = temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize());
// create the header using the spare_buffer
header_page* header = (header_page*) spare_page;
header->hdr_header.pag_type = pag_header;
header->hdr_sequence = sequence;
header->hdr_page_size = dbb->dbb_page_size;
header->hdr_data[0] = HDR_end;
header->hdr_end = HDR_SIZE;
// fool PIO_write into writing the scratch page into the correct place
BufferDesc temp_bdb(dbb->dbb_bcb);
temp_bdb.bdb_page = next->fil_min_page;
temp_bdb.bdb_buffer = (PAG) header;
header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum();
// It's header, never encrypted
if (!PIO_write(tdbb, shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
return 0;
next->fil_fudge = 1;
// Update the previous header page to point to new file --
// we can use the same header page, suitably modified,
// because they all look pretty much the same at this point
/*******************
Fix for bug 7925. drop_gdb wan not dropping secondary file in
multi-shadow files. The structure was not being filled with the
info. Commented some code so that the structure will always be filled.
-Sudesh 07/06/95
The original code :
===
if (shadow_file == file)
copy_header(tdbb);
else
===
************************/
// Temporarly reverting the change ------- Sudesh 07/07/95 *******
if (shadow_file == file)
{
copy_header(tdbb);
}
else
{
--start;
header->hdr_data[0] = HDR_end;
header->hdr_end = HDR_SIZE;
PAG_add_header_entry(tdbb, header, HDR_file, static_cast<USHORT>(strlen(file_name)),
reinterpret_cast<const UCHAR*>(file_name));
PAG_add_header_entry(tdbb, header, HDR_last_page, sizeof(start),
reinterpret_cast<const UCHAR*>(&start));
file->fil_fudge = 0;
temp_bdb.bdb_page = file->fil_min_page;
header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum();
// It's header, never encrypted
if (!PIO_write(tdbb, shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
return 0;
if (file->fil_min_page) {
file->fil_fudge = 1;
}
}
if (file->fil_min_page) {
file->fil_fudge = 1;
}
return sequence;
}
void SDW_check(thread_db* tdbb) void SDW_check(thread_db* tdbb)
{ {
/************************************** /**************************************
@ -814,12 +672,7 @@ bool SDW_rollover_to_shadow(thread_db* tdbb, jrd_file* file, const bool inAst)
// close the main database file if possible and release all file blocks // close the main database file if possible and release all file blocks
PIO_close(pageSpace->file); PIO_close(pageSpace->file);
delete pageSpace->file;
while ( (file = pageSpace->file) )
{
pageSpace->file = file->fil_next;
delete file;
}
/* point the main database file at the file of the first shadow /* point the main database file at the file of the first shadow
in the list and mark that shadow as rolled over to in the list and mark that shadow as rolled over to
@ -894,13 +747,7 @@ static void shutdown_shadow(Shadow* shadow)
// close the shadow files and free up the associated memory // close the shadow files and free up the associated memory
PIO_close(shadow->sdw_file); PIO_close(shadow->sdw_file);
jrd_file* file; delete shadow->sdw_file;
jrd_file* free = shadow->sdw_file;
for (; (file = free->fil_next); free = file)
delete free;
delete free;
delete shadow; delete shadow;
} }
@ -1003,12 +850,6 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name,
const header_page* shadow_header = (header_page*) spare_page; const header_page* shadow_header = (header_page*) spare_page;
// NOTE ! NOTE! NOTE!
// Starting V4.0, header pages can have overflow pages. For the shadow,
// we are making an assumption that the shadow header page will not
// overflow, as the only things written on a shadow header is the
// HDR_root_file_name, HDR_file, and HDR_last_page
const UCHAR* p = shadow_header->hdr_data; const UCHAR* p = shadow_header->hdr_data;
while (*p != HDR_end && *p != HDR_root_file_name) { while (*p != HDR_end && *p != HDR_root_file_name) {
p += 2 + p[1]; p += 2 + p[1];
@ -1046,10 +887,6 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name,
shadow->sdw_flags |= SDW_dumped; shadow->sdw_flags |= SDW_dumped;
} }
// get the ancillary files and reset the error environment
PAG_init2(tdbb, shadow_number);
} // try } // try
catch (const Firebird::Exception& ex) catch (const Firebird::Exception& ex)
{ {
@ -1257,35 +1094,6 @@ static void check_if_got_ast(thread_db* tdbb, jrd_file* file)
} }
#endif #endif
static void copy_header(thread_db* tdbb)
{
/**************************************
*
* c o p y _ h e a d e r
*
**************************************
*
* Functional description
* Fetch the header page from the database
* and write it to the shadow file. This is
* done so that if this shadow is extended,
* the header page will be there for writing
* the name of the extend file.
*
**************************************/
SET_TDBB(tdbb);
Database* dbb = tdbb->getDatabase();
CHECK_DBB(dbb);
// get the database header page and write it out --
// CCH will take care of modifying it
WIN window(HEADER_PAGE_NUMBER);
CCH_FETCH(tdbb, &window, LCK_write, pag_header);
CCH_MARK_MUST_WRITE(tdbb, &window);
CCH_RELEASE(tdbb, &window);
}
static void update_dbb_to_sdw(Database* dbb) static void update_dbb_to_sdw(Database* dbb)
{ {
@ -1319,13 +1127,7 @@ static void update_dbb_to_sdw(Database* dbb)
// hvlad: need sync for this code // hvlad: need sync for this code
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE); PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
PIO_close(pageSpace->file); PIO_close(pageSpace->file);
delete pageSpace->file;
jrd_file* file;
while ( (file = pageSpace->file) )
{
pageSpace->file = file->fil_next;
delete file;
}
pageSpace->file = shadow->sdw_file; pageSpace->file = shadow->sdw_file;
shadow->sdw_flags |= SDW_rollover; shadow->sdw_flags |= SDW_rollover;

View File

@ -29,7 +29,6 @@ namespace Jrd {
} }
void SDW_add(Jrd::thread_db* tdbb, const TEXT*, USHORT, USHORT); void SDW_add(Jrd::thread_db* tdbb, const TEXT*, USHORT, USHORT);
int SDW_add_file(Jrd::thread_db* tdbb, const TEXT*, SLONG, USHORT);
void SDW_check(Jrd::thread_db* tdbb); void SDW_check(Jrd::thread_db* tdbb);
bool SDW_check_conditional(Jrd::thread_db* tdbb); bool SDW_check_conditional(Jrd::thread_db* tdbb);
void SDW_close(); void SDW_close();

View File

@ -478,7 +478,6 @@ enum dfw_t {
dfw_create_index, dfw_create_index,
dfw_delete_index, dfw_delete_index,
dfw_compute_security, dfw_compute_security,
dfw_add_file,
dfw_add_shadow, dfw_add_shadow,
dfw_delete_shadow, dfw_delete_shadow,
dfw_delete_shadow_nodelete, dfw_delete_shadow_nodelete,

View File

@ -2240,27 +2240,32 @@ bool VIO_erase(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
case rel_files: case rel_files:
protect_system_table_delupd(tdbb, relation, "DELETE"); protect_system_table_delupd(tdbb, relation, "DELETE");
{ {
const bool name_defined = EVL_field(0, rpb->rpb_record, f_file_name, &desc); const bool nameDefined = EVL_field(0, rpb->rpb_record, f_file_name, &desc);
const USHORT file_flags = EVL_field(0, rpb->rpb_record, f_file_flags, &desc2) ?
const auto shadowNumber = EVL_field(0, rpb->rpb_record, f_file_shad_num, &desc2) ?
MOV_get_long(tdbb, &desc2, 0) : 0; MOV_get_long(tdbb, &desc2, 0) : 0;
if (file_flags & FILE_difference)
const auto fileFlags = EVL_field(0, rpb->rpb_record, f_file_flags, &desc2) ?
MOV_get_long(tdbb, &desc2, 0) : 0;
if (shadowNumber)
{ {
if (file_flags & FILE_backing_up) if (!(fileFlags & FILE_inactive))
{
const auto work = (fileFlags & FILE_nodelete) ?
dfw_delete_shadow_nodelete : dfw_delete_shadow;
DFW_post_work(transaction, work, &desc, shadowNumber);
}
}
else if (fileFlags & FILE_difference)
{
if (fileFlags & FILE_backing_up)
DFW_post_work(transaction, dfw_end_backup, &desc, 0); DFW_post_work(transaction, dfw_end_backup, &desc, 0);
if (name_defined)
if (nameDefined)
DFW_post_work(transaction, dfw_delete_difference, &desc, 0); DFW_post_work(transaction, dfw_delete_difference, &desc, 0);
} }
else if (EVL_field(0, rpb->rpb_record, f_file_shad_num, &desc2) &&
(id = MOV_get_long(tdbb, &desc2, 0)))
{
if (!(file_flags & FILE_inactive))
{
if (file_flags & FILE_nodelete)
DFW_post_work(transaction, dfw_delete_shadow_nodelete, &desc, id);
else
DFW_post_work(transaction, dfw_delete_shadow, &desc, id);
}
}
} }
break; break;
@ -3617,18 +3622,24 @@ bool VIO_modify(thread_db* tdbb, record_param* org_rpb, record_param* new_rpb, j
case rel_files: case rel_files:
protect_system_table_delupd(tdbb, relation, "UPDATE"); protect_system_table_delupd(tdbb, relation, "UPDATE");
{ {
SSHORT new_rel_flags, old_rel_flags;
EVL_field(0, new_rpb->rpb_record, f_file_name, &desc1); EVL_field(0, new_rpb->rpb_record, f_file_name, &desc1);
if (EVL_field(0, new_rpb->rpb_record, f_file_flags, &desc2) &&
((new_rel_flags = MOV_get_long(tdbb, &desc2, 0)) & FILE_difference) && const auto orgFileFlags = EVL_field(0, org_rpb->rpb_record, f_file_flags, &desc2) ?
EVL_field(0, org_rpb->rpb_record, f_file_flags, &desc2) && MOV_get_long(tdbb, &desc2, 0) : 0;
((old_rel_flags = MOV_get_long(tdbb, &desc2, 0)) != new_rel_flags)) const auto newFileFlags = EVL_field(0, new_rpb->rpb_record, f_file_flags, &desc2) ?
MOV_get_long(tdbb, &desc2, 0) : 0;
if ((newFileFlags & FILE_difference) && orgFileFlags != newFileFlags)
{ {
DFW_post_work(transaction, DFW_post_work(transaction,
(new_rel_flags & FILE_backing_up ? dfw_begin_backup : dfw_end_backup), (newFileFlags & FILE_backing_up) ? dfw_begin_backup : dfw_end_backup,
&desc1, 0); &desc1, 0);
} }
} }
// Nullify the unsupported fields
new_rpb->rpb_record->setNull(f_file_seq);
new_rpb->rpb_record->setNull(f_file_start);
new_rpb->rpb_record->setNull(f_file_length);
break; break;
case rel_charsets: case rel_charsets:
@ -4175,34 +4186,32 @@ void VIO_store(thread_db* tdbb, record_param* rpb, jrd_tra* transaction)
case rel_files: case rel_files:
protect_system_table_insert(tdbb, request, relation); protect_system_table_insert(tdbb, request, relation);
{ {
const bool name_defined = EVL_field(0, rpb->rpb_record, f_file_name, &desc); const bool nameDefined = EVL_field(0, rpb->rpb_record, f_file_name, &desc);
if (EVL_field(0, rpb->rpb_record, f_file_shad_num, &desc2) &&
MOV_get_long(tdbb, &desc2, 0)) const auto shadowNumber = EVL_field(0, rpb->rpb_record, f_file_shad_num, &desc2) ?
MOV_get_long(tdbb, &desc2, 0) : 0;
const auto fileFlags = EVL_field(0, rpb->rpb_record, f_file_flags, &desc2) ?
MOV_get_long(tdbb, &desc2, 0) : 0;
if (shadowNumber)
{ {
EVL_field(0, rpb->rpb_record, f_file_flags, &desc2); if (!(fileFlags & FILE_inactive))
if (!(MOV_get_long(tdbb, &desc2, 0) & FILE_inactive)) {
DFW_post_work(transaction, dfw_add_shadow, &desc, 0); DFW_post_work(transaction, dfw_add_shadow, &desc, 0);
} }
} else if (fileFlags & FILE_difference)
else
{ {
USHORT rel_flags; if (nameDefined)
if (EVL_field(0, rpb->rpb_record, f_file_flags, &desc2) &&
((rel_flags = MOV_get_long(tdbb, &desc2, 0)) & FILE_difference))
{
if (name_defined) {
DFW_post_work(transaction, dfw_add_difference, &desc, 0); DFW_post_work(transaction, dfw_add_difference, &desc, 0);
}
if (rel_flags & FILE_backing_up) if (fileFlags & FILE_backing_up)
{
DFW_post_work(transaction, dfw_begin_backup, &desc, 0); DFW_post_work(transaction, dfw_begin_backup, &desc, 0);
} }
} }
else { // Nullify the unsupported fields
DFW_post_work(transaction, dfw_add_file, &desc, 0); rpb->rpb_record->setNull(f_file_seq);
} rpb->rpb_record->setNull(f_file_start);
} rpb->rpb_record->setNull(f_file_length);
}
break; break;
case rel_triggers: case rel_triggers:

View File

@ -164,10 +164,6 @@ struct dba_rel
struct dba_fil struct dba_fil
{ {
dba_fil* fil_next; // Next file in database
ULONG fil_min_page; // Minimum page number in file
ULONG fil_max_page; // Maximum page number in file
USHORT fil_fudge; // Fudge factor for page relocation
#ifdef WIN_NT #ifdef WIN_NT
void *fil_desc; void *fil_desc;
#else #else
@ -216,16 +212,6 @@ static void print_help();
#include "../utilities/gstat/dba_proto.h" #include "../utilities/gstat/dba_proto.h"
struct open_files
{
#ifdef WIN_NT
void* desc;
#else
int desc;
#endif
open_files* open_files_next;
};
struct dba_mem struct dba_mem
{ {
char* memory; char* memory;
@ -241,7 +227,7 @@ public:
: ThreadData(tddDBA), uSvc(us) : ThreadData(tddDBA), uSvc(us)
{ {
//dba_throw = false; //dba_throw = false;
files = 0; file = 0;
relations = 0; relations = 0;
page_size = 0; page_size = 0;
dp_per_pp = 0; dp_per_pp = 0;
@ -252,14 +238,13 @@ public:
global_buffer = 0; global_buffer = 0;
exit_code = 0; exit_code = 0;
head_of_mem_list = 0; head_of_mem_list = 0;
head_of_files_list = 0;
memset(dba_status_vector, 0, sizeof (dba_status_vector)); memset(dba_status_vector, 0, sizeof (dba_status_vector));
dba_status = dba_status_vector; dba_status = dba_status_vector;
} }
//bool dba_throw; //bool dba_throw;
Firebird::UtilSvc* uSvc; Firebird::UtilSvc* uSvc;
dba_fil* files; dba_fil* file;
dba_rel* relations; dba_rel* relations;
USHORT page_size; USHORT page_size;
USHORT dp_per_pp; USHORT dp_per_pp;
@ -270,7 +255,6 @@ public:
pag* global_buffer; pag* global_buffer;
int exit_code; int exit_code;
dba_mem *head_of_mem_list; dba_mem *head_of_mem_list;
open_files *head_of_files_list;
ISC_STATUS *dba_status; ISC_STATUS *dba_status;
ISC_STATUS_ARRAY dba_status_vector; ISC_STATUS_ARRAY dba_status_vector;
@ -613,7 +597,7 @@ int gstat(Firebird::UtilSvc* uSvc)
expandDatabaseName(fileName, tempStr, NULL); expandDatabaseName(fileName, tempStr, NULL);
fileName = tempStr; fileName = tempStr;
dba_fil* current = db_open(fileName.c_str(), fileName.length()); dba_fil* file = db_open(fileName.c_str(), fileName.length());
alignas(DIRECT_IO_BLOCK_SIZE) SCHAR temp[MAX(RAW_HEADER_SIZE, DIRECT_IO_BLOCK_SIZE)]; alignas(DIRECT_IO_BLOCK_SIZE) SCHAR temp[MAX(RAW_HEADER_SIZE, DIRECT_IO_BLOCK_SIZE)];
tddba->page_size = MAX(RAW_HEADER_SIZE, DIRECT_IO_BLOCK_SIZE); tddba->page_size = MAX(RAW_HEADER_SIZE, DIRECT_IO_BLOCK_SIZE);
@ -661,38 +645,6 @@ int gstat(Firebird::UtilSvc* uSvc)
if (sw_header) if (sw_header)
dba_exit(FINI_OK, tddba); dba_exit(FINI_OK, tddba);
// gather continuation files
while (true)
{
if (page != HEADER_PAGE)
{
current = db_open(file_name, static_cast<USHORT>(strlen(file_name)));
header = (const header_page*) db_read(page);
}
if (current != tddba->files)
current->fil_fudge = 1; // ignore header page once read it
PathName nextFileName;
const UCHAR* vp = header->hdr_data;
for (const auto vend = reinterpret_cast<const UCHAR*>(header) + header->hdr_page_size;
vp < vend && *vp != HDR_end; vp += 2 + vp[1])
{
if (*vp == HDR_file)
nextFileName.assign(vp + 2, vp[1]);
if (*vp == HDR_last_page)
memcpy(&current->fil_max_page, vp + 2, sizeof(current->fil_max_page));
}
if (nextFileName.isEmpty())
break;
page = current->fil_max_page + 1; // first page of next file
}
if (sw_enc) if (sw_enc)
{ {
class Statist class Statist
@ -724,6 +676,7 @@ int gstat(Firebird::UtilSvc* uSvc)
private: private:
ULONG enc, non; ULONG enc, non;
}; };
Statist data, index, blob, generator, other; Statist data, index, blob, generator, other;
ULONG last = lastUsedPage(header->hdr_page_size); ULONG last = lastUsedPage(header->hdr_page_size);
@ -766,18 +719,6 @@ int gstat(Firebird::UtilSvc* uSvc)
dba_exit(FINI_OK, tddba); dba_exit(FINI_OK, tddba);
} }
// print continuation file sequence
dba_print(false, 7);
// msg 7: \n\nDatabase file sequence:
for (current = tddba->files; current->fil_next; current = current->fil_next)
{
dba_print(false, 8, SafeArg() << current->fil_string << current->fil_next->fil_string);
// msg 8: File %s continues as file %s
}
dba_print(false, 9, SafeArg() << current->fil_string << ((current == tddba->files) ? "only" : "last"));
// msg 9: File %s is the %s file\n
// Check to make sure that the user accessing the database is either // Check to make sure that the user accessing the database is either
// SYSDBA or owner of the database // SYSDBA or owner of the database
@ -1192,22 +1133,11 @@ int gstat(Firebird::UtilSvc* uSvc)
alloced = alloced->mem_next; alloced = alloced->mem_next;
} }
// close files // close file
open_files* open_file = tddba->head_of_files_list; if (tddba->file)
while (open_file) db_close(tddba->file->fil_desc);
{
db_close(open_file->desc);
open_file = open_file->open_files_next;
}
// free linked lists // free linked lists
while (tddba->head_of_files_list != 0)
{
open_files* tmp1 = tddba->head_of_files_list;
tddba->head_of_files_list = tddba->head_of_files_list->open_files_next;
delete tmp1;
}
while (tddba->head_of_mem_list != 0) while (tddba->head_of_mem_list != 0)
{ {
dba_mem* tmp2 = tddba->head_of_mem_list; dba_mem* tmp2 = tddba->head_of_mem_list;
@ -1865,29 +1795,12 @@ static dba_fil* db_open(const char* file_name, USHORT file_length)
**************************************/ **************************************/
tdba* tddba = tdba::getSpecific(); tdba* tddba = tdba::getSpecific();
dba_fil* fil; const auto file = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1);
if (tddba->files) strcpy(file->fil_string, file_name);
{ file->fil_length = file_length;
for (fil = tddba->files; fil->fil_next; fil = fil->fil_next);
fil->fil_next = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1);
fil->fil_next->fil_min_page = fil->fil_max_page + 1;
fil = fil->fil_next;
}
else
{
// empty list
fil = tddba->files = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1);
fil->fil_min_page = 0L;
}
fil->fil_next = NULL; file->fil_desc = CreateFile(file_name,
strcpy(fil->fil_string, file_name);
fil->fil_length = file_length;
fil->fil_fudge = 0;
fil->fil_max_page = 0L;
fil->fil_desc = CreateFile( file_name,
GENERIC_READ, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, NULL,
@ -1895,31 +1808,15 @@ static dba_fil* db_open(const char* file_name, USHORT file_length)
FILE_ATTRIBUTE_NORMAL, FILE_ATTRIBUTE_NORMAL,
0); 0);
if (fil->fil_desc == INVALID_HANDLE_VALUE) if (file->fil_desc == INVALID_HANDLE_VALUE)
{ {
tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 29, SafeArg() << file_name); tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 29, SafeArg() << file_name);
// msg 29: Can't open database file %s // msg 29: Can't open database file %s
db_error(GetLastError()); db_error(GetLastError());
} }
open_files* file_list = FB_NEW_POOL(*getDefaultMemoryPool()) open_files; tddba->file = file;
if (!file_list) return file;
{
// NOMEM: return error
dba_error(31);
}
file_list->desc = fil->fil_desc;
file_list->open_files_next = 0;
if (tddba->head_of_files_list == 0)
tddba->head_of_files_list = file_list;
else
{
file_list->open_files_next = tddba->head_of_files_list;
tddba->head_of_files_list = file_list;
}
return fil;
} }
@ -1945,17 +1842,9 @@ static const pag* db_read( SLONG page_number, bool ok_enc)
tddba->page_number = page_number; tddba->page_number = page_number;
dba_fil* fil;
for (fil = tddba->files; page_number > (SLONG) fil->fil_max_page && fil->fil_next;)
{
fil = fil->fil_next;
}
page_number -= fil->fil_min_page - fil->fil_fudge;
LARGE_INTEGER liOffset; LARGE_INTEGER liOffset;
liOffset.QuadPart = UInt32x32To64((DWORD) page_number, (DWORD) tddba->page_size); liOffset.QuadPart = UInt32x32To64((DWORD) page_number, (DWORD) tddba->page_size);
if (SetFilePointer(fil->fil_desc, (LONG) liOffset.LowPart, &liOffset.HighPart, FILE_BEGIN) == if (SetFilePointer(tddba->file->fil_desc, (LONG) liOffset.LowPart, &liOffset.HighPart, FILE_BEGIN) ==
(DWORD) -1) (DWORD) -1)
{ {
int lastError = GetLastError(); int lastError = GetLastError();
@ -1968,7 +1857,7 @@ static const pag* db_read( SLONG page_number, bool ok_enc)
} }
SLONG actual_length; SLONG actual_length;
if (!ReadFile( fil->fil_desc, if (!ReadFile( tddba->file->fil_desc,
tddba->global_buffer, tddba->global_buffer,
tddba->page_size, tddba->page_size,
reinterpret_cast<LPDWORD>(&actual_length), reinterpret_cast<LPDWORD>(&actual_length),
@ -2057,54 +1946,20 @@ static dba_fil* db_open(const char* file_name, USHORT file_length)
**************************************/ **************************************/
tdba* tddba = tdba::getSpecific(); tdba* tddba = tdba::getSpecific();
dba_fil* fil; const auto file = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1);
if (tddba->files)
{
for (fil = tddba->files; fil->fil_next; fil = fil->fil_next)
;
fil->fil_next = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1);
fil->fil_next->fil_min_page = fil->fil_max_page + 1;
fil = fil->fil_next;
}
else
{
// empty list
fil = tddba->files = (dba_fil*) alloc(sizeof(dba_fil) + file_length + 1); strcpy(file->fil_string, file_name);
fil->fil_min_page = 0L; file->fil_length = file_length;
}
fil->fil_next = NULL; if ((file->fil_desc = os_utils::open(file_name, O_RDONLY)) == -1)
strcpy(fil->fil_string, file_name);
fil->fil_length = file_length;
fil->fil_fudge = 0;
fil->fil_max_page = 0L;
if ((fil->fil_desc = os_utils::open(file_name, O_RDONLY)) == -1)
{ {
tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 29, SafeArg() << file_name); tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 29, SafeArg() << file_name);
// msg 29: Can't open database file %s // msg 29: Can't open database file %s
db_error(errno); db_error(errno);
} }
open_files* file_list = FB_NEW_POOL(*getDefaultMemoryPool()) open_files; tddba->file = file;
if (!file_list) return file;
{
// NOMEM: return error
dba_error(31);
}
file_list->desc = fil->fil_desc;
file_list->open_files_next = 0;
if (tddba->head_of_files_list == 0)
tddba->head_of_files_list = file_list;
else
{
file_list->open_files_next = tddba->head_of_files_list;
tddba->head_of_files_list = file_list;
}
return fil;
} }
@ -2127,15 +1982,8 @@ static const pag* db_read( SLONG page_number, bool ok_enc)
tddba->page_number = page_number; tddba->page_number = page_number;
dba_fil* fil;
for (fil = tddba->files; page_number > (SLONG) fil->fil_max_page && fil->fil_next;)
{
fil = fil->fil_next;
}
page_number -= fil->fil_min_page - fil->fil_fudge;
const FB_UINT64 offset = ((FB_UINT64) page_number) * ((FB_UINT64) tddba->page_size); const FB_UINT64 offset = ((FB_UINT64) page_number) * ((FB_UINT64) tddba->page_size);
if (os_utils::lseek (fil->fil_desc, offset, 0) == -1) if (os_utils::lseek (tddba->file->fil_desc, offset, 0) == -1)
{ {
tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg()); tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg());
// msg 30: Can't read a database page // msg 30: Can't read a database page
@ -2145,7 +1993,7 @@ static const pag* db_read( SLONG page_number, bool ok_enc)
USHORT length = tddba->page_size; USHORT length = tddba->page_size;
for (SCHAR* p = (SCHAR *) tddba->global_buffer; length > 0;) for (SCHAR* p = (SCHAR *) tddba->global_buffer; length > 0;)
{ {
const int l = read(fil->fil_desc, p, length); const int l = read(tddba->file->fil_desc, p, length);
if (l < 0) if (l < 0)
{ {
tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg()); tddba->uSvc->getStatusAccessor().setServiceStatus(GSTAT_MSG_FAC, 30, SafeArg());

View File

@ -231,17 +231,6 @@ void PPG_print_header(const header_page* header, bool nocreation, Firebird::Util
uSvc->printf(false, "\tRoot file name:\t\t%s\n", temp); uSvc->printf(false, "\tRoot file name:\t\t%s\n", temp);
break; break;
case HDR_file:
memcpy(temp, p + 2, p[1]);
temp[p[1]] = '\0';
uSvc->printf(false, "\tContinuation file:\t\t%s\n", temp);
break;
case HDR_last_page:
memcpy(&number, p + 2, sizeof(number));
uSvc->printf(false, "\tLast logical page:\t\t%ld\n", number);
break;
case HDR_sweep_interval: case HDR_sweep_interval:
memcpy(&number, p + 2, sizeof(number)); memcpy(&number, p + 2, sizeof(number));
uSvc->printf(false, "\tSweep interval:\t\t%ld\n", number); uSvc->printf(false, "\tSweep interval:\t\t%ld\n", number);

View File

@ -63,7 +63,6 @@ static void format_index_root(index_root_page*, int, SSHORT, SSHORT);
static void format_pointer(pointer_page*, int, SSHORT, SSHORT, bool, SSHORT, const SLONG*); static void format_pointer(pointer_page*, int, SSHORT, SSHORT, bool, SSHORT, const SLONG*);
static void format_pip(page_inv_page*, int, int); static void format_pip(page_inv_page*, int, int);
static void format_tip(tx_inv_page*, int, SLONG); static void format_tip(tx_inv_page*, int, SLONG);
static void get_next_file(rbdb*, header_page*);
static void get_range(TEXT***, const TEXT* const* const, ULONG*, ULONG*); static void get_range(TEXT***, const TEXT* const* const, ULONG*, ULONG*);
static void get_switch(TEXT**, swc*); static void get_switch(TEXT**, swc*);
static header_page* open_database(rbdb*, ULONG); static header_page* open_database(rbdb*, ULONG);
@ -197,8 +196,7 @@ int main( int argc, char *argv[])
rbdb = (rbdb*) RBDB_alloc((SLONG) (sizeof(struct rbdb) + strlen(db_in))); rbdb = (rbdb*) RBDB_alloc((SLONG) (sizeof(struct rbdb) + strlen(db_in)));
strcpy(rbdb->rbdb_file.fil_name, db_in); strcpy(rbdb->rbdb_file.fil_name, db_in);
rbdb->rbdb_file.fil_length = strlen(db_in); rbdb->rbdb_file.fil_length = strlen(db_in);
if (header = open_database(rbdb, pg_size)) header = open_database(rbdb, pg_size);
get_next_file(rbdb, header);
// some systems don't care for this write sharing stuff... // some systems don't care for this write sharing stuff...
if (rbdb && (sw_dump_tips || sw_dump_pages)) if (rbdb && (sw_dump_tips || sw_dump_pages))
@ -210,7 +208,6 @@ int main( int argc, char *argv[])
} }
} }
gdbb = &tdbb_struct; gdbb = &tdbb_struct;
gdbb->tdbb_database = &dbb_struct; gdbb->tdbb_database = &dbb_struct;
gdbb->tdbb_transaction = &dull; gdbb->tdbb_transaction = &dull;
@ -252,17 +249,15 @@ int main( int argc, char *argv[])
fclose(dbg_file); fclose(dbg_file);
if (rbdb) if (rbdb)
{
RBDB_close(rbdb); RBDB_close(rbdb);
while (rbdb)
{
rbdb* const next_db = rbdb->rbdb_next;
if (rbdb->rbdb_buffer1) if (rbdb->rbdb_buffer1)
gds__free(rbdb->rbdb_buffer1); gds__free(rbdb->rbdb_buffer1);
if (rbdb->rbdb_buffer2) if (rbdb->rbdb_buffer2)
gds__free(rbdb->rbdb_buffer2); gds__free(rbdb->rbdb_buffer2);
gds__free(rbdb); gds__free(rbdb);
rbdb = next_db;
} }
return 0; return 0;
@ -332,7 +327,6 @@ void RBDB_close( rbdb* rbdb)
* Functional description * Functional description
* *
**************************************/ **************************************/
for (; rbdb; rbdb = rbdb->rbdb_next)
close(rbdb->rbdb_file.fil_file); close(rbdb->rbdb_file.fil_file);
} }
@ -732,36 +726,6 @@ static void format_tip( tx_inv_page* page, int page_size, SLONG next_page)
} }
static void get_next_file( rbdb* rbdb, header_page* header)
{
/**************************************
*
* g e t _ n e x t _ f i l e
*
**************************************
*
* Functional description
* If there's another file as part of
* this database, get it now.
*
**************************************/
rbdb** next = &rbdb->rbdb_next;
const UCHAR* p = header->hdr_data;
for (const UCHAR* const end = p + header->hdr_page_size; p < end && *p != HDR_end; p += 2 + p[1])
{
if (*p == HDR_file)
{
rbdb* next_rbdb = (rbdb*) RBDB_alloc(sizeof(struct rbdb) + (SSHORT) p[1]);
next_rbdb->rbdb_file.fil_length = (SSHORT) p[1];
strncpy(next_rbdb->rbdb_file.fil_name, p + 2, (SSHORT) p[1]);
*next = next_rbdb;
next = &next_rbdb->rbdb_next;
break;
}
}
}
static void get_range(TEXT*** argv, const TEXT* const* const end, ULONG* lower, ULONG* upper) static void get_range(TEXT*** argv, const TEXT* const* const end, ULONG* lower, ULONG* upper)
{ {
/************************************** /**************************************