diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2021-06-14 15:41:37 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2021-06-14 18:13:40 +0300 |
commit | d69a106c04a6a7abe65e9150e5bf211d35a757f0 (patch) | |
tree | ef6110350999bc33523d52c9bb424c8dc9d03510 | |
parent | 72af65ca06eeec98266fce0c474d5bfbc3d91951 (diff) | |
download | gdbm-d69a106c04a6a7abe65e9150e5bf211d35a757f0.tar.gz gdbm-d69a106c04a6a7abe65e9150e5bf211d35a757f0.tar.bz2 |
Enable pre-reading the memory mapped regions on request.
The commit 4fb2326a4a introduced pre-reading of memory mapped
regions. While speeding up searches, it has a negative impact
on write operatons, since every remapping effectively re-reads
the entire database. See https://github.com/Perl/perl5/issues/18884
for details.
* NEWS: Document changes.
* doc/gdbm.texi: Document the GDBM_PREREAD flag.
* src/gdbm.h.in (GDBM_PREREAD): New flag.
* src/gdbmdefs.h (gdbm_file_info): New member: mmap_preread.
* src/gdbmopen.c (gdbm_fd_open): Set mmap_preread if requested.
* src/gdbmsetopt.c (setopt_gdbm_getflags): Report GDBM_PREREAD
flag, if dbf->mmap_preread is set.
* src/mmap.c (_gdbm_internal_remap): Use pre-fault reading only
if dbf->mmap_preread is set.
-rw-r--r-- | NEWS | 12 | ||||
-rw-r--r-- | doc/gdbm.texi | 16 | ||||
-rw-r--r-- | src/gdbm.h.in | 21 | ||||
-rw-r--r-- | src/gdbmdefs.h | 1 | ||||
-rw-r--r-- | src/gdbmopen.c | 1 | ||||
-rw-r--r-- | src/gdbmsetopt.c | 2 | ||||
-rw-r--r-- | src/mmap.c | 15 |
7 files changed, 52 insertions, 16 deletions
@@ -1,4 +1,4 @@ -GNU dbm NEWS -- history of user-visible changes. 2021-03-23 +GNU dbm NEWS -- history of user-visible changes. 2021-06-14 Copyright (C) 1990-2021 Free Software Foundation, Inc. See the end of file for copying conditions. @@ -12,6 +12,16 @@ The bucket cache support has been rewritten from scratch. The new bucket cache code provides for significant speed up of search operations. +* Change mmap prereading strategy + +Pre-reading of the memory mapper regions, introduced in version 1.19 +can be advantageous only when doing intensive look-ups on a read-only +database. It degrades performance otherwise, especially if doing +multiple inserts. Therefore, this version introduces a new flag +to gdbm_open: GDBM_PREREAD. When given, it enables pre-reading of +memory mapped regions. + +See https://github.com/Perl/perl5/issues/18884 for details. Version 1.19 - 2020-12-23 diff --git a/doc/gdbm.texi b/doc/gdbm.texi index 5f42ced..1aec85a 100644 --- a/doc/gdbm.texi +++ b/doc/gdbm.texi @@ -411,6 +411,22 @@ locking separately. @item GDBM_NOMMAP Disable memory mapping mechanism. This degrades performance. +@kwindex GDBM_PREREAD +@item GDBM_PREREAD +When mapping GDBM file to memory, read its contents immediately, +instead of when needed (@dfn{prefault reading}). This can be +advantageous if you open a @emph{read-only} database and are going to +do a lot of look-ups on it. In this case entire database will be +pre-read and look-ups will operate on an in-memory copy. In the +contrast, @code{GDBM_PREREAD} should not be used if you open a +database (even in read-only mode) only to do a couple of look-ups. +Finally, never use @code{GDBM_PREREAD} when opening a database for +updates, especially for inserts: this will degrade performance. + +This flag has no effect if @code{GDBM_NOMMAP} is given, or if the +operating system does not support prefault reading. It is known +to work on Linux and FreeBSD kernels. + @kwindex GDBM_BSEXACT @item GDBM_BSEXACT If this flag is set and the requested @var{block_size} cannot be used diff --git a/src/gdbm.h.in b/src/gdbm.h.in index 1cd54c4..a916457 100644 --- a/src/gdbm.h.in +++ b/src/gdbm.h.in @@ -44,16 +44,17 @@ extern "C" { # define GDBM_NEWDB 3 /* A writer. Always create a new db. */ # define GDBM_OPENMASK 7 /* Mask for the above. */ -# define GDBM_FAST 0x010 /* Write fast! => No fsyncs. OBSOLETE. */ -# define GDBM_SYNC 0x020 /* Sync operations to the disk. */ -# define GDBM_NOLOCK 0x040 /* Don't do file locking operations. */ -# define GDBM_NOMMAP 0x080 /* Don't use mmap(). */ -# define GDBM_CLOEXEC 0x100 /* Close the underlying fd on exec(3) */ -# define GDBM_BSEXACT 0x200 /* Don't adjust block_size. Bail out with +# define GDBM_FAST 0x0010 /* Write fast! => No fsyncs. OBSOLETE. */ +# define GDBM_SYNC 0x0020 /* Sync operations to the disk. */ +# define GDBM_NOLOCK 0x0040 /* Don't do file locking operations. */ +# define GDBM_NOMMAP 0x0080 /* Don't use mmap(). */ +# define GDBM_CLOEXEC 0x0100 /* Close the underlying fd on exec(3) */ +# define GDBM_BSEXACT 0x0200 /* Don't adjust block_size. Bail out with GDBM_BLOCK_SIZE_ERROR error if unable to set it. */ -# define GDBM_CLOERROR 0x400 /* Only for gdbm_fd_open: close fd on error. */ -# define GDBM_XVERIFY 0x800 /* Additional consistency checks. */ +# define GDBM_CLOERROR 0x0400 /* Only for gdbm_fd_open: close fd on error. */ +# define GDBM_XVERIFY 0x0800 /* Additional consistency checks. */ +# define GDBM_PREREAD 0x1000 /* Parameters to gdbm_store for simple insertion or replacement in the case that the key is already in the database. */ @@ -62,7 +63,7 @@ extern "C" { /* Parameters to gdbm_setopt, specifing the type of operation to perform. */ # define GDBM_SETCACHESIZE 1 /* Set the cache size. */ -# define GDBM_FASTMODE 2 /* Toggle fast mode. OBSOLETE. */ +# define GDBM_FASTMODE 2 /* Toggle fast mode. OBSOLETE. */ # define GDBM_SETSYNCMODE 3 /* Turn on or off sync operations. */ # define GDBM_SETCENTFREE 4 /* Keep all free blocks in the header. */ # define GDBM_SETCOALESCEBLKS 5 /* Attempt to coalesce free blocks. */ @@ -88,7 +89,7 @@ extern "C" { # define GDBM_CACHE_AUTO 0 typedef @GDBM_COUNT_T@ gdbm_count_t; - + /* The data and key structure. */ typedef struct { diff --git a/src/gdbmdefs.h b/src/gdbmdefs.h index e746ac3..a5daddd 100644 --- a/src/gdbmdefs.h +++ b/src/gdbmdefs.h @@ -272,6 +272,7 @@ struct gdbm_file_info off_t mapped_pos; /* Current offset in the region */ off_t mapped_off; /* Position in the file where the region begins */ + int mmap_preread :1; /* 1 if prefault reading is requested */ }; #define GDBM_DIR_COUNT(db) ((db)->header->dir_size / sizeof (off_t)) diff --git a/src/gdbmopen.c b/src/gdbmopen.c index 39ec928..8092432 100644 --- a/src/gdbmopen.c +++ b/src/gdbmopen.c @@ -556,6 +556,7 @@ gdbm_fd_open (int fd, const char *file_name, int block_size, #if HAVE_MMAP if (!(flags & GDBM_NOMMAP)) { + dbf->mmap_preread = (flags & GDBM_PREREAD) != 0; if (_gdbm_mapped_init (dbf) == 0) dbf->memory_mapping = TRUE; else diff --git a/src/gdbmsetopt.c b/src/gdbmsetopt.c index c6f2052..a49ea40 100644 --- a/src/gdbmsetopt.c +++ b/src/gdbmsetopt.c @@ -260,6 +260,8 @@ setopt_gdbm_getflags (GDBM_FILE dbf, void *optval, int optlen) flags |= GDBM_NOLOCK; if (!dbf->memory_mapping) flags |= GDBM_NOMMAP; + else if (dbf->mmap_preread) + flags |= GDBM_PREREAD; *(int*) optval = flags; } return 0; @@ -33,11 +33,11 @@ # endif # if defined(MAP_POPULATE) -# define GDBM_MMAP_FLAGS MAP_POPULATE +# define GDBM_MMAP_PREREAD MAP_POPULATE # elif defined(MAP_PREFAULT_READ) -# define GDBM_MMAP_FLAGS MAP_PREFAULT_READ +# define GDBM_MMAP_PREREAD MAP_PREFAULT_READ # else -# define GDBM_MMAP_FLAGS 0 +# define GDBM_MMAP_PREREAD 0 # endif /* Translate current offset in the mapped region into the absolute position */ @@ -82,6 +82,7 @@ int _gdbm_internal_remap (GDBM_FILE dbf, size_t size) { void *p; + int flags = MAP_SHARED; int prot = PROT_READ; size_t page_size = sysconf (_SC_PAGESIZE); @@ -100,9 +101,13 @@ _gdbm_internal_remap (GDBM_FILE dbf, size_t size) if (dbf->read_write) prot |= PROT_WRITE; + + if (dbf->mmap_preread) + { + flags |= GDBM_MMAP_PREREAD; + } - p = mmap (NULL, dbf->mapped_size, prot, MAP_SHARED | GDBM_MMAP_FLAGS, - dbf->desc, dbf->mapped_off); + p = mmap (NULL, dbf->mapped_size, prot, flags, dbf->desc, dbf->mapped_off); if (p == MAP_FAILED) { dbf->mapped_region = NULL; |