Skip to content

Commit b90c02f

Browse files
committed
Fixed bug #7873 : Wrong memory buffer alignment and IO buffer size when working in direct IO mode (#7890)
1 parent dd71073 commit b90c02f

File tree

13 files changed

+137
-121
lines changed

13 files changed

+137
-121
lines changed

src/common/classes/array.h

+10
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,16 @@ class Array : protected Storage
409409
return data;
410410
}
411411

412+
// prepare array to be used as a buffer of capacity bytes aligned on given alignment
413+
T* getAlignedBuffer(const size_type capacityL, const size_type alignL)
414+
{
415+
static_assert(sizeof(T) == 1, "sizeof(T) != 1");
416+
417+
ensureCapacity(capacityL + alignL, false);
418+
count = capacityL + alignL;
419+
return FB_ALIGN(data, alignL);
420+
}
421+
412422
// clear array and release dinamically allocated memory
413423
void free()
414424
{

src/jrd/CryptoManager.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,9 @@ namespace Jrd {
201201
Jrd::BufferDesc bdb(bcb);
202202
bdb.bdb_page = Jrd::HEADER_PAGE_NUMBER;
203203

204-
UCHAR* h = FB_NEW_POOL(*Firebird::MemoryPool::getContextPool()) UCHAR[dbb->dbb_page_size + PAGE_ALIGNMENT];
204+
UCHAR* h = FB_NEW_POOL(*MemoryPool::getContextPool()) UCHAR[dbb->dbb_page_size + dbb->getIOBlockSize()];
205205
buffer.reset(h);
206-
h = FB_ALIGN(h, PAGE_ALIGNMENT);
206+
h = FB_ALIGN(h, dbb->getIOBlockSize());
207207
bdb.bdb_buffer = (Ods::pag*) h;
208208

209209
Jrd::FbStatusVector* const status = tdbb->tdbb_status_vector;

src/jrd/CryptoManager.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -312,16 +312,16 @@ class CryptoManager final : public Firebird::PermanentStorage, public BarSync::I
312312
public:
313313
operator Ods::pag*()
314314
{
315-
return reinterpret_cast<Ods::pag*>(FB_ALIGN(buf, PAGE_ALIGNMENT));
315+
return reinterpret_cast<Ods::pag*>(buf);
316316
}
317317

318318
Ods::pag* operator->()
319319
{
320-
return reinterpret_cast<Ods::pag*>(FB_ALIGN(buf, PAGE_ALIGNMENT));
320+
return reinterpret_cast<Ods::pag*>(buf);
321321
}
322322

323323
private:
324-
char buf[MAX_PAGE_SIZE + PAGE_ALIGNMENT - 1];
324+
alignas(DIRECT_IO_BLOCK_SIZE) char buf[MAX_PAGE_SIZE];
325325
};
326326

327327
class DbInfo;

src/jrd/Database.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ namespace Jrd
5555
return pageSpace->onRawDevice();
5656
}
5757

58+
ULONG Database::getIOBlockSize() const
59+
{
60+
if ((dbb_flags & DBB_no_fs_cache) || onRawDevice())
61+
return DIRECT_IO_BLOCK_SIZE;
62+
63+
return PAGE_ALIGNMENT;
64+
}
65+
5866
AttNumber Database::generateAttachmentId()
5967
{
6068
fb_assert(dbb_tip_cache);

src/jrd/Database.h

+3
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,9 @@ class Database : public pool_alloc<type_dbb>
551551
// returns an unique ID string for a database file
552552
const Firebird::string& getUniqueFileId();
553553

554+
// returns the minimum IO block size
555+
ULONG getIOBlockSize() const;
556+
554557
#ifdef DEV_BUILD
555558
// returns true if main lock is in exclusive state
556559
bool locked() const

src/jrd/jrd.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -7562,11 +7562,17 @@ static JAttachment* create_attachment(const PathName& alias_name,
75627562

75637563
static void check_single_maintenance(thread_db* tdbb)
75647564
{
7565-
UCHAR spare_memory[RAW_HEADER_SIZE + PAGE_ALIGNMENT];
7566-
UCHAR* header_page_buffer = FB_ALIGN(spare_memory, PAGE_ALIGNMENT);
7565+
Database* const dbb = tdbb->getDatabase();
7566+
7567+
const ULONG ioBlockSize = dbb->getIOBlockSize();
7568+
const ULONG headerSize = MAX(RAW_HEADER_SIZE, ioBlockSize);
7569+
7570+
HalfStaticArray<UCHAR, RAW_HEADER_SIZE + PAGE_ALIGNMENT> temp;
7571+
UCHAR* header_page_buffer = temp.getAlignedBuffer(headerSize, ioBlockSize);
7572+
75677573
Ods::header_page* const header_page = reinterpret_cast<Ods::header_page*>(header_page_buffer);
75687574

7569-
PIO_header(tdbb, header_page_buffer, RAW_HEADER_SIZE);
7575+
PIO_header(tdbb, header_page_buffer, headerSize);
75707576

75717577
if ((header_page->hdr_flags & Ods::hdr_shutdown_mask) == Ods::hdr_shutdown_single)
75727578
{

src/jrd/nbak.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -899,17 +899,17 @@ void BackupManager::setForcedWrites(const bool forceWrite, const bool notUseFSCa
899899

900900
BackupManager::BackupManager(thread_db* tdbb, Database* _database, int ini_state) :
901901
dbCreating(false), database(_database), diff_file(NULL), alloc_table(NULL),
902-
last_allocated_page(0), current_scn(0), diff_name(*_database->dbb_permanent),
902+
last_allocated_page(0), temp_buffers_space(*database->dbb_permanent),
903+
current_scn(0), diff_name(*database->dbb_permanent),
903904
explicit_diff_name(false), flushInProgress(false), shutDown(false), allocIsValid(false),
904905
master(false), stateBlocking(false),
905906
stateLock(FB_NEW_POOL(*database->dbb_permanent) NBackupStateLock(tdbb, *database->dbb_permanent, this)),
906907
allocLock(FB_NEW_POOL(*database->dbb_permanent) NBackupAllocLock(tdbb, *database->dbb_permanent, this))
907908
{
908909
// Allocate various database page buffers needed for operation
909-
temp_buffers_space = FB_NEW_POOL(*database->dbb_permanent) BYTE[database->dbb_page_size * 3 + PAGE_ALIGNMENT];
910910
// Align it at sector boundary for faster IO (also guarantees correct alignment for ULONG later)
911-
BYTE* temp_buffers = reinterpret_cast<BYTE*>(FB_ALIGN(temp_buffers_space, PAGE_ALIGNMENT));
912-
memset(temp_buffers, 0, database->dbb_page_size * 3);
911+
UCHAR* temp_buffers = reinterpret_cast<UCHAR*>
912+
(temp_buffers_space.getAlignedBuffer(database->dbb_page_size * 3, database->getIOBlockSize()));
913913

914914
backup_state = ini_state;
915915

@@ -925,7 +925,6 @@ BackupManager::~BackupManager()
925925
delete stateLock;
926926
delete allocLock;
927927
delete alloc_table;
928-
delete[] temp_buffers_space;
929928
}
930929

931930
void BackupManager::setDifference(thread_db* tdbb, const char* filename)

src/jrd/nbak.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ class BackupManager
493493
AllocItemTree* alloc_table; // Cached allocation table of pages in difference file
494494
USHORT backup_state;
495495
ULONG last_allocated_page; // Last physical page allocated in the difference file
496-
BYTE *temp_buffers_space;
496+
Firebird::Array<UCHAR> temp_buffers_space;
497497
ULONG *alloc_buffer, *empty_buffer, *spare_buffer;
498498
ULONG current_scn;
499499
Firebird::PathName diff_name;

src/jrd/ods.h

+5
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,11 @@ Firebird::string pagtype(UCHAR type);
918918
// alignment for raw page access
919919
const USHORT PAGE_ALIGNMENT = 1024;
920920

921+
// alignment and IO block size/offset multiplier for non-buffered file access
922+
const ULONG DIRECT_IO_BLOCK_SIZE = 4096;
923+
924+
static_assert(MIN_PAGE_SIZE >= DIRECT_IO_BLOCK_SIZE, "check DIRECT_IO_BLOCK_SIZE");
925+
921926
// size of raw I/O operation for header page
922927
const USHORT RAW_HEADER_SIZE = 1024; // ROUNDUP(HDR_SIZE, PAGE_ALIGNMENT);
923928
//static_assert(RAW_HEADER_SIZE >= HDR_SIZE, "RAW_HEADER_SIZE is less than HDR_SIZE");

src/jrd/pag.cpp

+8-6
Original file line numberDiff line numberDiff line change
@@ -1261,10 +1261,13 @@ void PAG_header_init(thread_db* tdbb)
12611261
// and unit of transfer is a multiple of physical disk
12621262
// sector for raw disk access.
12631263

1264-
UCHAR temp_buffer[RAW_HEADER_SIZE + PAGE_ALIGNMENT];
1265-
UCHAR* const temp_page = FB_ALIGN(temp_buffer, PAGE_ALIGNMENT);
1264+
const ULONG ioBlockSize = dbb->getIOBlockSize();
1265+
const ULONG headerSize = MAX(RAW_HEADER_SIZE, ioBlockSize);
12661266

1267-
PIO_header(tdbb, temp_page, RAW_HEADER_SIZE);
1267+
HalfStaticArray<UCHAR, RAW_HEADER_SIZE + PAGE_ALIGNMENT> temp;
1268+
UCHAR* const temp_page = temp.getAlignedBuffer(headerSize, ioBlockSize);
1269+
1270+
PIO_header(tdbb, temp_page, headerSize);
12681271
const header_page* header = (header_page*) temp_page;
12691272

12701273
if (header->hdr_header.pag_type != pag_header || header->hdr_sequence)
@@ -1377,8 +1380,7 @@ void PAG_init2(thread_db* tdbb, USHORT shadow_number)
13771380
// the temporary page buffer for raw disk access.
13781381

13791382
Array<UCHAR> temp;
1380-
UCHAR* const temp_page =
1381-
FB_ALIGN(temp.getBuffer(dbb->dbb_page_size + PAGE_ALIGNMENT), PAGE_ALIGNMENT);
1383+
UCHAR* const temp_page = temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize());
13821384

13831385
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
13841386
jrd_file* file = pageSpace->file;
@@ -2603,7 +2605,7 @@ ULONG PAG_page_count(thread_db* tdbb)
26032605
Database* const dbb = tdbb->getDatabase();
26042606
Array<UCHAR> temp;
26052607
page_inv_page* pip = reinterpret_cast<Ods::page_inv_page*>
2606-
(FB_ALIGN(temp.getBuffer(dbb->dbb_page_size + PAGE_ALIGNMENT), PAGE_ALIGNMENT));
2608+
(temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize()));
26072609

26082610
PageSpace* pageSpace = dbb->dbb_page_manager.findPageSpace(DB_PAGE_SPACE);
26092611
fb_assert(pageSpace);

src/jrd/sdw.cpp

+61-81
Original file line numberDiff line numberDiff line change
@@ -186,98 +186,80 @@ int SDW_add_file(thread_db* tdbb, const TEXT* file_name, SLONG start, USHORT sha
186186
// and set up to release it in case of error. Align
187187
// the spare page buffer for raw disk access.
188188

189-
SCHAR* const spare_buffer =
190-
FB_NEW_POOL(*tdbb->getDefaultPool()) char[dbb->dbb_page_size + PAGE_ALIGNMENT];
191-
// And why doesn't the code check that the allocation succeeds?
189+
Array<UCHAR> temp;
190+
UCHAR* const spare_page = temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize());
191+
192+
// create the header using the spare_buffer
193+
194+
header_page* header = (header_page*) spare_page;
195+
header->hdr_header.pag_type = pag_header;
196+
header->hdr_sequence = sequence;
197+
header->hdr_page_size = dbb->dbb_page_size;
198+
header->hdr_data[0] = HDR_end;
199+
header->hdr_end = HDR_SIZE;
200+
header->hdr_next_page = 0;
201+
202+
// fool PIO_write into writing the scratch page into the correct place
203+
BufferDesc temp_bdb(dbb->dbb_bcb);
204+
temp_bdb.bdb_page = next->fil_min_page;
205+
temp_bdb.bdb_buffer = (PAG) header;
206+
header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum();
207+
// It's header, never encrypted
208+
if (!PIO_write(tdbb, shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
209+
return 0;
192210

193-
SCHAR* spare_page = FB_ALIGN(spare_buffer, PAGE_ALIGNMENT);
211+
next->fil_fudge = 1;
194212

195-
try {
213+
// Update the previous header page to point to new file --
214+
// we can use the same header page, suitably modified,
215+
// because they all look pretty much the same at this point
216+
217+
/*******************
218+
Fix for bug 7925. drop_gdb wan not dropping secondary file in
219+
multi-shadow files. The structure was not being filled with the
220+
info. Commented some code so that the structure will always be filled.
196221
197-
// create the header using the spare_buffer
222+
-Sudesh 07/06/95
223+
224+
The original code :
225+
===
226+
if (shadow_file == file)
227+
copy_header(tdbb);
228+
else
229+
===
230+
************************/
198231

199-
header_page* header = (header_page*) spare_page;
200-
header->hdr_header.pag_type = pag_header;
201-
header->hdr_sequence = sequence;
202-
header->hdr_page_size = dbb->dbb_page_size;
232+
// Temporarly reverting the change ------- Sudesh 07/07/95 *******
233+
234+
if (shadow_file == file)
235+
{
236+
copy_header(tdbb);
237+
}
238+
else
239+
{
240+
--start;
203241
header->hdr_data[0] = HDR_end;
204242
header->hdr_end = HDR_SIZE;
205243
header->hdr_next_page = 0;
206244

207-
// fool PIO_write into writing the scratch page into the correct place
208-
BufferDesc temp_bdb(dbb->dbb_bcb);
209-
temp_bdb.bdb_page = next->fil_min_page;
210-
temp_bdb.bdb_buffer = (PAG) header;
245+
PAG_add_header_entry(tdbb, header, HDR_file, static_cast<USHORT>(strlen(file_name)),
246+
reinterpret_cast<const UCHAR*>(file_name));
247+
PAG_add_header_entry(tdbb, header, HDR_last_page, sizeof(start),
248+
reinterpret_cast<const UCHAR*>(&start));
249+
file->fil_fudge = 0;
250+
temp_bdb.bdb_page = file->fil_min_page;
211251
header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum();
212252
// It's header, never encrypted
213253
if (!PIO_write(tdbb, shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
214-
{
215-
delete[] spare_buffer;
216254
return 0;
217-
}
218-
next->fil_fudge = 1;
219-
220-
// Update the previous header page to point to new file --
221-
// we can use the same header page, suitably modified,
222-
// because they all look pretty much the same at this point
223-
224-
/*******************
225-
Fix for bug 7925. drop_gdb wan not dropping secondary file in
226-
multi-shadow files. The structure was not being filled with the
227-
info. Commented some code so that the structure will always be filled.
228-
229-
-Sudesh 07/06/95
230-
231-
The original code :
232-
===
233-
if (shadow_file == file)
234-
copy_header(tdbb);
235-
else
236-
===
237-
************************/
238-
239-
// Temporarly reverting the change ------- Sudesh 07/07/95 *******
240-
241-
if (shadow_file == file)
242-
{
243-
copy_header(tdbb);
244-
}
245-
else
246-
{
247-
--start;
248-
header->hdr_data[0] = HDR_end;
249-
header->hdr_end = HDR_SIZE;
250-
header->hdr_next_page = 0;
251-
252-
PAG_add_header_entry(tdbb, header, HDR_file, static_cast<USHORT>(strlen(file_name)),
253-
reinterpret_cast<const UCHAR*>(file_name));
254-
PAG_add_header_entry(tdbb, header, HDR_last_page, sizeof(start),
255-
reinterpret_cast<const UCHAR*>(&start));
256-
file->fil_fudge = 0;
257-
temp_bdb.bdb_page = file->fil_min_page;
258-
header->hdr_header.pag_pageno = temp_bdb.bdb_page.getPageNum();
259-
// It's header, never encrypted
260-
if (!PIO_write(tdbb, shadow_file, &temp_bdb, reinterpret_cast<Ods::pag*>(header), 0))
261-
{
262-
delete[] spare_buffer;
263-
return 0;
264-
}
265-
if (file->fil_min_page) {
266-
file->fil_fudge = 1;
267-
}
268-
}
269255

270256
if (file->fil_min_page) {
271257
file->fil_fudge = 1;
272258
}
259+
}
273260

274-
delete[] spare_buffer;
275-
276-
} // try
277-
catch (const Firebird::Exception&)
278-
{
279-
delete[] spare_buffer;
280-
throw;
261+
if (file->fil_min_page) {
262+
file->fil_fudge = 1;
281263
}
282264

283265
return sequence;
@@ -1004,9 +986,9 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name,
1004986
// catch errors: delete the shadow file if missing, and deallocate the spare buffer
1005987

1006988
shadow = NULL;
1007-
SLONG* const spare_buffer =
1008-
FB_NEW_POOL(*tdbb->getDefaultPool()) SLONG[(dbb->dbb_page_size + PAGE_ALIGNMENT) / sizeof(SLONG)];
1009-
UCHAR* spare_page = FB_ALIGN((UCHAR*) spare_buffer, PAGE_ALIGNMENT);
989+
990+
Array<UCHAR> temp;
991+
UCHAR* const spare_page = temp.getAlignedBuffer(dbb->dbb_page_size, dbb->getIOBlockSize());
1010992

1011993
WIN window(DB_PAGE_SPACE, -1);
1012994
jrd_file* shadow_file = 0;
@@ -1087,8 +1069,6 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name,
10871069

10881070
PAG_init2(tdbb, shadow_number);
10891071

1090-
delete[] spare_buffer;
1091-
10921072
} // try
10931073
catch (const Firebird::Exception& ex)
10941074
{
@@ -1101,7 +1081,7 @@ void SDW_start(thread_db* tdbb, const TEXT* file_name,
11011081
PIO_close(shadow_file);
11021082
delete shadow_file;
11031083
}
1104-
delete[] spare_buffer;
1084+
11051085
if ((file_flags & FILE_manual) && !delete_files) {
11061086
ERR_post(Arg::Gds(isc_shadow_missing) << Arg::Num(shadow_number));
11071087
}

src/utilities/gstat/dba.epp

+10-5
Original file line numberDiff line numberDiff line change
@@ -615,8 +615,8 @@ int gstat(Firebird::UtilSvc* uSvc)
615615

616616
dba_fil* current = db_open(fileName.c_str(), fileName.length());
617617

618-
SCHAR temp[RAW_HEADER_SIZE];
619-
tddba->page_size = sizeof(temp);
618+
alignas(DIRECT_IO_BLOCK_SIZE) SCHAR temp[MAX(RAW_HEADER_SIZE, DIRECT_IO_BLOCK_SIZE)];
619+
tddba->page_size = MAX(RAW_HEADER_SIZE, DIRECT_IO_BLOCK_SIZE);
620620
tddba->global_buffer = (pag*) temp;
621621
tddba->page_number = -1;
622622
const header_page* header = (const header_page*) db_read((SLONG) 0);
@@ -642,9 +642,14 @@ int gstat(Firebird::UtilSvc* uSvc)
642642
tddba->page_size = header->hdr_page_size;
643643
tddba->dp_per_pp = Ods::dataPagesPerPP(tddba->page_size);
644644
tddba->max_records = Ods::maxRecsPerDP(tddba->page_size);
645-
tddba->buffer1 = (pag*) alloc(tddba->page_size);
646-
tddba->buffer2 = (pag*) alloc(tddba->page_size);
647-
tddba->global_buffer = (pag*) alloc(tddba->page_size);
645+
{ // scope
646+
char* buff = alloc(tddba->page_size * 3 + DIRECT_IO_BLOCK_SIZE);
647+
buff = FB_ALIGN(buff, DIRECT_IO_BLOCK_SIZE);
648+
649+
tddba->buffer1 = (pag*) buff;
650+
tddba->buffer2 = (pag*) (buff + tddba->page_size);
651+
tddba->global_buffer = (pag*) (buff + tddba->page_size * 2);
652+
}
648653
tddba->page_number = -1;
649654

650655
// gather continuation files

0 commit comments

Comments
 (0)