7910 l2arc_write_buffers() may write beyond target_sz
[unleashed.git] / usr / src / lib / libnisdb / db_log.cc
blobb9b602e4d8b4684c126e1b3992f60595a7e3486d
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * db_log.cc
25 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
29 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include <stdio.h>
32 #include <errno.h>
34 #include <malloc.h>
35 #include <string.h>
36 #ifdef TDRPC
37 #include <sysent.h>
38 #endif
39 #include <unistd.h>
41 #include "db_headers.h"
42 #include "db_log.h"
44 #include "nisdb_mt.h"
46 static void
47 delete_log_entry(db_log_entry *lentry)
49 db_query *q;
50 entry_object *obj;
51 if (lentry) {
52 if ((q = lentry->get_query())) {
53 delete q;
55 if ((obj = lentry->get_object())) {
56 free_entry(obj);
58 delete lentry;
63 * Execute given function 'func' on log.
64 * function takes as arguments: pointer to log entry, character pointer to
65 * another argument, and pointer to an integer, which is used as a counter.
66 * 'func' should increment this value for each successful application.
67 * The log is traversed until either 'func' returns FALSE, or when the log
68 * is exhausted. The second argument to 'execute_on_log' is passed as the
69 * second argument to 'func'. The third argument, 'clean' determines whether
70 * the log entry is deleted after the function has been applied.
71 * Returns the number of times that 'func' incremented its third argument.
73 int
74 db_log::execute_on_log(bool_t (*func) (db_log_entry *, char *, int *),
75 char* arg, bool_t clean)
77 db_log_entry *j;
78 int count = 0;
79 bool_t done = FALSE;
81 WRITELOCK(this, 0, "w db_log::execute_on_log");
82 if (open() == TRUE) { // open log
83 while (!done) {
84 j = get();
85 if (j == NULL)
86 break;
87 if ((*func)(j, arg, &count) == FALSE) done = TRUE;
88 if (clean) delete_log_entry(j);
91 sync_log();
92 close();
94 WRITEUNLOCK(this, count, "wu db_log::execute_on_log");
96 return (count);
99 static bool_t
100 print_log_entry(db_log_entry *j, char * /* dummy */, int *count)
102 j->print();
103 ++ *count;
104 return (TRUE);
107 /* Print contents of log file to stdout */
109 db_log::print()
111 return (execute_on_log(&(print_log_entry), NULL));
114 /* Make copy of current log to log pointed to by 'f'. */
116 db_log::copy(db_log *f)
118 db_log_entry *j;
119 int l, ret = 0;
121 WRITELOCK(f, -1, "w f db_log::copy");
122 if ((l = acqnonexcl()) != 0) {
123 WRITEUNLOCK(f, l, "wu f db_log::copy");
124 return (l);
126 for (;;) {
127 j = get();
128 if (j == NULL)
129 break;
130 if (f->append(j) < 0) {
131 WARNING_M(
132 "db_log::copy: could not append to log file: ");
133 ret = -1;
134 break;
136 delete_log_entry(j);
138 if ((l = relnonexcl()) != 0) {
139 ret = l;
141 WRITEUNLOCK(f, ret, "wu f db_log::copy");
142 return (ret);
145 /* Rewinds current log */
147 db_log::rewind()
149 return (fseek(file, 0L, 0));
153 * Return the next element in current log; return NULL if end of log or error.
154 * Log must have been opened for READ.
156 db_log_entry
157 *db_log::get()
159 db_log_entry *j;
161 READLOCK(this, NULL, "r db_log::get");
162 if (mode != PICKLE_READ) {
163 READUNLOCK(this, NULL, "ru db_log::get");
164 return (NULL);
167 j = new db_log_entry;
169 if (j == NULL) {
170 READUNLOCK(this, NULL, "ru db_log::get");
171 return (NULL);
173 if (xdr_db_log_entry(&(xdr), j) == FALSE) {
174 delete_log_entry (j);
175 /* WARNING("Could not sucessfully finish reading log"); */
176 READUNLOCK(this, NULL, "ru db_log::get");
177 return (NULL);
179 if (! j->sane()) {
180 WARNING("truncated log entry found");
181 delete_log_entry(j);
182 j = NULL;
184 READUNLOCK(this, j, "ru db_log::get");
185 return (j);
188 /* Append given log entry to log. */
190 db_log::append(db_log_entry *j)
192 int status;
194 WRITELOCK(this, -1, "w db_log::append");
195 if (mode != PICKLE_APPEND) {
196 WRITEUNLOCK(this, -1, "wu db_log::append");
197 return (-1);
200 /* xdr returns TRUE if successful, FALSE otherwise */
201 status = ((xdr_db_log_entry(&(xdr), j)) ? 0 : -1);
202 if (status < 0) {
203 WARNING("db_log: could not write log entry");
204 } else {
205 syncstate++;
207 WRITEUNLOCK(this, status, "wu db_log::append");
208 return (status);
212 copy_log_file(char *oldname, char *newname) {
214 int from, to, ret = 0;
215 ssize_t size, w, b;
216 char buf[8192];
218 if ((from = open(oldname, O_RDONLY, 0666)) < 0) {
219 if (errno == ENOENT) {
220 return (0);
221 } else {
222 return (errno);
225 if ((to = open(newname, O_WRONLY|O_CREAT|O_TRUNC, 0660)) < 0) {
226 ret = errno;
227 (void) close(from);
228 return (ret);
231 while ((size = read(from, buf, sizeof (buf))) > 0) {
232 b = 0;
233 while (size > 0) {
234 w = write(to, &buf[b], size);
235 if (w < 0) {
236 size == -1;
237 break;
239 size -= w;
240 b += w;
242 if (size != 0) {
243 ret = errno;
244 break;
248 (void) close(from);
250 if (ret != 0) {
251 errno = ret;
252 WARNING_M("db_log: error copying log file")
253 (void) close(to);
254 return (ret);
257 if (fsync(to) != 0) {
258 ret = errno;
259 WARNING_M("db_log: error syncing log file");
262 (void) close(to);
264 return (ret);
269 * Return value is expected to be the usual C convention of non-zero
270 * for success, 0 for failure.
273 db_log::sync_log()
275 int status, err;
277 WRITELOCK(this, -1, "w db_log::sync_log");
278 status = fflush(file);
279 if (status < 0) {
280 WARNING("db_log: could not flush log entry to disk");
281 WRITEUNLOCK(this, status, "wu db_log::sync_log");
282 return (status);
285 status = fsync(fileno(file));
286 if (status < 0) {
287 WARNING("db_log: could not sync log entry to disk");
288 } else if (tmplog != 0) {
289 if (syncstate == 0) {
290 /* Log already stable; nothing to do */
291 err = 0;
292 } else if ((err = copy_log_file(tmplog, stablelog)) == 0) {
293 if (rename(stablelog, oldlog) != 0) {
294 WARNING_M("db_log: could not mv stable log");
295 } else {
296 syncstate = 0;
298 } else {
299 errno = err;
300 WARNING_M("db_log: could not stabilize log");
302 status = (err == 0);
303 } else {
305 * Successful sync of file, but no tmplog to sync
306 * so we make sure we return 'success'.
308 status = 1;
310 WRITEUNLOCK(this, status, "wu db_log::sync_log");
311 return (status);
315 db_log::close() {
317 int ret;
319 WRITELOCK(this, -1, "w db_log::close");
320 if (mode != PICKLE_READ && oldlog != 0) {
321 if (syncstate != 0) {
322 WARNING("db_log: closing unstable tmp log");
324 filename = oldlog;
325 oldlog = 0;
328 ret = pickle_file::close();
329 if (tmplog != 0) {
330 (void) unlink(tmplog);
331 delete tmplog;
332 tmplog = 0;
334 if (stablelog != 0) {
335 delete stablelog;
336 stablelog = 0;
338 WRITEUNLOCK(this, ret, "wu db_log::close");
339 return (ret);
342 bool_t
343 db_log::open(void) {
345 int len, cpstat;
346 bool_t ret;
348 WRITELOCK(this, FALSE, "w db_log::open");
349 if (mode == PICKLE_READ || (!copylog)) {
350 ret = pickle_file::open();
351 WRITEUNLOCK(this, ret, "wu db_log::open");
352 return (ret);
355 len = strlen(filename);
356 tmplog = new char[len + sizeof (".tmp")];
357 if (tmplog == 0) {
358 WARNING("db_log: could not allocate tmp log name");
359 ret = pickle_file::open();
360 WRITEUNLOCK(this, ret, "wu db_log::open");
361 return (ret);
363 stablelog = new char[len + sizeof (".stable")];
364 if (stablelog == 0) {
365 WARNING("db_log: could not allocate stable log name");
366 delete tmplog;
367 tmplog = 0;
368 ret = pickle_file::open();
369 WRITEUNLOCK(this, ret, "wu db_log::open");
370 return (ret);
372 sprintf(tmplog, "%s.tmp", filename);
373 sprintf(stablelog, "%s.stable", filename);
375 if ((cpstat = copy_log_file(filename, tmplog)) == 0) {
376 oldlog = filename;
377 filename = tmplog;
378 } else {
379 syslog(LOG_WARNING,
380 "db_log: Error copying \"%s\" to \"%s\": %s",
381 filename, tmplog, strerror(cpstat));
382 delete tmplog;
383 tmplog = 0;
384 delete stablelog;
385 stablelog = 0;
388 ret = pickle_file::open();
389 WRITEUNLOCK(this, ret, "wu db_log::open");
390 return (ret);