xref: /titanic_52/usr/src/lib/libnisdb/db.cc (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  *	db.cc
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <string.h>
33*7c478bd9Sstevel@tonic-gate #ifdef TDRPC
34*7c478bd9Sstevel@tonic-gate #include <sysent.h>
35*7c478bd9Sstevel@tonic-gate #else
36*7c478bd9Sstevel@tonic-gate #include <unistd.h>
37*7c478bd9Sstevel@tonic-gate #endif
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include "nisdb_mt.h"
40*7c478bd9Sstevel@tonic-gate #include "db_headers.h"
41*7c478bd9Sstevel@tonic-gate #include "db.h"
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate extern db_result *empty_result(db_status);
44*7c478bd9Sstevel@tonic-gate extern int add_to_standby_list(db*);
45*7c478bd9Sstevel@tonic-gate extern int remove_from_standby_list(db*);
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /* for db_next_desc */
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #define	LINEAR 1
50*7c478bd9Sstevel@tonic-gate #define	CHAINED 2
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate struct db_next_info {
53*7c478bd9Sstevel@tonic-gate 	int next_type;		/* linear or chained */
54*7c478bd9Sstevel@tonic-gate 	void* next_value;	/* linear: entryp; */
55*7c478bd9Sstevel@tonic-gate 				/* chained: db_next_index_desc* */
56*7c478bd9Sstevel@tonic-gate };
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate /* Constructor:  Create a database using the given name, 'dbname.'
60*7c478bd9Sstevel@tonic-gate 	    The database is stored in a file named 'dbname'.
61*7c478bd9Sstevel@tonic-gate 	    The log file is stored in a file named 'dbname'.log.
62*7c478bd9Sstevel@tonic-gate 	    A temporary file 'dbname'.tmp is also used.   */
63*7c478bd9Sstevel@tonic-gate db::db(char* dbname)
64*7c478bd9Sstevel@tonic-gate {
65*7c478bd9Sstevel@tonic-gate 	int len = strlen(dbname);
66*7c478bd9Sstevel@tonic-gate 	dbfilename = new char[len+1];
67*7c478bd9Sstevel@tonic-gate 	if (dbfilename == NULL)
68*7c478bd9Sstevel@tonic-gate 		FATAL("db::db: cannot allocate space", DB_MEMORY_LIMIT);
69*7c478bd9Sstevel@tonic-gate 	logfilename = new char[len+5];
70*7c478bd9Sstevel@tonic-gate 	if (logfilename == NULL) {
71*7c478bd9Sstevel@tonic-gate 		delete dbfilename;
72*7c478bd9Sstevel@tonic-gate 		FATAL("db::db: cannot allocate space", DB_MEMORY_LIMIT);
73*7c478bd9Sstevel@tonic-gate 	}
74*7c478bd9Sstevel@tonic-gate 	tmpfilename = new char[len+5];
75*7c478bd9Sstevel@tonic-gate 	if (tmpfilename == NULL) {
76*7c478bd9Sstevel@tonic-gate 		delete dbfilename;
77*7c478bd9Sstevel@tonic-gate 		delete logfilename;
78*7c478bd9Sstevel@tonic-gate 		FATAL("db::db: cannot allocate space", DB_MEMORY_LIMIT);
79*7c478bd9Sstevel@tonic-gate 	}
80*7c478bd9Sstevel@tonic-gate 	sprintf(dbfilename, "%s", dbname);
81*7c478bd9Sstevel@tonic-gate 	sprintf(logfilename, "%s.log", dbname);
82*7c478bd9Sstevel@tonic-gate 	sprintf(tmpfilename, "%s.tmp", dbname);
83*7c478bd9Sstevel@tonic-gate 	logfile = NULL;
84*7c478bd9Sstevel@tonic-gate 	logfile_opened = FALSE;
85*7c478bd9Sstevel@tonic-gate 	changed = FALSE;
86*7c478bd9Sstevel@tonic-gate 	INITRW(db);
87*7c478bd9Sstevel@tonic-gate 	READLOCKOK(db);
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	internal_db.setDbPtr(this);
90*7c478bd9Sstevel@tonic-gate 	(void) internal_db.configure(dbname);
91*7c478bd9Sstevel@tonic-gate }
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate /* destructor:  note that associated files should be removed separated  */
94*7c478bd9Sstevel@tonic-gate db::~db()
95*7c478bd9Sstevel@tonic-gate {
96*7c478bd9Sstevel@tonic-gate 	(void)acqexcl();
97*7c478bd9Sstevel@tonic-gate 	internal_db.reset();  /* clear any associated data structures */
98*7c478bd9Sstevel@tonic-gate 	delete dbfilename;
99*7c478bd9Sstevel@tonic-gate 	delete logfilename;
100*7c478bd9Sstevel@tonic-gate 	delete tmpfilename;
101*7c478bd9Sstevel@tonic-gate 	close_log();
102*7c478bd9Sstevel@tonic-gate 	delete logfile;
103*7c478bd9Sstevel@tonic-gate 	(void)destroylock();
104*7c478bd9Sstevel@tonic-gate }
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate static void
108*7c478bd9Sstevel@tonic-gate assign_next_desc(db_next_desc* desc, entryp value)
109*7c478bd9Sstevel@tonic-gate {
110*7c478bd9Sstevel@tonic-gate 	db_next_info * store = new db_next_info;
111*7c478bd9Sstevel@tonic-gate 	if (store == NULL) {
112*7c478bd9Sstevel@tonic-gate 		desc->db_next_desc_val =  NULL;
113*7c478bd9Sstevel@tonic-gate 		desc->db_next_desc_len = 0;
114*7c478bd9Sstevel@tonic-gate 		FATAL("db::assign_next_desc: cannot allocate space",
115*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT);
116*7c478bd9Sstevel@tonic-gate 	}
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	store->next_type = LINEAR;
119*7c478bd9Sstevel@tonic-gate 	store->next_value = (void*)value;
120*7c478bd9Sstevel@tonic-gate 	desc->db_next_desc_val =  (char*) store;
121*7c478bd9Sstevel@tonic-gate 	desc->db_next_desc_len = sizeof (db_next_info);
122*7c478bd9Sstevel@tonic-gate }
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate static void
125*7c478bd9Sstevel@tonic-gate assign_next_desc(db_next_desc* desc, db_next_index_desc * value)
126*7c478bd9Sstevel@tonic-gate {
127*7c478bd9Sstevel@tonic-gate 	db_next_info * store = new db_next_info;
128*7c478bd9Sstevel@tonic-gate 	if (store == NULL) {
129*7c478bd9Sstevel@tonic-gate 		desc->db_next_desc_val =  NULL;
130*7c478bd9Sstevel@tonic-gate 		desc->db_next_desc_len = 0;
131*7c478bd9Sstevel@tonic-gate 		FATAL("db::assign_next_desc: cannot allocate space (2)",
132*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT);
133*7c478bd9Sstevel@tonic-gate 	}
134*7c478bd9Sstevel@tonic-gate 	store->next_type = CHAINED;
135*7c478bd9Sstevel@tonic-gate 	store->next_value = (void*)value;
136*7c478bd9Sstevel@tonic-gate 	desc->db_next_desc_val =  (char*) store;
137*7c478bd9Sstevel@tonic-gate 	desc->db_next_desc_len = sizeof (db_next_info);
138*7c478bd9Sstevel@tonic-gate }
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate static entryp
141*7c478bd9Sstevel@tonic-gate extract_next_desc(db_next_desc* desc, int *next_type,
142*7c478bd9Sstevel@tonic-gate 		db_next_index_desc** place2)
143*7c478bd9Sstevel@tonic-gate {
144*7c478bd9Sstevel@tonic-gate 	entryp place;
145*7c478bd9Sstevel@tonic-gate 
146*7c478bd9Sstevel@tonic-gate 	if (desc == NULL || desc->db_next_desc_len != sizeof (db_next_info)) {
147*7c478bd9Sstevel@tonic-gate 		*next_type = 0;
148*7c478bd9Sstevel@tonic-gate 		return (0);
149*7c478bd9Sstevel@tonic-gate 	}
150*7c478bd9Sstevel@tonic-gate 	*next_type = ((db_next_info*) desc->db_next_desc_val)->next_type;
151*7c478bd9Sstevel@tonic-gate 	switch (*next_type) {
152*7c478bd9Sstevel@tonic-gate 	case LINEAR:
153*7c478bd9Sstevel@tonic-gate 		place = (entryp)
154*7c478bd9Sstevel@tonic-gate 			((db_next_info*) desc->db_next_desc_val)->next_value;
155*7c478bd9Sstevel@tonic-gate 		return (place);
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	case CHAINED:
158*7c478bd9Sstevel@tonic-gate 		*place2 = (db_next_index_desc*)
159*7c478bd9Sstevel@tonic-gate 			((db_next_info*) desc->db_next_desc_val) ->next_value;
160*7c478bd9Sstevel@tonic-gate 		return (0);
161*7c478bd9Sstevel@tonic-gate 	default:
162*7c478bd9Sstevel@tonic-gate 		*next_type = 0;   // invalid type
163*7c478bd9Sstevel@tonic-gate 		return (0);
164*7c478bd9Sstevel@tonic-gate 	}
165*7c478bd9Sstevel@tonic-gate }
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate /* Execute the specified action using the rest of the arguments as input.
168*7c478bd9Sstevel@tonic-gate 	    Return  a structure db_result containing the result. */
169*7c478bd9Sstevel@tonic-gate db_result *
170*7c478bd9Sstevel@tonic-gate db::exec_action(db_action action, db_query *query,
171*7c478bd9Sstevel@tonic-gate 		entry_object *content, db_next_desc* previous)
172*7c478bd9Sstevel@tonic-gate {
173*7c478bd9Sstevel@tonic-gate 	entryp where, prev;
174*7c478bd9Sstevel@tonic-gate 	db_result *res = new db_result;
175*7c478bd9Sstevel@tonic-gate 	long num_answers;
176*7c478bd9Sstevel@tonic-gate 	entry_object_p * ans;
177*7c478bd9Sstevel@tonic-gate 	entry_object * single;
178*7c478bd9Sstevel@tonic-gate 	db_next_index_desc *index_desc;
179*7c478bd9Sstevel@tonic-gate 	int next_type;
180*7c478bd9Sstevel@tonic-gate 	db_next_index_desc *prev_desc;
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 	if (res == NULL)
183*7c478bd9Sstevel@tonic-gate 		FATAL3("db::exec_action: cannot allocate space for result",
184*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, NULL);
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	res->objects.objects_len = 0; /* default */
187*7c478bd9Sstevel@tonic-gate 	res->objects.objects_val = NULL;  /* default */
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	switch (action) {
190*7c478bd9Sstevel@tonic-gate 	case DB_LOOKUP:
191*7c478bd9Sstevel@tonic-gate 		res->status = internal_db.lookup(query, &num_answers, &ans);
192*7c478bd9Sstevel@tonic-gate 		res->objects.objects_len = (int) num_answers;
193*7c478bd9Sstevel@tonic-gate 		res->objects.objects_val = ans;
194*7c478bd9Sstevel@tonic-gate 		break;
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	case DB_ADD:
197*7c478bd9Sstevel@tonic-gate 		res->status = internal_db.add(query, content);
198*7c478bd9Sstevel@tonic-gate 		break;
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 	case DB_REMOVE:
201*7c478bd9Sstevel@tonic-gate 		res->status = internal_db.remove(query);
202*7c478bd9Sstevel@tonic-gate 		break;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	case DB_FIRST:
205*7c478bd9Sstevel@tonic-gate 		if (query == NULL) {
206*7c478bd9Sstevel@tonic-gate 			res->status = internal_db.first(&where, &single);
207*7c478bd9Sstevel@tonic-gate 			if (res->status == DB_SUCCESS)
208*7c478bd9Sstevel@tonic-gate 				assign_next_desc(&(res->nextinfo), where);
209*7c478bd9Sstevel@tonic-gate 		}  else {
210*7c478bd9Sstevel@tonic-gate 			res->status = internal_db.first(query,
211*7c478bd9Sstevel@tonic-gate 							&index_desc,
212*7c478bd9Sstevel@tonic-gate 							&single);
213*7c478bd9Sstevel@tonic-gate 			if (res->status == DB_SUCCESS)
214*7c478bd9Sstevel@tonic-gate 				assign_next_desc(&(res->nextinfo), index_desc);
215*7c478bd9Sstevel@tonic-gate 		}
216*7c478bd9Sstevel@tonic-gate 		if (res->status == DB_SUCCESS) {
217*7c478bd9Sstevel@tonic-gate 			res->objects.objects_val = new entry_object_p;
218*7c478bd9Sstevel@tonic-gate 			if (res->objects.objects_val == NULL) {
219*7c478bd9Sstevel@tonic-gate 				res->objects.objects_len = 0;
220*7c478bd9Sstevel@tonic-gate 				delete res;
221*7c478bd9Sstevel@tonic-gate 				FATAL3(
222*7c478bd9Sstevel@tonic-gate 		"db::exec_action: cannot allocate space for DB_FIRST result",
223*7c478bd9Sstevel@tonic-gate 		DB_MEMORY_LIMIT, NULL);
224*7c478bd9Sstevel@tonic-gate 			}
225*7c478bd9Sstevel@tonic-gate 			res->objects.objects_len = 1;
226*7c478bd9Sstevel@tonic-gate 			res->objects.objects_val[0] = single;
227*7c478bd9Sstevel@tonic-gate 		}
228*7c478bd9Sstevel@tonic-gate 		break;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	case DB_NEXT:
231*7c478bd9Sstevel@tonic-gate 		prev = extract_next_desc(previous, &next_type, &prev_desc);
232*7c478bd9Sstevel@tonic-gate 		switch (next_type) {
233*7c478bd9Sstevel@tonic-gate 		case LINEAR:
234*7c478bd9Sstevel@tonic-gate 			if (prev != 0) {
235*7c478bd9Sstevel@tonic-gate 				res->status = internal_db.next(prev, &where,
236*7c478bd9Sstevel@tonic-gate 								&single);
237*7c478bd9Sstevel@tonic-gate 				if (res->status == DB_SUCCESS)
238*7c478bd9Sstevel@tonic-gate 					assign_next_desc(&(res->nextinfo),
239*7c478bd9Sstevel@tonic-gate 								where);
240*7c478bd9Sstevel@tonic-gate 			} else
241*7c478bd9Sstevel@tonic-gate 					// invalid previous indicator
242*7c478bd9Sstevel@tonic-gate 				res->status = DB_NOTFOUND;
243*7c478bd9Sstevel@tonic-gate 			break;
244*7c478bd9Sstevel@tonic-gate 		case CHAINED:
245*7c478bd9Sstevel@tonic-gate 			if (prev_desc != NULL) {
246*7c478bd9Sstevel@tonic-gate 				res->status = internal_db.next(prev_desc,
247*7c478bd9Sstevel@tonic-gate 							&index_desc, &single);
248*7c478bd9Sstevel@tonic-gate 				if (res->status == DB_SUCCESS)
249*7c478bd9Sstevel@tonic-gate 					assign_next_desc(&(res->nextinfo),
250*7c478bd9Sstevel@tonic-gate 								index_desc);
251*7c478bd9Sstevel@tonic-gate 			} else
252*7c478bd9Sstevel@tonic-gate 					// invalid previous indicator
253*7c478bd9Sstevel@tonic-gate 				res->status = DB_NOTFOUND;
254*7c478bd9Sstevel@tonic-gate 			break;
255*7c478bd9Sstevel@tonic-gate 		default:
256*7c478bd9Sstevel@tonic-gate 			WARNING("db::exec_action: invalid previous indicator");
257*7c478bd9Sstevel@tonic-gate 			res->status = DB_BADQUERY;
258*7c478bd9Sstevel@tonic-gate 		}
259*7c478bd9Sstevel@tonic-gate 		if (previous && previous->db_next_desc_val) {
260*7c478bd9Sstevel@tonic-gate 			delete previous->db_next_desc_val;
261*7c478bd9Sstevel@tonic-gate 			previous->db_next_desc_len = 0;
262*7c478bd9Sstevel@tonic-gate 			previous->db_next_desc_val = NULL;
263*7c478bd9Sstevel@tonic-gate 		}
264*7c478bd9Sstevel@tonic-gate 		if (res->status == DB_SUCCESS) {
265*7c478bd9Sstevel@tonic-gate 			res->objects.objects_len = 1;
266*7c478bd9Sstevel@tonic-gate 			res->objects.objects_val = new entry_object_p;
267*7c478bd9Sstevel@tonic-gate 			if (res->objects.objects_val == NULL) {
268*7c478bd9Sstevel@tonic-gate 				res->objects.objects_len = 0;
269*7c478bd9Sstevel@tonic-gate 				delete res;
270*7c478bd9Sstevel@tonic-gate 				FATAL3(
271*7c478bd9Sstevel@tonic-gate 		    "db::exec_action: cannot allocate space for DB_NEXT result",
272*7c478bd9Sstevel@tonic-gate 		    DB_MEMORY_LIMIT, NULL);
273*7c478bd9Sstevel@tonic-gate 			}
274*7c478bd9Sstevel@tonic-gate 			res->objects.objects_val[0] = single;
275*7c478bd9Sstevel@tonic-gate 		}
276*7c478bd9Sstevel@tonic-gate 		break;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	case DB_RESET_NEXT:
279*7c478bd9Sstevel@tonic-gate 		prev = extract_next_desc(previous, &next_type, &prev_desc);
280*7c478bd9Sstevel@tonic-gate 		switch (next_type) {
281*7c478bd9Sstevel@tonic-gate 		case LINEAR:
282*7c478bd9Sstevel@tonic-gate 			res->status = DB_SUCCESS;
283*7c478bd9Sstevel@tonic-gate 			if (previous->db_next_desc_val) {
284*7c478bd9Sstevel@tonic-gate 	delete previous->db_next_desc_val;
285*7c478bd9Sstevel@tonic-gate 	previous->db_next_desc_len = 0;
286*7c478bd9Sstevel@tonic-gate 	previous->db_next_desc_val = NULL;
287*7c478bd9Sstevel@tonic-gate 			}
288*7c478bd9Sstevel@tonic-gate 			break;   // do nothing
289*7c478bd9Sstevel@tonic-gate 		case CHAINED:
290*7c478bd9Sstevel@tonic-gate 			res->status = internal_db.reset_next(prev_desc);
291*7c478bd9Sstevel@tonic-gate 			if (previous->db_next_desc_val) {
292*7c478bd9Sstevel@tonic-gate 	delete previous->db_next_desc_val;
293*7c478bd9Sstevel@tonic-gate 	previous->db_next_desc_len = 0;
294*7c478bd9Sstevel@tonic-gate 	previous->db_next_desc_val = NULL;
295*7c478bd9Sstevel@tonic-gate 			}
296*7c478bd9Sstevel@tonic-gate 			break;
297*7c478bd9Sstevel@tonic-gate 		default:
298*7c478bd9Sstevel@tonic-gate 			WARNING("db::exec_action: invalid previous indicator");
299*7c478bd9Sstevel@tonic-gate 			res->status = DB_BADQUERY;
300*7c478bd9Sstevel@tonic-gate 		}
301*7c478bd9Sstevel@tonic-gate 		break;
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	case DB_ALL:
304*7c478bd9Sstevel@tonic-gate 		res->status = internal_db.all(&num_answers, &ans);
305*7c478bd9Sstevel@tonic-gate 		res->objects.objects_len = (int) num_answers;
306*7c478bd9Sstevel@tonic-gate 		res->objects.objects_val = ans;
307*7c478bd9Sstevel@tonic-gate 		break;
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	default:
310*7c478bd9Sstevel@tonic-gate 		WARNING("unknown request");
311*7c478bd9Sstevel@tonic-gate 		res->status = DB_BADQUERY;
312*7c478bd9Sstevel@tonic-gate 		return (res);
313*7c478bd9Sstevel@tonic-gate 	}
314*7c478bd9Sstevel@tonic-gate 	return (res);
315*7c478bd9Sstevel@tonic-gate }
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate /*
318*7c478bd9Sstevel@tonic-gate  * Log the given action and execute it.
319*7c478bd9Sstevel@tonic-gate  * The minor version of the database is updated after the action has
320*7c478bd9Sstevel@tonic-gate  * been executed and the database is flagged as being changed.
321*7c478bd9Sstevel@tonic-gate  * Return the structure db_result, or NULL if the logging failed or the
322*7c478bd9Sstevel@tonic-gate  * action is unknown.
323*7c478bd9Sstevel@tonic-gate */
324*7c478bd9Sstevel@tonic-gate db_result *
325*7c478bd9Sstevel@tonic-gate db::log_action(db_action action, db_query *query, entry_object *content)
326*7c478bd9Sstevel@tonic-gate {
327*7c478bd9Sstevel@tonic-gate 	vers *v = internal_db.get_version()->nextminor();
328*7c478bd9Sstevel@tonic-gate 	db_result * res;
329*7c478bd9Sstevel@tonic-gate 	db_log_entry le(action, v, query, content);
330*7c478bd9Sstevel@tonic-gate 	bool_t copylog = FALSE;
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, empty_result(DB_LOCK_ERROR), "w db::log_action");
333*7c478bd9Sstevel@tonic-gate 	/*
334*7c478bd9Sstevel@tonic-gate 	 * If this is a synchronous operation on the master we should
335*7c478bd9Sstevel@tonic-gate 	 * not copy the log for each operation.  Doing so causes
336*7c478bd9Sstevel@tonic-gate 	 * massive disk IO that hampers the performance of these operations.
337*7c478bd9Sstevel@tonic-gate 	 * Where as on the replica these operations are not synchronous
338*7c478bd9Sstevel@tonic-gate 	 * (batched) and don't affect the performance as much.
339*7c478bd9Sstevel@tonic-gate 	 */
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	if ((action == DB_ADD_NOSYNC) || (action == DB_REMOVE_NOSYNC))
342*7c478bd9Sstevel@tonic-gate 		copylog = TRUE;
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	if (open_log(copylog) < 0)  {
345*7c478bd9Sstevel@tonic-gate 		delete v;
346*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, empty_result(DB_LOCK_ERROR),
347*7c478bd9Sstevel@tonic-gate 				"wu db::log_action DB_STORAGE_LIMIT");
348*7c478bd9Sstevel@tonic-gate 		return (empty_result(DB_STORAGE_LIMIT));
349*7c478bd9Sstevel@tonic-gate 	}
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	if (logfile->append(&le) < 0) {
352*7c478bd9Sstevel@tonic-gate 		close_log();
353*7c478bd9Sstevel@tonic-gate 		WARNING_M("db::log_action: could not add log entry: ");
354*7c478bd9Sstevel@tonic-gate 		delete v;
355*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, empty_result(DB_LOCK_ERROR),
356*7c478bd9Sstevel@tonic-gate 				"wu db::log_action DB_STORAGE_LIMIT");
357*7c478bd9Sstevel@tonic-gate 		return (empty_result(DB_STORAGE_LIMIT));
358*7c478bd9Sstevel@tonic-gate 	}
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	switch (action) {
361*7c478bd9Sstevel@tonic-gate 	case DB_ADD_NOSYNC:
362*7c478bd9Sstevel@tonic-gate 		action = DB_ADD;
363*7c478bd9Sstevel@tonic-gate 		break;
364*7c478bd9Sstevel@tonic-gate 	case DB_REMOVE_NOSYNC:
365*7c478bd9Sstevel@tonic-gate 		action = DB_REMOVE;
366*7c478bd9Sstevel@tonic-gate 		break;
367*7c478bd9Sstevel@tonic-gate 	default:
368*7c478bd9Sstevel@tonic-gate 		if (logfile->sync_log() < 0) {
369*7c478bd9Sstevel@tonic-gate 			close_log();
370*7c478bd9Sstevel@tonic-gate 			WARNING_M("db::log_action: could not add log entry: ");
371*7c478bd9Sstevel@tonic-gate 			delete v;
372*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, empty_result(DB_LOCK_ERROR),
373*7c478bd9Sstevel@tonic-gate 					"wu db::log_action DB_STORAGE_LIMIT");
374*7c478bd9Sstevel@tonic-gate 			return (empty_result(DB_STORAGE_LIMIT));
375*7c478bd9Sstevel@tonic-gate 		}
376*7c478bd9Sstevel@tonic-gate 		break;
377*7c478bd9Sstevel@tonic-gate 	}
378*7c478bd9Sstevel@tonic-gate 	res = exec_action(action, query, content, NULL);
379*7c478bd9Sstevel@tonic-gate 	internal_db.change_version(v);
380*7c478bd9Sstevel@tonic-gate 	delete v;
381*7c478bd9Sstevel@tonic-gate 	changed = TRUE;
382*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, empty_result(DB_LOCK_ERROR), "wu db::log_action");
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	return (res);
385*7c478bd9Sstevel@tonic-gate }
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate /*
388*7c478bd9Sstevel@tonic-gate  * Execute 'action' using the rest of the arguments as input.
389*7c478bd9Sstevel@tonic-gate  * Return the result of the operation in a db_result structure;
390*7c478bd9Sstevel@tonic-gate  * Return NULL if the request is unknown.
391*7c478bd9Sstevel@tonic-gate  * If the action involves updates (ADD and REMOVE), it is logged first.
392*7c478bd9Sstevel@tonic-gate  */
393*7c478bd9Sstevel@tonic-gate db_result *
394*7c478bd9Sstevel@tonic-gate db::execute(db_action action, db_query *query,
395*7c478bd9Sstevel@tonic-gate 		entry_object *content, db_next_desc* previous)
396*7c478bd9Sstevel@tonic-gate {
397*7c478bd9Sstevel@tonic-gate 	db_result	*res;
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	switch (action) {
400*7c478bd9Sstevel@tonic-gate 	case DB_LOOKUP:
401*7c478bd9Sstevel@tonic-gate 	case DB_FIRST:
402*7c478bd9Sstevel@tonic-gate 	case DB_NEXT:
403*7c478bd9Sstevel@tonic-gate 	case DB_ALL:
404*7c478bd9Sstevel@tonic-gate 	case DB_RESET_NEXT:
405*7c478bd9Sstevel@tonic-gate 		READLOCK(this, empty_result(DB_LOCK_ERROR), "r db::execute");
406*7c478bd9Sstevel@tonic-gate 		res = exec_action(action, query, content, previous);
407*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, empty_result(DB_LOCK_ERROR),
408*7c478bd9Sstevel@tonic-gate 				"ru db::execute");
409*7c478bd9Sstevel@tonic-gate 		return (res);
410*7c478bd9Sstevel@tonic-gate 
411*7c478bd9Sstevel@tonic-gate 	case DB_ADD_NOLOG:
412*7c478bd9Sstevel@tonic-gate 		WRITELOCK(this, empty_result(DB_LOCK_ERROR), "w db::execute");
413*7c478bd9Sstevel@tonic-gate 		changed = TRUE;
414*7c478bd9Sstevel@tonic-gate 		res = exec_action(DB_ADD, query, content, previous);
415*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, empty_result(DB_LOCK_ERROR),
416*7c478bd9Sstevel@tonic-gate 				"wu db::execute");
417*7c478bd9Sstevel@tonic-gate 		return (res);
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	case DB_ADD:
420*7c478bd9Sstevel@tonic-gate 	case DB_REMOVE:
421*7c478bd9Sstevel@tonic-gate 	case DB_ADD_NOSYNC:
422*7c478bd9Sstevel@tonic-gate 	case DB_REMOVE_NOSYNC:
423*7c478bd9Sstevel@tonic-gate 		/* log_action() will do the locking */
424*7c478bd9Sstevel@tonic-gate 		return (log_action(action, query, content));
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	default:
427*7c478bd9Sstevel@tonic-gate 		WARNING("db::execute: unknown request");
428*7c478bd9Sstevel@tonic-gate 		return (empty_result(DB_INTERNAL_ERROR));
429*7c478bd9Sstevel@tonic-gate 	}
430*7c478bd9Sstevel@tonic-gate }
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate /* close existing logfile and delete its structure */
433*7c478bd9Sstevel@tonic-gate int
434*7c478bd9Sstevel@tonic-gate db::reset_log()
435*7c478bd9Sstevel@tonic-gate {
436*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db::reset_log");
437*7c478bd9Sstevel@tonic-gate 	/* try to close old log file */
438*7c478bd9Sstevel@tonic-gate 	/* doesnot matter since we do synchronous writes only */
439*7c478bd9Sstevel@tonic-gate 	if (logfile != NULL) {
440*7c478bd9Sstevel@tonic-gate 	    if (logfile_opened == TRUE) {
441*7c478bd9Sstevel@tonic-gate 		    logfile->sync_log();
442*7c478bd9Sstevel@tonic-gate 		    if (logfile->close() < 0) {
443*7c478bd9Sstevel@tonic-gate 			WARNING_M("db::reset_log: could not close log file: ");
444*7c478bd9Sstevel@tonic-gate 		    }
445*7c478bd9Sstevel@tonic-gate 		    remove_from_standby_list(this);
446*7c478bd9Sstevel@tonic-gate 	    }
447*7c478bd9Sstevel@tonic-gate 	    delete logfile;
448*7c478bd9Sstevel@tonic-gate 	    logfile = NULL;
449*7c478bd9Sstevel@tonic-gate 	}
450*7c478bd9Sstevel@tonic-gate 	logfile_opened = FALSE;
451*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db::reset_log");
452*7c478bd9Sstevel@tonic-gate 	return (0);
453*7c478bd9Sstevel@tonic-gate }
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate /* close existing logfile, but leave its structure if exists */
456*7c478bd9Sstevel@tonic-gate int
457*7c478bd9Sstevel@tonic-gate db::close_log(int bypass_standby)
458*7c478bd9Sstevel@tonic-gate {
459*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db::close_log");
460*7c478bd9Sstevel@tonic-gate 	if (logfile != NULL && logfile_opened == TRUE) {
461*7c478bd9Sstevel@tonic-gate 		logfile->sync_log();
462*7c478bd9Sstevel@tonic-gate 		logfile->close();
463*7c478bd9Sstevel@tonic-gate 		if (!bypass_standby)
464*7c478bd9Sstevel@tonic-gate 		    remove_from_standby_list(this);
465*7c478bd9Sstevel@tonic-gate 	}
466*7c478bd9Sstevel@tonic-gate 	logfile_opened = FALSE;
467*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db::close_log");
468*7c478bd9Sstevel@tonic-gate 	return (0);
469*7c478bd9Sstevel@tonic-gate }
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate /* open logfile, creating its structure if it does not exist */
472*7c478bd9Sstevel@tonic-gate int
473*7c478bd9Sstevel@tonic-gate db::open_log(bool_t copylog)
474*7c478bd9Sstevel@tonic-gate {
475*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db::open_log");
476*7c478bd9Sstevel@tonic-gate 	if (logfile == NULL) {
477*7c478bd9Sstevel@tonic-gate 		if ((logfile = new db_log(logfilename, PICKLE_APPEND))
478*7c478bd9Sstevel@tonic-gate 		    == NULL)
479*7c478bd9Sstevel@tonic-gate 			FATAL3("db::reset_log: cannot allocate space",
480*7c478bd9Sstevel@tonic-gate 			    DB_MEMORY_LIMIT, -1);
481*7c478bd9Sstevel@tonic-gate 	}
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	if (logfile_opened == TRUE) {
484*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, -1, "wu db::open_log");
485*7c478bd9Sstevel@tonic-gate 		return (0);
486*7c478bd9Sstevel@tonic-gate 	}
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate 	logfile->copylog = copylog;
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	if ((logfile->open()) == NULL){
491*7c478bd9Sstevel@tonic-gate 		WARNING_M("db::open_log: could not open log file: ");
492*7c478bd9Sstevel@tonic-gate 		delete logfile;
493*7c478bd9Sstevel@tonic-gate 		logfile = NULL;
494*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, -1, "wu db::open_log");
495*7c478bd9Sstevel@tonic-gate 		return (-1);
496*7c478bd9Sstevel@tonic-gate 	}
497*7c478bd9Sstevel@tonic-gate 	add_to_standby_list(this);
498*7c478bd9Sstevel@tonic-gate 	logfile_opened = TRUE;
499*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db::open_log");
500*7c478bd9Sstevel@tonic-gate 	return (0);
501*7c478bd9Sstevel@tonic-gate }
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate /*
504*7c478bd9Sstevel@tonic-gate  * Execute log entry 'j' on the database identified by 'dbchar' if the
505*7c478bd9Sstevel@tonic-gate  * version of j is later than that of the database.  If 'j' is executed,
506*7c478bd9Sstevel@tonic-gate  * 'count' is incremented and the database's verison is updated to that of 'j'.
507*7c478bd9Sstevel@tonic-gate  * Returns TRUE always for valid log entries; FALSE otherwise.
508*7c478bd9Sstevel@tonic-gate  */
509*7c478bd9Sstevel@tonic-gate static bool_t
510*7c478bd9Sstevel@tonic-gate apply_log_entry(db_log_entry * j, char * dbchar, int *count)
511*7c478bd9Sstevel@tonic-gate {
512*7c478bd9Sstevel@tonic-gate 	db_mindex * db = (db_mindex *) dbchar;
513*7c478bd9Sstevel@tonic-gate 	bool_t status = TRUE;
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	WRITELOCK(db, FALSE, "db::apply_log_entry");
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 	if (db->get_version()->earlier_than(j->get_version())) {
518*7c478bd9Sstevel@tonic-gate 		++ *count;
519*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
520*7c478bd9Sstevel@tonic-gate 		j->print();
521*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
522*7c478bd9Sstevel@tonic-gate 		switch (j->get_action()) {
523*7c478bd9Sstevel@tonic-gate 		case DB_ADD:
524*7c478bd9Sstevel@tonic-gate 		case DB_ADD_NOSYNC:
525*7c478bd9Sstevel@tonic-gate 			db->add(j->get_query(), j->get_object());
526*7c478bd9Sstevel@tonic-gate 			break;
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 		case DB_REMOVE:
529*7c478bd9Sstevel@tonic-gate 		case DB_REMOVE_NOSYNC:
530*7c478bd9Sstevel@tonic-gate 			db->remove(j->get_query());
531*7c478bd9Sstevel@tonic-gate 			break;
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 		default:
534*7c478bd9Sstevel@tonic-gate 			WARNING("db::apply_log_entry: unknown action_type");
535*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(db, FALSE, "db::apply_log_entry");
536*7c478bd9Sstevel@tonic-gate 			return (FALSE);
537*7c478bd9Sstevel@tonic-gate 		}
538*7c478bd9Sstevel@tonic-gate 		db->change_version(j->get_version());
539*7c478bd9Sstevel@tonic-gate 	}
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(db, FALSE, "db::apply_log_entry");
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 	return (TRUE);  /* always want to TRUE if action valid ? */
544*7c478bd9Sstevel@tonic-gate }
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate /*
547*7c478bd9Sstevel@tonic-gate  * Execute log entry 'j' on this db.  'j' is executed if its version is
548*7c478bd9Sstevel@tonic-gate  * later than that of the database; if executed, the database's version
549*7c478bd9Sstevel@tonic-gate  * will be changed to that of 'j', regardless of the status of the operation.
550*7c478bd9Sstevel@tonic-gate  * Returns TRUE if 'j' was executed;   FALSE if it was not.
551*7c478bd9Sstevel@tonic-gate  * Log entry is added to this database's log if log_entry is applied.
552*7c478bd9Sstevel@tonic-gate  */
553*7c478bd9Sstevel@tonic-gate bool_t
554*7c478bd9Sstevel@tonic-gate db::execute_log_entry(db_log_entry *j)
555*7c478bd9Sstevel@tonic-gate {
556*7c478bd9Sstevel@tonic-gate 	int count = 0;
557*7c478bd9Sstevel@tonic-gate 	apply_log_entry (j, (char *) &internal_db, &count);
558*7c478bd9Sstevel@tonic-gate 	bool_t copylog = FALSE;
559*7c478bd9Sstevel@tonic-gate 	db_action action;
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	/*
562*7c478bd9Sstevel@tonic-gate 	 * If this is a synchronous operation on the master we should
563*7c478bd9Sstevel@tonic-gate 	 * not copy the log for each operation.  Doing so causes
564*7c478bd9Sstevel@tonic-gate 	 * massive disk IO that hampers the performance of these operations.
565*7c478bd9Sstevel@tonic-gate 	 * Where as on the replica these operations are not synchronous
566*7c478bd9Sstevel@tonic-gate 	 * (batched) and don't affect the performance as much.
567*7c478bd9Sstevel@tonic-gate 	 */
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	action = j->get_action();
570*7c478bd9Sstevel@tonic-gate 	if ((action == DB_ADD_NOSYNC) || (action == DB_REMOVE_NOSYNC))
571*7c478bd9Sstevel@tonic-gate 		copylog = TRUE;
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	/*
574*7c478bd9Sstevel@tonic-gate 	 * should really record the log entry first, but can''t do that without
575*7c478bd9Sstevel@tonic-gate 	 * knowing whether the log entry is applicable.
576*7c478bd9Sstevel@tonic-gate 	 */
577*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db::execute_log_entry");
578*7c478bd9Sstevel@tonic-gate 	if (count == 1) {
579*7c478bd9Sstevel@tonic-gate 		if (open_log(copylog) < 0) {
580*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, FALSE, "wu db::execute_log_entry");
581*7c478bd9Sstevel@tonic-gate 			return (FALSE);
582*7c478bd9Sstevel@tonic-gate 		}
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 		if (logfile->append(j) < 0) {
585*7c478bd9Sstevel@tonic-gate 			close_log();
586*7c478bd9Sstevel@tonic-gate 			WARNING_M(
587*7c478bd9Sstevel@tonic-gate 			"db::execute_log_entry: could not add log entry: ");
588*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, FALSE, "wu db::execute_log_entry");
589*7c478bd9Sstevel@tonic-gate 			return (FALSE);
590*7c478bd9Sstevel@tonic-gate 		}
591*7c478bd9Sstevel@tonic-gate //	  close_log();  /* do this asynchronously */
592*7c478bd9Sstevel@tonic-gate 	}
593*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, FALSE, "wu db::execute_log_entry");
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	return (count == 1);
596*7c478bd9Sstevel@tonic-gate }
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate /* Incorporate updates in log to database already loaded.
599*7c478bd9Sstevel@tonic-gate 	    Does not affect "logfile" */
600*7c478bd9Sstevel@tonic-gate int
601*7c478bd9Sstevel@tonic-gate db::incorporate_log(char* filename)
602*7c478bd9Sstevel@tonic-gate {
603*7c478bd9Sstevel@tonic-gate 	db_log f(filename, PICKLE_READ);
604*7c478bd9Sstevel@tonic-gate 	int ret;
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db::incorporate_log");
607*7c478bd9Sstevel@tonic-gate 	WRITELOCK2((&internal_db), -1, "w internal_db db::incorporate_log",
608*7c478bd9Sstevel@tonic-gate 			this);
609*7c478bd9Sstevel@tonic-gate 	internal_db.setNoWriteThrough();
610*7c478bd9Sstevel@tonic-gate 	ret = f.execute_on_log(&(apply_log_entry), (char *) &internal_db);
611*7c478bd9Sstevel@tonic-gate 	internal_db.clearNoWriteThrough();
612*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK2(this, (&internal_db), ret, ret,
613*7c478bd9Sstevel@tonic-gate 			"wu db::incorporate_log",
614*7c478bd9Sstevel@tonic-gate 			"wu mindex db::incorporate_log");
615*7c478bd9Sstevel@tonic-gate 	return (ret);
616*7c478bd9Sstevel@tonic-gate }
617*7c478bd9Sstevel@tonic-gate 
618*7c478bd9Sstevel@tonic-gate /* Load database and incorporate any logged updates into the loaded copy.
619*7c478bd9Sstevel@tonic-gate 	    Return TRUE if load succeeds; FALSE otherwise. */
620*7c478bd9Sstevel@tonic-gate bool_t
621*7c478bd9Sstevel@tonic-gate db::load()
622*7c478bd9Sstevel@tonic-gate {
623*7c478bd9Sstevel@tonic-gate 	int count;
624*7c478bd9Sstevel@tonic-gate 	int load_status;
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db::load");
627*7c478bd9Sstevel@tonic-gate 	if (changed == TRUE)
628*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
629*7c478bd9Sstevel@tonic-gate 	"WARNING: the current db '%s' has been changed but not checkpointed",
630*7c478bd9Sstevel@tonic-gate 			dbfilename);
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	unlink(tmpfilename);  /* get rid of partial checkpoints */
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	if ((load_status = internal_db.load(dbfilename)) != 0) {
635*7c478bd9Sstevel@tonic-gate 	    if (load_status < 0)
636*7c478bd9Sstevel@tonic-gate 		    syslog(LOG_ERR, "Load of db '%s' failed", dbfilename);
637*7c478bd9Sstevel@tonic-gate 	    /* otherwise, there was just nothing to load */
638*7c478bd9Sstevel@tonic-gate 	    WRITEUNLOCK(this, FALSE, "wu db::load");
639*7c478bd9Sstevel@tonic-gate 	    return (FALSE);
640*7c478bd9Sstevel@tonic-gate 	}
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 	changed = FALSE;
643*7c478bd9Sstevel@tonic-gate 	reset_log();
644*7c478bd9Sstevel@tonic-gate 	WRITELOCK2((&internal_db), FALSE, "w internal_db db::load", this);
645*7c478bd9Sstevel@tonic-gate 	internal_db.setInitialLoad();
646*7c478bd9Sstevel@tonic-gate 	if ((count = incorporate_log(logfilename)) < 0)
647*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "incorporation of db logfile '%s' load failed",
648*7c478bd9Sstevel@tonic-gate 	    logfilename);
649*7c478bd9Sstevel@tonic-gate 	changed = (count > 0);
650*7c478bd9Sstevel@tonic-gate 	internal_db.clearInitialLoad();
651*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK2(this, (&internal_db),
652*7c478bd9Sstevel@tonic-gate 			(changed ? TRUE : FALSE), (changed ? TRUE : FALSE),
653*7c478bd9Sstevel@tonic-gate 			"wu db::load", "wu internal_db db::load");
654*7c478bd9Sstevel@tonic-gate 	return (TRUE);
655*7c478bd9Sstevel@tonic-gate }
656*7c478bd9Sstevel@tonic-gate 
657*7c478bd9Sstevel@tonic-gate /*
658*7c478bd9Sstevel@tonic-gate  * Initialize the database using table scheme 's'.
659*7c478bd9Sstevel@tonic-gate  * Because the 'scheme' must be 'remembered' between restarts,
660*7c478bd9Sstevel@tonic-gate  * after the initialization, the empty database is checkpointed to record
661*7c478bd9Sstevel@tonic-gate  * the scheme. Returns TRUE if initialization succeeds; FALSE otherwise.
662*7c478bd9Sstevel@tonic-gate  */
663*7c478bd9Sstevel@tonic-gate bool_t
664*7c478bd9Sstevel@tonic-gate db::init(db_scheme * s)
665*7c478bd9Sstevel@tonic-gate {
666*7c478bd9Sstevel@tonic-gate 	bool_t	ret = FALSE;
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db::init");
669*7c478bd9Sstevel@tonic-gate 	internal_db.init(s);
670*7c478bd9Sstevel@tonic-gate 	if (internal_db.good()) {
671*7c478bd9Sstevel@tonic-gate 		unlink(tmpfilename);	/* delete partial checkpoints */
672*7c478bd9Sstevel@tonic-gate 		unlink(logfilename);	/* delete previous logfile */
673*7c478bd9Sstevel@tonic-gate 		reset_log();
674*7c478bd9Sstevel@tonic-gate 		changed = TRUE;		/* force dump to get scheme stored. */
675*7c478bd9Sstevel@tonic-gate 		ret = checkpoint();
676*7c478bd9Sstevel@tonic-gate 	}
677*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, FALSE, "wu db::init");
678*7c478bd9Sstevel@tonic-gate 	return (ret);
679*7c478bd9Sstevel@tonic-gate }
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate /*
682*7c478bd9Sstevel@tonic-gate     Write out in-memory copy of database to file.
683*7c478bd9Sstevel@tonic-gate 	    1.  Update major version.
684*7c478bd9Sstevel@tonic-gate 	    2.  Dump contents to temporary file.
685*7c478bd9Sstevel@tonic-gate 	    3.  Rename temporary file to real database file.
686*7c478bd9Sstevel@tonic-gate 	    4.  Remove log file.
687*7c478bd9Sstevel@tonic-gate     A checkpoint is done only if it has changed since the previous checkpoint.
688*7c478bd9Sstevel@tonic-gate     Returns TRUE if checkpoint was successful; FALSE otherwise.
689*7c478bd9Sstevel@tonic-gate */
690*7c478bd9Sstevel@tonic-gate bool_t
691*7c478bd9Sstevel@tonic-gate db::checkpoint()
692*7c478bd9Sstevel@tonic-gate {
693*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db::checkpoint");
694*7c478bd9Sstevel@tonic-gate 	if (changed == FALSE) {
695*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE, "wu db::checkpoint");
696*7c478bd9Sstevel@tonic-gate 		return (TRUE);
697*7c478bd9Sstevel@tonic-gate 	}
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	vers *oldversion = new vers(internal_db.get_version()); /* copy */
700*7c478bd9Sstevel@tonic-gate 	vers *nextversion = oldversion->nextmajor();	/* get next version */
701*7c478bd9Sstevel@tonic-gate 	internal_db.change_version(nextversion);	/* change version */
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	if (internal_db.dump(tmpfilename) < 0) {  	/* dump to tempfile */
704*7c478bd9Sstevel@tonic-gate 		WARNING_M("db::checkpoint: could not dump database: ");
705*7c478bd9Sstevel@tonic-gate 		internal_db.change_version(oldversion);	/* rollback */
706*7c478bd9Sstevel@tonic-gate 		delete nextversion;
707*7c478bd9Sstevel@tonic-gate 		delete oldversion;
708*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE, "wu db::checkpoint");
709*7c478bd9Sstevel@tonic-gate 		return (FALSE);
710*7c478bd9Sstevel@tonic-gate 	}
711*7c478bd9Sstevel@tonic-gate 	if (rename(tmpfilename, dbfilename) < 0){  	/* rename permanently */
712*7c478bd9Sstevel@tonic-gate 		WARNING_M(
713*7c478bd9Sstevel@tonic-gate 		    "db::checkpoint: could not rename temp file to db file: ");
714*7c478bd9Sstevel@tonic-gate 		internal_db.change_version(oldversion);	/* rollback */
715*7c478bd9Sstevel@tonic-gate 		delete nextversion;
716*7c478bd9Sstevel@tonic-gate 		delete oldversion;
717*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE, "wu db::checkpoint");
718*7c478bd9Sstevel@tonic-gate 		return (FALSE);
719*7c478bd9Sstevel@tonic-gate 	}
720*7c478bd9Sstevel@tonic-gate 	reset_log();		/* should check for what? */
721*7c478bd9Sstevel@tonic-gate 	unlink(logfilename);	/* should do atomic rename and log delete */
722*7c478bd9Sstevel@tonic-gate 	delete nextversion;
723*7c478bd9Sstevel@tonic-gate 	delete oldversion;
724*7c478bd9Sstevel@tonic-gate 	changed = FALSE;
725*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, FALSE, "wu db::checkpoint");
726*7c478bd9Sstevel@tonic-gate 	return (TRUE);
727*7c478bd9Sstevel@tonic-gate }
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 
730*7c478bd9Sstevel@tonic-gate /* For generating log_list */
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate struct traverse_info {
733*7c478bd9Sstevel@tonic-gate 	vers *version;		// version to check for
734*7c478bd9Sstevel@tonic-gate 	db_log_entry * head;	// head of list of log entries found
735*7c478bd9Sstevel@tonic-gate 	db_log_entry * tail;	// tail of list of log entries found
736*7c478bd9Sstevel@tonic-gate };
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate /*
739*7c478bd9Sstevel@tonic-gate  * For the given entry determine, if it is later than the version supplied,
740*7c478bd9Sstevel@tonic-gate  *	    1.  increment 'count'.
741*7c478bd9Sstevel@tonic-gate  *	    2.  add the entry to the list of log entries found.
742*7c478bd9Sstevel@tonic-gate  *
743*7c478bd9Sstevel@tonic-gate  * Since traversal happens on an automatic (struct traverse_info) in
744*7c478bd9Sstevel@tonic-gate  * db::get_log_entries_since(), no locking is necessary.
745*7c478bd9Sstevel@tonic-gate  */
746*7c478bd9Sstevel@tonic-gate static bool_t entry_since(db_log_entry * j, char * tichar, int *count)
747*7c478bd9Sstevel@tonic-gate {
748*7c478bd9Sstevel@tonic-gate 	traverse_info *ti = (traverse_info*) tichar;
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	if (ti->version->earlier_than(j->get_version())) {
751*7c478bd9Sstevel@tonic-gate 		++ *count;
752*7c478bd9Sstevel@tonic-gate //    j->print();   // debug
753*7c478bd9Sstevel@tonic-gate 		if (ti->head == NULL)
754*7c478bd9Sstevel@tonic-gate 			ti->head = j;
755*7c478bd9Sstevel@tonic-gate 		else {
756*7c478bd9Sstevel@tonic-gate 			ti->tail->setnextptr(j); // make last entry point to j
757*7c478bd9Sstevel@tonic-gate 		}
758*7c478bd9Sstevel@tonic-gate 		ti->tail = j;			// make j new last entry
759*7c478bd9Sstevel@tonic-gate 	}
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate 	return (TRUE);
762*7c478bd9Sstevel@tonic-gate }
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate /* Return structure db_log_list containing entries that are later
765*7c478bd9Sstevel@tonic-gate 	    than the version 'v' given.  */
766*7c478bd9Sstevel@tonic-gate db_log_list*
767*7c478bd9Sstevel@tonic-gate db::get_log_entries_since(vers * v)
768*7c478bd9Sstevel@tonic-gate {
769*7c478bd9Sstevel@tonic-gate 	int count;
770*7c478bd9Sstevel@tonic-gate 	struct traverse_info ti;
771*7c478bd9Sstevel@tonic-gate 	db_log f(logfilename, PICKLE_READ);
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	ti.version = v;
774*7c478bd9Sstevel@tonic-gate 	ti.head = ti.tail = NULL;
775*7c478bd9Sstevel@tonic-gate 
776*7c478bd9Sstevel@tonic-gate 	count = f.execute_on_log(&(entry_since), (char *) &ti, FALSE);
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	db_log_list * answer = new db_log_list;
779*7c478bd9Sstevel@tonic-gate 
780*7c478bd9Sstevel@tonic-gate 	if (answer == NULL)
781*7c478bd9Sstevel@tonic-gate 		FATAL3("db::get_log_entries_since: cannot allocate space",
782*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, NULL);
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 	answer->list.list_len = count;
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate 	if (count > 0) {
787*7c478bd9Sstevel@tonic-gate 		db_log_entry_p *entries;
788*7c478bd9Sstevel@tonic-gate 		db_log_entry_p currentry, nextentry;
789*7c478bd9Sstevel@tonic-gate 		int i;
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate 		entries = answer->list.list_val = new db_log_entry_p[count];
792*7c478bd9Sstevel@tonic-gate 		if (entries == NULL) {
793*7c478bd9Sstevel@tonic-gate 			delete answer;
794*7c478bd9Sstevel@tonic-gate 			FATAL3(
795*7c478bd9Sstevel@tonic-gate 		"db::get_log_entries_since: cannot allocate space for entries",
796*7c478bd9Sstevel@tonic-gate 		DB_MEMORY_LIMIT, NULL);
797*7c478bd9Sstevel@tonic-gate 			}
798*7c478bd9Sstevel@tonic-gate 		currentry = ti.head;
799*7c478bd9Sstevel@tonic-gate 		for (i = 0, currentry = ti.head;
800*7c478bd9Sstevel@tonic-gate 			i < count && currentry != NULL;
801*7c478bd9Sstevel@tonic-gate 			i++) {
802*7c478bd9Sstevel@tonic-gate 			entries[i] = currentry;
803*7c478bd9Sstevel@tonic-gate 			nextentry = currentry->getnextptr();
804*7c478bd9Sstevel@tonic-gate 			currentry->setnextptr(NULL);
805*7c478bd9Sstevel@tonic-gate 			currentry = nextentry;
806*7c478bd9Sstevel@tonic-gate 		}
807*7c478bd9Sstevel@tonic-gate 	} else
808*7c478bd9Sstevel@tonic-gate 		answer->list.list_val = NULL;
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	return (answer);
811*7c478bd9Sstevel@tonic-gate }
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate /* Delete all files associated with database. */
814*7c478bd9Sstevel@tonic-gate int
815*7c478bd9Sstevel@tonic-gate db::remove_files()
816*7c478bd9Sstevel@tonic-gate {
817*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db::remove_files");
818*7c478bd9Sstevel@tonic-gate 	unlink(tmpfilename);  /* delete partial checkpoints */
819*7c478bd9Sstevel@tonic-gate 	reset_log();
820*7c478bd9Sstevel@tonic-gate 	unlink(logfilename);  /* delete logfile */
821*7c478bd9Sstevel@tonic-gate 	unlink(dbfilename);   /* delete database file */
822*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db::remove_files");
823*7c478bd9Sstevel@tonic-gate 	return (0);
824*7c478bd9Sstevel@tonic-gate }
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate db_status
827*7c478bd9Sstevel@tonic-gate db::sync_log() {
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	db_status	ret;
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db::sync_log");
832*7c478bd9Sstevel@tonic-gate 	if (logfile == 0) {
833*7c478bd9Sstevel@tonic-gate 		ret = DB_BADTABLE;
834*7c478bd9Sstevel@tonic-gate 	} else {
835*7c478bd9Sstevel@tonic-gate 		if (logfile_opened == FALSE || logfile->sync_log())
836*7c478bd9Sstevel@tonic-gate 			ret = DB_SUCCESS;
837*7c478bd9Sstevel@tonic-gate 		else
838*7c478bd9Sstevel@tonic-gate 			ret = DB_SYNC_FAILED;
839*7c478bd9Sstevel@tonic-gate 	}
840*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, DB_LOCK_ERROR, "wu db::sync_log");
841*7c478bd9Sstevel@tonic-gate 	return (ret);
842*7c478bd9Sstevel@tonic-gate }
843*7c478bd9Sstevel@tonic-gate 
844*7c478bd9Sstevel@tonic-gate /* Pass configuration information to the db_mindex */
845*7c478bd9Sstevel@tonic-gate bool_t
846*7c478bd9Sstevel@tonic-gate db::configure(char *objName) {
847*7c478bd9Sstevel@tonic-gate 	return (internal_db.configure(objName));
848*7c478bd9Sstevel@tonic-gate }
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate db_mindex *
851*7c478bd9Sstevel@tonic-gate db::mindex(void) {
852*7c478bd9Sstevel@tonic-gate 	return (&internal_db);
853*7c478bd9Sstevel@tonic-gate }
854