xref: /illumos-gate/usr/src/lib/libnisdb/db_dictlog.cc (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
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.
8  *
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.
13  *
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]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  *	db_dictlog.cc
24  *
25  *	Copyright (c) 1988-2000 by Sun Microsystems, Inc.
26  *	All Rights Reserved.
27  */
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 #include <stdio.h>
32 
33 #include <malloc.h>
34 #include <string.h>
35 #ifdef TDRPC
36 #include <sysent.h>
37 #endif
38 #include <unistd.h>
39 
40 #include "nisdb_rw.h"
41 
42 #include "db_headers.h"
43 #include "db_dictlog.h"
44 
45 #include "nisdb_mt.h"
46 
47 
48 /*
49  * Constructor:  Create a log entry using the given parameters.  Note that
50  * pointers to db_query and entry_object are simply assigned, not copied.
51  */
52 db_dictlog_entry::db_dictlog_entry(int a, vers * v, char *tname,
53 				    table_obj *obj)
54 {
55 	action = a;
56 	aversion.assign(v);
57 	table_name = tname;
58 	table_object = obj;
59 	next = NULL;
60 	bversion.assign(v);
61 }
62 
63 db_dictlog_entry::~db_dictlog_entry()
64 {
65 /* we might not have allocated these ourselves, so we cannot delete them */
66 }
67 
68 /* prints a line from the journal */
69 void
70 db_dictlog_entry::print()
71 {
72 	switch (action) {
73 	case DB_ADD_TABLE:
74 	    printf ("add: ");
75 	    break;
76 	case DB_REMOVE_TABLE:
77 	    printf ("remove: ");
78 	    break;
79 	default:
80 	    printf ("action(%d): ", action);
81 	    break;
82 	}
83 
84 	aversion.print(stdout);
85 	putchar(' ');
86 	if (table_name != NULL)
87 		printf ("table %s\n", table_name);
88 	else
89 		printf("no table!\n");
90 	bversion.print(stdout);
91 	putchar('\n');
92 }
93 
94 static void
95 free_table_entry(table_obj* obj)
96 {
97 	if (obj == NULL)
98 		return;
99 
100 	if (obj->ta_type != NULL)
101 		free(obj->ta_type);
102 
103 	table_col* tcs = obj->ta_cols.ta_cols_val;
104 	int i;
105 	for (i = 0; i < obj->ta_cols.ta_cols_len; i++) {
106 		if (tcs[i].tc_name != NULL)
107 			delete tcs[i].tc_name;
108 	}
109 	if (tcs != NULL)
110 		delete tcs;
111 	if (obj->ta_path != NULL)
112 		free(obj->ta_path);
113 	free(obj);
114 }
115 
116 static void
117 delete_log_entry(db_dictlog_entry *lentry)
118 {
119 	char *tname;
120 	table_obj *obj;
121 	if (lentry) {
122 		if ((tname = lentry->get_table_name())) {
123 			delete tname;
124 		}
125 		if ((obj = lentry->get_table_object())) {
126 		    free_table_entry(obj);
127 		}
128 		delete lentry;
129 	}
130 }
131 
132 /*
133  * Execute given function 'func' on log.
134  * function takes as arguments: pointer to log entry, character pointer to
135  * another argument, and pointer to an integer, which is used as a counter.
136  * 'func' should increment this value for each successful application.
137  * The log is traversed until either 'func' returns FALSE, or when the log
138  * is exhausted.  The second argument to 'execute_on_log' is passed as the
139  * second argument to 'func'.  The third argument, 'clean' determines whether
140  * the log entry is deleted after the function has been applied.
141  * Returns the number of times that 'func' incremented its third argument.
142  */
143 int
144 db_dictlog::execute_on_log(bool_t (*func) (db_dictlog_entry *,
145 					    char *, int *),
146 					    char* dict, bool_t clean)
147 {
148 	db_dictlog_entry    *j;
149 	int count = 0;
150 	bool_t done = FALSE;
151 
152 	WRITELOCK(this, 0, "w db_dictlog::execute_on_log");
153 	if (open() == FALSE) {   // open log
154 		WRITEUNLOCK(this, 0, "wu db_dictlog::execute_on_log");
155 		return (0);
156 	}
157 	while (!done) {
158 		j = get();
159 		if (j == NULL)
160 			break;
161 		if ((*func)(j, dict, &count) == FALSE) done = TRUE;
162 		if (clean) delete_log_entry(j);
163 	}
164 
165 	close();
166 	WRITEUNLOCK(this, count, "wu db_dictlog::execute_on_log");
167 	return (count);
168 }
169 
170 static bool_t
171 print_log_entry(db_dictlog_entry *j, char*, int *count)
172 {
173 	j->print();
174 	++ *count;
175 	return (TRUE);
176 }
177 
178 /* Print contents of log file to stdout */
179 int
180 db_dictlog::print()
181 {
182 	return (execute_on_log(&(print_log_entry), NULL));
183 }
184 
185 /*
186  * Return the next element in current log; return NULL if end of log or error.
187  * Log must have been opened for READ.
188  */
189 db_dictlog_entry
190 *db_dictlog::get()
191 {
192 	db_dictlog_entry *j;
193 
194 	READLOCK(this, NULL, "r db_dictlog::get");
195 	if (mode != PICKLE_READ) {
196 		READUNLOCK(this, NULL, "ru db_dictlog::get");
197 		return (NULL);
198 	}
199 
200 	j = new db_dictlog_entry;
201 
202 	if (j == NULL) {
203 		READUNLOCK(this, NULL, "ru db_dictlog::get");
204 		return (NULL);
205 	}
206 	if (xdr_db_dictlog_entry(&(xdr), j) == FALSE) {
207 		delete_log_entry (j);
208 /*    WARNING("Could not sucessfully finish reading log"); */
209 		READUNLOCK(this, NULL, "ru db_dictlog::get");
210 		return (NULL);
211 	}
212 	if (! j->sane()) {
213 		WARNING("truncated log entry found");
214 		delete_log_entry(j);
215 		j = NULL;
216 	}
217 	READUNLOCK(this, j, "ru db_dictlog::get");
218 	return (j);
219 }
220 
221 /* Append given log entry to log. */
222 int
223 db_dictlog::append(db_dictlog_entry *j)
224 {
225 	int status;
226 
227 	WRITELOCK(this, -1, "w db_dictlog::append");
228 	if (mode != PICKLE_APPEND) {
229 		WRITEUNLOCK(this, -1, "wu db_dictlog::append");
230 		return (-1);
231 	}
232 
233 	/* xdr returns TRUE if successful, FALSE otherwise */
234 	status = ((xdr_db_dictlog_entry(&(xdr), j)) ? 0 : -1);
235 	if (status < 0) {
236 		WARNING("db_dictlog: could not write log entry");
237 		WRITEUNLOCK(this, status, "wu db_dictlog::append");
238 		return (status);
239 	}
240 
241 	status = fflush(file);
242 	if (status < 0) {
243 		WARNING("db_dictlog: could not flush log entry to disk");
244 		WRITEUNLOCK(this, status, "wu db_dictlog::append");
245 		return (status);
246 	}
247 
248 	status = fsync(fileno(file));
249 	if (status < 0) {
250 		WARNING("db_dictlog: could not sync log entry to disk");
251 	}
252 
253 	WRITEUNLOCK(this, status, "wu db_dictlog::append");
254 	return (status);
255 }
256