source: main/tags/2.26/gsdl/packages/wingdbm/gdbmreorg.c@ 28875

Last change on this file since 28875 was 525, checked in by rjmcnab, 25 years ago

added need_filelock option to open

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 6.2 KB
Line 
1/* gdbmreorg.c - Reorganize the database file. */
2
3/* This file is part of GDBM, the GNU data base manager, by Philip A. Nelson.
4 Copyright (C) 1990, 1991, 1993 Free Software Foundation, Inc.
5
6 GDBM is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GDBM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GDBM; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 You may contact the author by:
21 e-mail: [email protected]
22 us-mail: Philip A. Nelson
23 Computer Science Department
24 Western Washington University
25 Bellingham, WA 98226
26
27************************************************************************/
28
29
30/* AIX demands this be the very first thing in the file. */
31#if !defined(__GNUC__) && defined(_AIX)
32 #pragma alloca
33#endif
34
35/* include system configuration before all else. */
36#include "autoconf.h"
37
38#include "gdbmdefs.h"
39#include "gdbmerrno.h"
40#include "extern.h"
41
42#if !HAVE_RENAME
43
44/* Rename takes OLD_NAME and renames it as NEW_NAME. If it can not rename
45 the file a non-zero value is returned. OLD_NAME is guaranteed to
46 remain if it can't be renamed. It assumes NEW_NAME always exists (due
47 to being used in gdbm). */
48
49static int
50rename (old_name, new_name)
51 char* old_name;
52 char* new_name;
53{
54 if (unlink (new_name) != 0)
55 return -1;
56
57 if (link (old_name, new_name) != 0)
58 return -1;
59
60 unlink (old_name);
61 return 0;
62
63}
64#endif
65
66
67
68/* Reorganize the database. This requires creating a new file and inserting
69 all the elements in the old file DBF into the new file. The new file
70 is then renamed to the same name as the old file and DBF is updated to
71 contain all the correct information about the new file. If an error
72 is detected, the return value is negative. The value zero is returned
73 after a successful reorganization. */
74
75int
76gdbm_reorganize (dbf)
77 gdbm_file_info *dbf;
78
79{
80 gdbm_file_info *new_dbf; /* The new file. */
81 char *new_name; /* A temporary name. */
82 int len; /* Used in new_name construction. */
83 datum key, nextkey, data; /* For the sequential sweep. */
84 struct stat fileinfo; /* Information about the file. */
85 int index; /* Use in moving the bucket cache. */
86
87
88 /* Readers can not reorganize! */
89 if (dbf->read_write == GDBM_READER)
90 {
91 gdbm_errno = GDBM_READER_CANT_REORGANIZE;
92 return -1;
93 }
94
95 /* Initialize the gdbm_errno variable. */
96 gdbm_errno = GDBM_NO_ERROR;
97
98 /* Construct new name for temporary file. */
99 len = strlen (dbf->name);
100 new_name = (char *) alloca (len + 3);
101 if (new_name == NULL)
102 {
103 gdbm_errno = GDBM_MALLOC_ERROR;
104 return -1;
105 }
106 strcpy (&new_name[0], dbf->name);
107 new_name[len+2] = 0;
108 new_name[len+1] = '#';
109 while ( (len > 0) && new_name[len-1] != '/')
110 {
111 new_name[len] = new_name[len-1];
112 len -= 1;
113 }
114 new_name[len] = '#';
115
116 /* Get the mode for the old file and open the new database.
117 The "fast" mode is used because the reorganization will fail
118 unless we create a complete copy of the database. */
119 fstat (dbf->desc, &fileinfo);
120 new_dbf = gdbm_open (new_name, dbf->header->block_size,
121 GDBM_WRCREAT | GDBM_FAST,
122 fileinfo.st_mode, dbf->fatal_err);
123
124 if (new_dbf == NULL)
125 {
126 gdbm_errno = GDBM_REORGANIZE_FAILED;
127 return -1;
128 }
129
130
131 /* For each item in the old database, add an entry in the new. */
132 key = gdbm_firstkey (dbf);
133
134 while (key.dptr != NULL)
135 {
136 data = gdbm_fetch (dbf, key);
137 if (data.dptr != NULL)
138 {
139 /* Add the data to the new file. */
140 if (gdbm_store (new_dbf, key, data, GDBM_INSERT) != 0)
141 {
142 gdbm_close (new_dbf);
143 gdbm_errno = GDBM_REORGANIZE_FAILED;
144 unlink (new_name);
145 return -1;
146 }
147 }
148 else
149 {
150 /* ERROR! Abort and don't finish reorganize. */
151 gdbm_close (new_dbf);
152 gdbm_errno = GDBM_REORGANIZE_FAILED;
153 unlink (new_name);
154 return -1;
155 }
156 nextkey = gdbm_nextkey (dbf, key);
157 free (key.dptr);
158 free (data.dptr);
159 key = nextkey;
160 }
161
162 /* Write everything. */
163 _gdbm_end_update (new_dbf);
164 gdbm_sync (new_dbf);
165
166
167 /* Move the new file to old name. */
168
169#ifdef MSDOS
170 if (close (new_dbf->desc)
171 || unlink (dbf->name)
172 || rename (new_name, dbf->name)
173 || (new_dbf->desc = open (dbf->name, O_RDWR|O_BINARY)) < 0)
174#else /* not MSDOS */
175 if (rename (new_name, dbf->name) != 0)
176#endif /* not MSDOS */
177 {
178 gdbm_errno = GDBM_REORGANIZE_FAILED;
179 gdbm_close (new_dbf);
180 return -1;
181 }
182
183 /* Fix up DBF to have the correct information for the new file. */
184 if (dbf->need_filelock) {
185 UNLOCK_FILE(dbf);
186 }
187 close (dbf->desc);
188 free (dbf->header);
189 free (dbf->dir);
190
191 if (dbf->bucket_cache != NULL) {
192 for (index = 0; index < dbf->cache_size; index++) {
193 if (dbf->bucket_cache[index].ca_bucket != NULL)
194 free (dbf->bucket_cache[index].ca_bucket);
195 if (dbf->bucket_cache[index].ca_data.dptr != NULL)
196 free (dbf->bucket_cache[index].ca_data.dptr);
197 }
198 free (dbf->bucket_cache);
199 }
200
201 dbf->desc = new_dbf->desc;
202 dbf->header = new_dbf->header;
203 dbf->dir = new_dbf->dir;
204 dbf->bucket = new_dbf->bucket;
205 dbf->bucket_dir = new_dbf->bucket_dir;
206 dbf->last_read = new_dbf->last_read;
207 dbf->bucket_cache = new_dbf->bucket_cache;
208 dbf->cache_size = new_dbf->cache_size;
209 dbf->header_changed = new_dbf->header_changed;
210 dbf->directory_changed = new_dbf->directory_changed;
211 dbf->bucket_changed = new_dbf->bucket_changed;
212 dbf->second_changed = new_dbf->second_changed;
213
214 free (new_dbf);
215
216 /* Make sure the new database is all on disk. */
217 fsync (dbf->desc);
218
219 /* Force the right stuff for a correct bucket cache. */
220 dbf->cache_entry = &dbf->bucket_cache[0];
221 _gdbm_get_bucket (dbf, 0);
222
223 return 0;
224}
Note: See TracBrowser for help on using the repository browser.