diff --git a/configure.ac b/configure.ac index ac17c6742d..0b6eb1ec7f 100644 --- a/configure.ac +++ b/configure.ac @@ -690,6 +690,7 @@ AC_CHECK_HEADERS(poll.h) AC_CHECK_HEADERS(langinfo.h) AC_CHECK_HEADERS(iconv.h) AC_CHECK_HEADERS(libio.h) +AC_CHECK_HEADERS(linux/falloc.h) dnl check for ICU presence AC_CHECK_HEADER(unicode/ucnv.h,,AC_MSG_ERROR(ICU support not found - please install development ICU package)) diff --git a/src/jrd/os/pio.h b/src/jrd/os/pio.h index 450c484a9b..e8f2d6a397 100644 --- a/src/jrd/os/pio.h +++ b/src/jrd/os/pio.h @@ -94,6 +94,7 @@ const USHORT FIL_force_write = 1; const USHORT FIL_no_fs_cache = 2; // not using file system cache const USHORT FIL_readonly = 4; // file opened in readonly mode const USHORT FIL_sh_write = 8; // file opened in shared write mode +const USHORT FIL_no_fast_extend = 16; // file not supports fast extending // Physical IO trace events diff --git a/src/jrd/os/posix/unix.cpp b/src/jrd/os/posix/unix.cpp index ef60314d14..413614e19e 100644 --- a/src/jrd/os/posix/unix.cpp +++ b/src/jrd/os/posix/unix.cpp @@ -45,6 +45,9 @@ #ifdef HAVE_AIO_H #include #endif +#ifdef HAVE_LINUX_FALLOC_H +#include +#endif #include "../jrd/jrd.h" #include "../jrd/os/pio.h" @@ -291,7 +294,7 @@ bool PIO_expand(const TEXT* file_name, USHORT file_length, TEXT* expanded_name, } -void PIO_extend(Database* dbb, jrd_file* /*main_file*/, const ULONG /*extPages*/, const USHORT /*pageSize*/) +void PIO_extend(Database* dbb, jrd_file* main_file, const ULONG extPages, const USHORT pageSize) { /************************************** * @@ -303,6 +306,56 @@ void PIO_extend(Database* dbb, jrd_file* /*main_file*/, const ULONG /*extPages*/ * Extend file by extPages pages of pageSize size. * **************************************/ + +#ifdef HAVE_LINUX_FALLOC_H + 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) + return; + + const ULONG extendBy = MIN(fileMaxPages - filePages + file->fil_fudge, leftPages); + + int r; + for (r = 0; r < IO_RETRY; r++) + { + int err = fallocate(file->fil_desc, 0, filePages * pageSize, extendBy * pageSize); + if (err == 0) + break; + + err = errno; + if (SYSCALL_INTERRUPTED(err)) + continue; + + if (err == EOPNOTSUPP || err == ENOSYS) + file->fil_flags |= FIL_no_fast_extend; + else + unix_error("fallocate", file, isc_io_write_err); + return; + } + + if (r == IO_RETRY) + { +#ifdef DEV_BUILD + fprintf(stderr, "PIO_extend: retry count exceeded\n"); + fflush(stderr); +#endif + unix_error("fallocate_retry", file, isc_io_write_err); + return; + } + + leftPages -= extendBy; + } + } +#else + main_file->fil_flags |= FIL_no_fast_extend; +#endif // HAVE_LINUX_FALLOC_H + // not implemented return; } diff --git a/src/jrd/pag.cpp b/src/jrd/pag.cpp index 72bdf0f515..935fcaefc1 100644 --- a/src/jrd/pag.cpp +++ b/src/jrd/pag.cpp @@ -640,7 +640,7 @@ PAG PAG_allocate(thread_db* tdbb, WIN* window) // At this point we ensure database has at least "initialized" pages // allocated. To avoid file growth by few pages when all this space // will be used, extend file up to initialized + next_init_pages now - pageSpace->extend(tdbb, initialized + next_init_pages); + pageSpace->extend(tdbb, initialized + next_init_pages, false); } break; // Found a page and successfully fake-ed it @@ -2039,7 +2039,7 @@ ULONG PageSpace::lastUsedPage(const Database* dbb) return pgSpace->lastUsedPage(); } -bool PageSpace::extend(thread_db* tdbb, const ULONG pageNum) +bool PageSpace::extend(thread_db* tdbb, const ULONG pageNum, const bool forceSize) { /************************************** * @@ -2051,12 +2051,16 @@ bool PageSpace::extend(thread_db* tdbb, const ULONG pageNum) * If "DatabaseGrowthIncrement" is less than MIN_EXTEND_BYTES then don't * extend file(s) * + * If forceSize is true, extend file up to pageNum pages (despite of value + * of "DatabaseGrowthIncrement") and don't make attempts to extend by less + * pages. + * **************************************/ fb_assert(dbb == tdbb->getDatabase()); const int MAX_EXTEND_BYTES = dbb->dbb_config->getDatabaseGrowthIncrement(); - if (pageNum < maxPageNumber || MAX_EXTEND_BYTES < MIN_EXTEND_BYTES) + if (pageNum < maxPageNumber || MAX_EXTEND_BYTES < MIN_EXTEND_BYTES && !forceSize) return true; if (pageNum >= maxAlloc()) @@ -2071,6 +2075,7 @@ bool PageSpace::extend(thread_db* tdbb, const ULONG pageNum) while (true) { + const ULONG oldMaxPageNumber = maxPageNumber; try { PIO_extend(dbb, file, extPages, dbb->dbb_page_size); @@ -2078,10 +2083,16 @@ bool PageSpace::extend(thread_db* tdbb, const ULONG pageNum) } catch (const status_exception&) { - if (extPages > reqPages) + if (extPages > reqPages && !forceSize) { - extPages = MAX(reqPages, extPages / 2); fb_utils::init_status(tdbb->tdbb_status_vector); + + // if file was extended, return, else try to extend by less pages + + if (oldMaxPageNumber < maxAlloc()) + return true; + + extPages = MAX(reqPages, extPages / 2); } else { diff --git a/src/jrd/pag.h b/src/jrd/pag.h index f1e8d204cc..24e00283bc 100644 --- a/src/jrd/pag.h +++ b/src/jrd/pag.h @@ -120,7 +120,7 @@ public: static ULONG lastUsedPage(const Database* dbb); // extend page space - bool extend(thread_db*, const ULONG); + bool extend(thread_db*, const ULONG, const bool); // get SCN's page number ULONG getSCNPageNum(ULONG sequence);