aboutsummaryrefslogtreecommitdiff
path: root/src/gdbmreorg.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2016-07-19 12:01:48 +0300
committerSergey Poznyakoff <gray@gnu.org>2016-07-19 12:58:16 +0300
commit85f1e72da83e3078e2ae1f78093ef0966e43cec1 (patch)
treeb00707979e9088d5f7b7880d438260eb063c9160 /src/gdbmreorg.c
parent8e83f209342e2b035bbb19efa87ec5295158ef65 (diff)
downloadgdbm-85f1e72da83e3078e2ae1f78093ef0966e43cec1.tar.gz
gdbm-85f1e72da83e3078e2ae1f78093ef0966e43cec1.tar.bz2
Implement gdbm_recover function
* configure.ac: Don't check for rename. * src/Makefile.am (libgdbm_la_SOURCES): Add recover.c * src/recover.c: New file. * src/bucket.c (_gdbm_get_bucket): Remove extra space before [ * src/err.c (prerror): Take additional argument (gdbm_perror): Print system errno if necessary. * src/gdbm.h.in (GDBM_CLOERROR): New flag. (gdbm_fd_open, gdbm_copy_meta): New proto. (gdbm_last_syserr,gdbm_db_strerror,gdbm_recover): New proto. (gdbm_syserr): New extern. (gdbm_recovery): New struct. (GDBM_RCVR_DEFAULT,GDBM_RCVR_ERRFUN) (GDBM_RCVR_MAX_FAILED_KEYS) (GDBM_RCVR_MAX_FAILED_BUCKETS) (GDBM_RCVR_MAX_FAILURES) (GDBM_RCVR_BACKUP): New flags. (GDBM_BACKUP_FAILED): New error code. * src/gdbmclose.c (gdbm_close): Work correctly if dbf->desc == -1. * src/gdbmcount.c (gdbm_count): Remove spurious sorting. Use _gdbm_next_bucket_dir for iterating over the buckets. * src/gdbmdefs.h (struct gdbm_file_info)<last_syserror> <last_errstr>: New members. * src/gdbmerrno.c (gdbm_set_errno): Set last_syserror as well. (gdbm_clear_error): Reset last_syserror. (gdbm_last_syserr): New function. (gdbm_errlist): New entry for GDBM_BACKUP_FAILED. (gdbm_db_strerror): New function. (gdbm_syserr): New global. * src/gdbmload.c (get_parms): Buffer can be NULL. * src/gdbmopen.c (gdbm_fd_open): New function. (gdbm_open): Rewrite as a wrapper over gdbm_fd_open. * src/gdbmreorg.c (gdbm_reorganize): Rewrite as a wrapper over gdbm_recover. * src/proto.h (_gdbm_next_bucket_dir): New proto. * src/gdbmtool.c: New command: recover. * tests/.gitignore: Add gtrecover * tests/gtrecover.c: New test program. * tests/Makefile.am: Build gtrecover
Diffstat (limited to 'src/gdbmreorg.c')
-rw-r--r--src/gdbmreorg.c189
1 files changed, 4 insertions, 185 deletions
diff --git a/src/gdbmreorg.c b/src/gdbmreorg.c
index 13fa7fc..e9b7742 100644
--- a/src/gdbmreorg.c
+++ b/src/gdbmreorg.c
@@ -19,35 +19,8 @@
/* Include system configuration before all else. */
#include "autoconf.h"
-
#include "gdbmdefs.h"
-#if !HAVE_RENAME
-
-/* Rename takes OLD_NAME and renames it as NEW_NAME. If it can not rename
- the file a non-zero value is returned. OLD_NAME is guaranteed to
- remain if it can't be renamed. It assumes NEW_NAME always exists (due
- to being used in gdbm). */
-
-static int
-_gdbm_rename (char *old_name, char *new_name)
-{
- if (unlink (new_name) != 0)
- return -1;
-
- if (link (old_name, new_name) != 0)
- return -1;
-
- unlink (old_name);
- return 0;
-
-}
-
-# define rename _gdbm_rename
-#endif
-
-
-
/* Reorganize the database. This requires creating a new file and inserting
all the elements in the old file DBF into the new file. The new file
is then renamed to the same name as the old file and DBF is updated to
@@ -58,165 +31,11 @@ _gdbm_rename (char *old_name, char *new_name)
int
gdbm_reorganize (GDBM_FILE dbf)
{
- GDBM_FILE new_dbf; /* The new file. */
- char *new_name; /* A temporary name. */
- int len; /* Used in new_name construction. */
- datum key, nextkey, data; /* For the sequential sweep. */
- struct stat fileinfo; /* Information about the file. */
- int index; /* Use in moving the bucket cache. */
-
+ gdbm_recovery rcvr;
+
/* Return immediately if the database needs recovery */
GDBM_ASSERT_CONSISTENCY (dbf, -1);
- /* Readers can not reorganize! */
- if (dbf->read_write == GDBM_READER)
- {
- gdbm_set_errno (dbf, GDBM_READER_CANT_REORGANIZE, FALSE);
- return -1;
- }
-
- /* Get the mode for the old file */
- if (fstat (dbf->desc, &fileinfo))
- {
- gdbm_set_errno (dbf, GDBM_FILE_STAT_ERROR, FALSE);
- return -1;
- }
-
- /* Initialize the gdbm_errno variable. */
- gdbm_set_errno (dbf, GDBM_NO_ERROR, FALSE);
-
- /* Construct new name for temporary file. */
- len = strlen (dbf->name);
- new_name = (char *) malloc (len + 3);
- if (new_name == NULL)
- {
- gdbm_set_errno (dbf, GDBM_MALLOC_ERROR, FALSE);
- return -1;
- }
- strcpy (&new_name[0], dbf->name);
- new_name[len+2] = 0;
- new_name[len+1] = '#';
- while ( (len > 0) && new_name[len-1] != '/')
- {
- new_name[len] = new_name[len-1];
- len -= 1;
- }
- new_name[len] = '#';
-
- /* Open the new database. */
- new_dbf = gdbm_open (new_name, dbf->header->block_size,
- GDBM_WRCREAT | (dbf->cloexec ? GDBM_CLOEXEC : 0),
- fileinfo.st_mode, dbf->fatal_err);
-
- if (new_dbf == NULL)
- {
- free (new_name);
- gdbm_set_errno (NULL, GDBM_REORGANIZE_FAILED, FALSE);
- return -1;
- }
-
-
- /* For each item in the old database, add an entry in the new. */
- key = gdbm_firstkey (dbf);
-
- while (key.dptr != NULL)
- {
- data = gdbm_fetch (dbf, key);
- if (data.dptr != NULL)
- {
- /* Add the data to the new file. */
- if (gdbm_store (new_dbf, key, data, GDBM_INSERT) != 0)
- {
- gdbm_close (new_dbf);
- gdbm_set_errno (NULL, GDBM_REORGANIZE_FAILED, FALSE);
- unlink (new_name);
- free (new_name);
- return -1;
- }
- }
- else
- {
- /* ERROR! Abort and don't finish reorganize. */
- gdbm_close (new_dbf);
- gdbm_set_errno (NULL, GDBM_REORGANIZE_FAILED, FALSE);
- unlink (new_name);
- free (new_name);
- return -1;
- }
- nextkey = gdbm_nextkey (dbf, key);
- free (key.dptr);
- free (data.dptr);
- key = nextkey;
- }
-
- /* Write everything. */
- if (_gdbm_end_update (new_dbf))
- {
- gdbm_close (new_dbf);
- return -1;
- }
- gdbm_sync (new_dbf);
-
-#if HAVE_MMAP
- _gdbm_mapped_unmap (dbf);
-#endif
-
- /* Move the new file to old name. */
-
- if (rename (new_name, dbf->name) != 0)
- {
- gdbm_set_errno (NULL, GDBM_REORGANIZE_FAILED, FALSE);
- gdbm_close (new_dbf);
- free (new_name);
- return -1;
- }
-
- /* Fix up DBF to have the correct information for the new file. */
- if (dbf->file_locking)
- {
- _gdbm_unlock_file (dbf);
- }
- close (dbf->desc);
- free (dbf->header);
- free (dbf->dir);
-
- if (dbf->bucket_cache != NULL) {
- for (index = 0; index < dbf->cache_size; index++) {
- if (dbf->bucket_cache[index].ca_bucket != NULL)
- free (dbf->bucket_cache[index].ca_bucket);
- if (dbf->bucket_cache[index].ca_data.dptr != NULL)
- free (dbf->bucket_cache[index].ca_data.dptr);
- }
- free (dbf->bucket_cache);
- }
-
- dbf->desc = new_dbf->desc;
- dbf->header = new_dbf->header;
- dbf->dir = new_dbf->dir;
- dbf->bucket = new_dbf->bucket;
- dbf->bucket_dir = new_dbf->bucket_dir;
- dbf->last_read = new_dbf->last_read;
- dbf->bucket_cache = new_dbf->bucket_cache;
- dbf->cache_size = new_dbf->cache_size;
- dbf->header_changed = new_dbf->header_changed;
- dbf->directory_changed = new_dbf->directory_changed;
- dbf->bucket_changed = new_dbf->bucket_changed;
- dbf->second_changed = new_dbf->second_changed;
-
-#if HAVE_MMAP
- /* Re-initialize mapping if required */
- if (dbf->memory_mapping)
- _gdbm_mapped_init (dbf);
-#endif
-
- free (new_dbf->name);
- free (new_dbf);
- free (new_name);
-
- /* Make sure the new database is all on disk. */
- __fsync (dbf);
-
- /* Force the right stuff for a correct bucket cache. */
- dbf->cache_entry = &dbf->bucket_cache[0];
- return _gdbm_get_bucket (dbf, 0);
+ rcvr.max_failures = 0;
+ return gdbm_recover (dbf, &rcvr, GDBM_RCVR_MAX_FAILURES);
}

Return to:

Send suggestions and report system problems to the System administrator.