xref: /titanic_53/usr/src/lib/libnisdb/db_dictionary.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_dictionary.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 "db_headers.h"
32*7c478bd9Sstevel@tonic-gate #include "db_entry.h"
33*7c478bd9Sstevel@tonic-gate #include "db_dictionary.h"
34*7c478bd9Sstevel@tonic-gate #include "db_dictlog.h"
35*7c478bd9Sstevel@tonic-gate #include "db_vers.h"
36*7c478bd9Sstevel@tonic-gate #include "nisdb_mt.h"
37*7c478bd9Sstevel@tonic-gate #include "nisdb_rw.h"
38*7c478bd9Sstevel@tonic-gate #include "ldap_parse.h"
39*7c478bd9Sstevel@tonic-gate #include "ldap_map.h"
40*7c478bd9Sstevel@tonic-gate #include "nis_hashitem.h"
41*7c478bd9Sstevel@tonic-gate #include "ldap_util.h"
42*7c478bd9Sstevel@tonic-gate #include "nis_db.h"
43*7c478bd9Sstevel@tonic-gate #include <rpcsvc/nis.h>
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #include <stdio.h>
46*7c478bd9Sstevel@tonic-gate #include <string.h>
47*7c478bd9Sstevel@tonic-gate #include <malloc.h>
48*7c478bd9Sstevel@tonic-gate #ifdef TDRPC
49*7c478bd9Sstevel@tonic-gate #include <sysent.h>
50*7c478bd9Sstevel@tonic-gate #endif
51*7c478bd9Sstevel@tonic-gate #include <unistd.h>
52*7c478bd9Sstevel@tonic-gate #include <syslog.h>
53*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate typedef bool_t	(*db_func)(XDR *, db_table_desc *);
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate extern db_dictionary *InUseDictionary;
58*7c478bd9Sstevel@tonic-gate extern db_dictionary *FreeDictionary;
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /* *************** dictionary version ****************** */
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate #define	DB_MAGIC 0x12340000
63*7c478bd9Sstevel@tonic-gate #define	DB_MAJOR 0
64*7c478bd9Sstevel@tonic-gate #define	DB_MINOR 10
65*7c478bd9Sstevel@tonic-gate #define	DB_VERSION_0_9	(DB_MAGIC|(DB_MAJOR<<8)|9)
66*7c478bd9Sstevel@tonic-gate #define	DB_ORIG_VERSION	DB_VERSION_0_9
67*7c478bd9Sstevel@tonic-gate #define	DB_CURRENT_VERSION (DB_MAGIC|DB_MAJOR<<8|DB_MINOR)
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate vers db_update_version;   /* Note 'global' for all dbs. */
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate #define	INMEMORY_ONLY 1
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate /*
74*7c478bd9Sstevel@tonic-gate  * Checks for valid version.  For now, there are two:
75*7c478bd9Sstevel@tonic-gate  * DB_VERSION_ORIG was the ORIGINAL one with major = 0, minor = 9
76*7c478bd9Sstevel@tonic-gate  * DB_CURRENT_VERSION is the latest one with changes in the database format
77*7c478bd9Sstevel@tonic-gate  *	for entry objects and the change in the dictionary format.
78*7c478bd9Sstevel@tonic-gate  *
79*7c478bd9Sstevel@tonic-gate  * Our current implementation can support both versions.
80*7c478bd9Sstevel@tonic-gate  */
81*7c478bd9Sstevel@tonic-gate static inline bool_t
82*7c478bd9Sstevel@tonic-gate db_valid_version(u_int vers)
83*7c478bd9Sstevel@tonic-gate {
84*7c478bd9Sstevel@tonic-gate 	return ((vers == DB_CURRENT_VERSION) || (vers == DB_ORIG_VERSION));
85*7c478bd9Sstevel@tonic-gate }
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate static char *
88*7c478bd9Sstevel@tonic-gate db_version_str(u_int vers)
89*7c478bd9Sstevel@tonic-gate {
90*7c478bd9Sstevel@tonic-gate 	static char vstr[128];
91*7c478bd9Sstevel@tonic-gate 	u_int d_major =  (vers&0x0000ff00)>>8;
92*7c478bd9Sstevel@tonic-gate 	u_int d_minor =  (vers&0x000000ff);
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 	sprintf(vstr, "SunSoft, SSM, Version %d.%d", d_major, d_minor);
95*7c478bd9Sstevel@tonic-gate 	return (vstr);
96*7c478bd9Sstevel@tonic-gate }
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate /*
99*7c478bd9Sstevel@tonic-gate  * Special XDR version that checks for a valid version number.
100*7c478bd9Sstevel@tonic-gate  * If we don't find an acceptable version, exit immediately instead
101*7c478bd9Sstevel@tonic-gate  * of continuing to xdr rest of dictionary, which might lead to
102*7c478bd9Sstevel@tonic-gate  * a core dump if the formats between versions are incompatible.
103*7c478bd9Sstevel@tonic-gate  * In the future, there might be a switch to determine versions
104*7c478bd9Sstevel@tonic-gate  * and their corresponding XDR routines for the rest of the dictionary.
105*7c478bd9Sstevel@tonic-gate  */
106*7c478bd9Sstevel@tonic-gate extern "C" {
107*7c478bd9Sstevel@tonic-gate bool_t
108*7c478bd9Sstevel@tonic-gate xdr_db_dict_version(XDR *xdrs, db_dict_version *objp)
109*7c478bd9Sstevel@tonic-gate {
110*7c478bd9Sstevel@tonic-gate 	if (xdrs->x_op == XDR_DECODE) {
111*7c478bd9Sstevel@tonic-gate 		if (!xdr_u_int(xdrs, (u_int*) objp) ||
112*7c478bd9Sstevel@tonic-gate 		    !db_valid_version(((u_int) *objp))) {
113*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
114*7c478bd9Sstevel@tonic-gate 	"db_dictionary: invalid dictionary format! Expecting %s",
115*7c478bd9Sstevel@tonic-gate 				db_version_str(DB_CURRENT_VERSION));
116*7c478bd9Sstevel@tonic-gate 			fprintf(stderr,
117*7c478bd9Sstevel@tonic-gate 	"db_dictionary: invalid dictionary format! Expecting %s\n",
118*7c478bd9Sstevel@tonic-gate 				db_version_str(DB_CURRENT_VERSION));
119*7c478bd9Sstevel@tonic-gate 			exit(1);
120*7c478bd9Sstevel@tonic-gate 		}
121*7c478bd9Sstevel@tonic-gate 	} else if (!xdr_u_int(xdrs, (u_int*) objp))
122*7c478bd9Sstevel@tonic-gate 		return (FALSE);
123*7c478bd9Sstevel@tonic-gate 	return (TRUE);
124*7c478bd9Sstevel@tonic-gate }
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate void
127*7c478bd9Sstevel@tonic-gate make_zero(vers* v)
128*7c478bd9Sstevel@tonic-gate {
129*7c478bd9Sstevel@tonic-gate 	v->zero();
130*7c478bd9Sstevel@tonic-gate }
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate };
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate /* ******************* dictionary data structures *************** */
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate /* Delete contents of single db_table_desc pointed to by 'current.' */
139*7c478bd9Sstevel@tonic-gate static void
140*7c478bd9Sstevel@tonic-gate delete_table_desc(db_table_desc *current)
141*7c478bd9Sstevel@tonic-gate {
142*7c478bd9Sstevel@tonic-gate 	if (current->table_name != NULL) delete current->table_name;
143*7c478bd9Sstevel@tonic-gate 	if (current->scheme != NULL) delete current->scheme;
144*7c478bd9Sstevel@tonic-gate 	if (current->database != NULL) delete current->database;
145*7c478bd9Sstevel@tonic-gate 	delete current;
146*7c478bd9Sstevel@tonic-gate }
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate /* Create new table descriptor using given table name and table_object. */
149*7c478bd9Sstevel@tonic-gate db_status
150*7c478bd9Sstevel@tonic-gate db_dictionary::create_table_desc(char *tab, table_obj* zdesc,
151*7c478bd9Sstevel@tonic-gate 				db_table_desc** answer)
152*7c478bd9Sstevel@tonic-gate {
153*7c478bd9Sstevel@tonic-gate 	db_table_desc *newtab;
154*7c478bd9Sstevel@tonic-gate 	if ((newtab = new db_table_desc) == NULL) {
155*7c478bd9Sstevel@tonic-gate 		FATAL3(
156*7c478bd9Sstevel@tonic-gate 	    "db_dictionary::add_table: could not allocate space for new table",
157*7c478bd9Sstevel@tonic-gate 		DB_MEMORY_LIMIT, DB_MEMORY_LIMIT);
158*7c478bd9Sstevel@tonic-gate 	}
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	newtab->database = NULL;
161*7c478bd9Sstevel@tonic-gate 	newtab->table_name = NULL;
162*7c478bd9Sstevel@tonic-gate 	newtab->next = NULL;
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	if ((newtab->scheme = new db_scheme(zdesc)) == NULL) {
165*7c478bd9Sstevel@tonic-gate 		delete_table_desc(newtab);
166*7c478bd9Sstevel@tonic-gate 		FATAL3(
167*7c478bd9Sstevel@tonic-gate 	"db_dictionary::add_table: could not allocate space for scheme",
168*7c478bd9Sstevel@tonic-gate 		DB_MEMORY_LIMIT, DB_MEMORY_LIMIT);
169*7c478bd9Sstevel@tonic-gate 	}
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	if (newtab->scheme->numkeys() == 0) {
172*7c478bd9Sstevel@tonic-gate 		WARNING(
173*7c478bd9Sstevel@tonic-gate 	"db_dictionary::add_table: could not translate table_obj to scheme");
174*7c478bd9Sstevel@tonic-gate 		delete_table_desc(newtab);
175*7c478bd9Sstevel@tonic-gate 		return (DB_BADOBJECT);
176*7c478bd9Sstevel@tonic-gate 	}
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 	if ((newtab->table_name = strdup(tab)) == NULL) {
179*7c478bd9Sstevel@tonic-gate 		delete_table_desc(newtab);
180*7c478bd9Sstevel@tonic-gate 		FATAL3(
181*7c478bd9Sstevel@tonic-gate 	    "db_dictionary::add_table: could not allocate space for table name",
182*7c478bd9Sstevel@tonic-gate 		DB_MEMORY_LIMIT, DB_MEMORY_LIMIT);
183*7c478bd9Sstevel@tonic-gate 	}
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	if (answer)
186*7c478bd9Sstevel@tonic-gate 		*answer = newtab;
187*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
188*7c478bd9Sstevel@tonic-gate }
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate /* Delete list of db_table_desc pointed to by 'head.' */
192*7c478bd9Sstevel@tonic-gate static void
193*7c478bd9Sstevel@tonic-gate delete_bucket(db_table_desc *head)
194*7c478bd9Sstevel@tonic-gate {
195*7c478bd9Sstevel@tonic-gate 	db_table_desc * nextone, *current;
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 	for (current = head; current != NULL; current = nextone) {
198*7c478bd9Sstevel@tonic-gate 		nextone = current->next;	// remember next
199*7c478bd9Sstevel@tonic-gate 		delete_table_desc(current);
200*7c478bd9Sstevel@tonic-gate 	}
201*7c478bd9Sstevel@tonic-gate }
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate static void
204*7c478bd9Sstevel@tonic-gate delete_dictionary(db_dict_desc *dict)
205*7c478bd9Sstevel@tonic-gate {
206*7c478bd9Sstevel@tonic-gate 	db_table_desc* bucket;
207*7c478bd9Sstevel@tonic-gate 	int i;
208*7c478bd9Sstevel@tonic-gate 	if (dict) {
209*7c478bd9Sstevel@tonic-gate 		if (dict->tables.tables_val) {
210*7c478bd9Sstevel@tonic-gate 			/* delete each bucket */
211*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < dict->tables.tables_len; i++)
212*7c478bd9Sstevel@tonic-gate 				bucket = dict->tables.tables_val[i];
213*7c478bd9Sstevel@tonic-gate 				if (bucket)
214*7c478bd9Sstevel@tonic-gate 					delete_bucket(bucket);
215*7c478bd9Sstevel@tonic-gate 			/* delete table */
216*7c478bd9Sstevel@tonic-gate 			delete dict->tables.tables_val;
217*7c478bd9Sstevel@tonic-gate 		}
218*7c478bd9Sstevel@tonic-gate 		/* delete dictionary */
219*7c478bd9Sstevel@tonic-gate 		delete dict;
220*7c478bd9Sstevel@tonic-gate 	}
221*7c478bd9Sstevel@tonic-gate }
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate /* Relocate bucket starting with this entry to new hashtable 'new_tab'. */
224*7c478bd9Sstevel@tonic-gate static void
225*7c478bd9Sstevel@tonic-gate relocate_bucket(db_table_desc* bucket,
226*7c478bd9Sstevel@tonic-gate 		db_table_desc_p *new_tab, unsigned long hashsize)
227*7c478bd9Sstevel@tonic-gate {
228*7c478bd9Sstevel@tonic-gate 	db_table_desc_p np, next_np, *hp;
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate 	for (np = bucket; np != NULL; np = next_np) {
231*7c478bd9Sstevel@tonic-gate 		next_np = np->next;
232*7c478bd9Sstevel@tonic-gate 		hp = &new_tab[np->hashval % hashsize];
233*7c478bd9Sstevel@tonic-gate 		np->next = *hp;
234*7c478bd9Sstevel@tonic-gate 		*hp = np;
235*7c478bd9Sstevel@tonic-gate 	}
236*7c478bd9Sstevel@tonic-gate }
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate /*
239*7c478bd9Sstevel@tonic-gate  * Return pointer to entry with same hash value and table_name
240*7c478bd9Sstevel@tonic-gate  * as those supplied.  Returns NULL if not found.
241*7c478bd9Sstevel@tonic-gate  */
242*7c478bd9Sstevel@tonic-gate static db_status
243*7c478bd9Sstevel@tonic-gate enumerate_bucket(db_table_desc* bucket, db_status(*func)(db_table_desc *))
244*7c478bd9Sstevel@tonic-gate {
245*7c478bd9Sstevel@tonic-gate 	db_table_desc_p np;
246*7c478bd9Sstevel@tonic-gate 	db_status status;
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	for (np = bucket; np != NULL; np = np->next) {
249*7c478bd9Sstevel@tonic-gate 		status = (func)(np);
250*7c478bd9Sstevel@tonic-gate 		if (status != DB_SUCCESS)
251*7c478bd9Sstevel@tonic-gate 			return (status);
252*7c478bd9Sstevel@tonic-gate 	}
253*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
254*7c478bd9Sstevel@tonic-gate }
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate /*
258*7c478bd9Sstevel@tonic-gate  * Return pointer to entry with same hash value and table_name
259*7c478bd9Sstevel@tonic-gate  * as those supplied.  Returns NULL if not found.
260*7c478bd9Sstevel@tonic-gate  */
261*7c478bd9Sstevel@tonic-gate static db_table_desc_p
262*7c478bd9Sstevel@tonic-gate search_bucket(db_table_desc* bucket, unsigned long hval, char *target)
263*7c478bd9Sstevel@tonic-gate {
264*7c478bd9Sstevel@tonic-gate 	db_table_desc_p np;
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	for (np = bucket; np != NULL; np = np->next) {
267*7c478bd9Sstevel@tonic-gate 		if (np->hashval == hval &&
268*7c478bd9Sstevel@tonic-gate 		    strcmp(np->table_name, target) == 0) {
269*7c478bd9Sstevel@tonic-gate 			break;
270*7c478bd9Sstevel@tonic-gate 		}
271*7c478bd9Sstevel@tonic-gate 	}
272*7c478bd9Sstevel@tonic-gate 	return (np);
273*7c478bd9Sstevel@tonic-gate }
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate /*
277*7c478bd9Sstevel@tonic-gate  * Remove entry with the specified hashvalue and target table name.
278*7c478bd9Sstevel@tonic-gate  * Returns 'TRUE' if successful, FALSE otherwise.
279*7c478bd9Sstevel@tonic-gate  * If the entry being removed is at the head of the list, then
280*7c478bd9Sstevel@tonic-gate  * the head is updated to reflect the removal. The storage for the
281*7c478bd9Sstevel@tonic-gate  * entry is freed if desired.
282*7c478bd9Sstevel@tonic-gate  */
283*7c478bd9Sstevel@tonic-gate static bool_t
284*7c478bd9Sstevel@tonic-gate remove_from_bucket(db_table_desc_p bucket,
285*7c478bd9Sstevel@tonic-gate 		db_table_desc_p *head, unsigned long hval, char *target,
286*7c478bd9Sstevel@tonic-gate 		bool_t free_storage)
287*7c478bd9Sstevel@tonic-gate {
288*7c478bd9Sstevel@tonic-gate 	db_table_desc_p np, dp;
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate 	/* Search for it in the bucket */
291*7c478bd9Sstevel@tonic-gate 	for (dp = np = bucket; np != NULL; np = np->next) {
292*7c478bd9Sstevel@tonic-gate 		if (np->hashval == hval &&
293*7c478bd9Sstevel@tonic-gate 		    strcmp(np->table_name, target) == 0) {
294*7c478bd9Sstevel@tonic-gate 			break;
295*7c478bd9Sstevel@tonic-gate 		} else {
296*7c478bd9Sstevel@tonic-gate 			dp = np;
297*7c478bd9Sstevel@tonic-gate 		}
298*7c478bd9Sstevel@tonic-gate 	}
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	if (np == NULL)
301*7c478bd9Sstevel@tonic-gate 		return (FALSE);	// cannot delete if it is not there
302*7c478bd9Sstevel@tonic-gate 
303*7c478bd9Sstevel@tonic-gate 	if (dp == np) {
304*7c478bd9Sstevel@tonic-gate 		*head = np->next;	// deleting head of bucket
305*7c478bd9Sstevel@tonic-gate 	} else {
306*7c478bd9Sstevel@tonic-gate 		dp->next = np->next;	// deleting interior link
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate 	if (free_storage)
309*7c478bd9Sstevel@tonic-gate 		delete_table_desc(np);
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	return (TRUE);
312*7c478bd9Sstevel@tonic-gate }
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate /*
316*7c478bd9Sstevel@tonic-gate  * Add given entry to the bucket pointed to by 'bucket'.
317*7c478bd9Sstevel@tonic-gate  * If an entry with the same table_name is found, no addition
318*7c478bd9Sstevel@tonic-gate  * is done.  The entry is added to the head of the bucket.
319*7c478bd9Sstevel@tonic-gate  */
320*7c478bd9Sstevel@tonic-gate static bool_t
321*7c478bd9Sstevel@tonic-gate add_to_bucket(db_table_desc_p bucket, db_table_desc **head, db_table_desc_p td)
322*7c478bd9Sstevel@tonic-gate {
323*7c478bd9Sstevel@tonic-gate 	db_table_desc_p curr, prev;
324*7c478bd9Sstevel@tonic-gate 	register char *target_name;
325*7c478bd9Sstevel@tonic-gate 	unsigned long target_hval;
326*7c478bd9Sstevel@tonic-gate 	target_name = td->table_name;
327*7c478bd9Sstevel@tonic-gate 	target_hval = td->hashval;
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	/* Search for it in the bucket */
330*7c478bd9Sstevel@tonic-gate 	for (prev = curr = bucket; curr != NULL; curr = curr->next) {
331*7c478bd9Sstevel@tonic-gate 		if (curr->hashval == target_hval &&
332*7c478bd9Sstevel@tonic-gate 		    strcmp(curr->table_name, target_name) == 0) {
333*7c478bd9Sstevel@tonic-gate 			break;
334*7c478bd9Sstevel@tonic-gate 		} else {
335*7c478bd9Sstevel@tonic-gate 			prev = curr;
336*7c478bd9Sstevel@tonic-gate 		}
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	if (curr != NULL)
340*7c478bd9Sstevel@tonic-gate 		return (FALSE);  /* duplicates not allowed */
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	curr = *head;
343*7c478bd9Sstevel@tonic-gate 	*head = td;
344*7c478bd9Sstevel@tonic-gate 	td->next = curr;
345*7c478bd9Sstevel@tonic-gate 	return (TRUE);
346*7c478bd9Sstevel@tonic-gate }
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate /* Print bucket starting with this entry. */
350*7c478bd9Sstevel@tonic-gate static void
351*7c478bd9Sstevel@tonic-gate print_bucket(db_table_desc *head)
352*7c478bd9Sstevel@tonic-gate {
353*7c478bd9Sstevel@tonic-gate 	db_table_desc *np;
354*7c478bd9Sstevel@tonic-gate 	for (np = head; np != NULL; np = np->next) {
355*7c478bd9Sstevel@tonic-gate 		printf("%s: %d\n", np->table_name, np->hashval);
356*7c478bd9Sstevel@tonic-gate 	}
357*7c478bd9Sstevel@tonic-gate }
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate static db_status
360*7c478bd9Sstevel@tonic-gate print_table(db_table_desc *tbl)
361*7c478bd9Sstevel@tonic-gate {
362*7c478bd9Sstevel@tonic-gate 	if (tbl == NULL)
363*7c478bd9Sstevel@tonic-gate 		return (DB_BADTABLE);
364*7c478bd9Sstevel@tonic-gate 	printf("%s: %d\n", tbl->table_name, tbl->hashval);
365*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
366*7c478bd9Sstevel@tonic-gate }
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate static int hashsizes[] = {		/* hashtable sizes */
370*7c478bd9Sstevel@tonic-gate 	11,
371*7c478bd9Sstevel@tonic-gate 	53,
372*7c478bd9Sstevel@tonic-gate 	113,
373*7c478bd9Sstevel@tonic-gate 	337,
374*7c478bd9Sstevel@tonic-gate 	977,
375*7c478bd9Sstevel@tonic-gate 	2053,
376*7c478bd9Sstevel@tonic-gate 	4073,
377*7c478bd9Sstevel@tonic-gate 	8011,
378*7c478bd9Sstevel@tonic-gate 	16001,
379*7c478bd9Sstevel@tonic-gate 	0
380*7c478bd9Sstevel@tonic-gate };
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate // prevents wrap around numbers from being passed
383*7c478bd9Sstevel@tonic-gate #define	CALLOC_LIMIT 536870911
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate /* Returns the next size to use for the hash table */
386*7c478bd9Sstevel@tonic-gate static unsigned int
387*7c478bd9Sstevel@tonic-gate get_next_hashsize(long unsigned oldsize)
388*7c478bd9Sstevel@tonic-gate {
389*7c478bd9Sstevel@tonic-gate 	long unsigned newsize, n;
390*7c478bd9Sstevel@tonic-gate 	if (oldsize == 0)
391*7c478bd9Sstevel@tonic-gate 		newsize = hashsizes[0];
392*7c478bd9Sstevel@tonic-gate 	else {
393*7c478bd9Sstevel@tonic-gate 		for (n = 0; newsize = hashsizes[n++]; )
394*7c478bd9Sstevel@tonic-gate 			if (oldsize == newsize) {
395*7c478bd9Sstevel@tonic-gate 				newsize = hashsizes[n];	/* get next size */
396*7c478bd9Sstevel@tonic-gate 				break;
397*7c478bd9Sstevel@tonic-gate 			}
398*7c478bd9Sstevel@tonic-gate 		if (newsize == 0)
399*7c478bd9Sstevel@tonic-gate 			newsize = oldsize * 2 + 1;	/* just double */
400*7c478bd9Sstevel@tonic-gate 	}
401*7c478bd9Sstevel@tonic-gate 	return (newsize);
402*7c478bd9Sstevel@tonic-gate }
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate /*
405*7c478bd9Sstevel@tonic-gate  * Grow the current hashtable upto the next size.
406*7c478bd9Sstevel@tonic-gate  * The contents of the existing hashtable is copied to the new one and
407*7c478bd9Sstevel@tonic-gate  * relocated according to its hashvalue relative to the new size.
408*7c478bd9Sstevel@tonic-gate  * Old table is deleted after the relocation.
409*7c478bd9Sstevel@tonic-gate  */
410*7c478bd9Sstevel@tonic-gate static void
411*7c478bd9Sstevel@tonic-gate grow_dictionary(db_dict_desc_p dd)
412*7c478bd9Sstevel@tonic-gate {
413*7c478bd9Sstevel@tonic-gate 	unsigned int oldsize, i, new_size;
414*7c478bd9Sstevel@tonic-gate 	db_table_desc_p * oldtab, *newtab;
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	oldsize = dd->tables.tables_len;
417*7c478bd9Sstevel@tonic-gate 	oldtab = dd->tables.tables_val;
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	new_size = get_next_hashsize(oldsize);
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	if (new_size > CALLOC_LIMIT) {
422*7c478bd9Sstevel@tonic-gate 		FATAL("db_dictionary::grow: table size exceeds calloc limit",
423*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT);
424*7c478bd9Sstevel@tonic-gate 	}
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	if ((newtab = (db_table_desc_p*)
427*7c478bd9Sstevel@tonic-gate 		calloc((unsigned int) new_size,
428*7c478bd9Sstevel@tonic-gate 			sizeof (db_table_desc_p))) == NULL) {
429*7c478bd9Sstevel@tonic-gate 		FATAL("db_dictionary::grow: cannot allocate space",
430*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT);
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	if (oldtab != NULL) {		// must transfer contents of old to new
434*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < oldsize; i++) {
435*7c478bd9Sstevel@tonic-gate 			relocate_bucket(oldtab[i], newtab, new_size);
436*7c478bd9Sstevel@tonic-gate 		}
437*7c478bd9Sstevel@tonic-gate 		delete oldtab;		// delete old hashtable
438*7c478bd9Sstevel@tonic-gate 	}
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 	dd->tables.tables_val = newtab;
441*7c478bd9Sstevel@tonic-gate 	dd->tables.tables_len = new_size;
442*7c478bd9Sstevel@tonic-gate }
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate #define	HASHSHIFT	3
445*7c478bd9Sstevel@tonic-gate #define	HASHMASK	0x1f
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate static u_int
448*7c478bd9Sstevel@tonic-gate get_hashval(char *value)
449*7c478bd9Sstevel@tonic-gate {
450*7c478bd9Sstevel@tonic-gate 	int i, len;
451*7c478bd9Sstevel@tonic-gate 	u_int hval = 0;
452*7c478bd9Sstevel@tonic-gate 
453*7c478bd9Sstevel@tonic-gate 	len = strlen(value);
454*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
455*7c478bd9Sstevel@tonic-gate 		hval = ((hval<<HASHSHIFT)^hval);
456*7c478bd9Sstevel@tonic-gate 		hval += (value[i] & HASHMASK);
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	return (hval);
460*7c478bd9Sstevel@tonic-gate }
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate static db_status
463*7c478bd9Sstevel@tonic-gate enumerate_dictionary(db_dict_desc *dd, db_status (*func) (db_table_desc*))
464*7c478bd9Sstevel@tonic-gate {
465*7c478bd9Sstevel@tonic-gate 	int i;
466*7c478bd9Sstevel@tonic-gate 	db_table_desc *bucket;
467*7c478bd9Sstevel@tonic-gate 	db_status status;
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	if (dd == NULL)
470*7c478bd9Sstevel@tonic-gate 		return (DB_SUCCESS);
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < dd->tables.tables_len; i++) {
473*7c478bd9Sstevel@tonic-gate 		bucket = dd->tables.tables_val[i];
474*7c478bd9Sstevel@tonic-gate 		if (bucket) {
475*7c478bd9Sstevel@tonic-gate 			status = enumerate_bucket(bucket, func);
476*7c478bd9Sstevel@tonic-gate 			if (status != DB_SUCCESS)
477*7c478bd9Sstevel@tonic-gate 				return (status);
478*7c478bd9Sstevel@tonic-gate 		}
479*7c478bd9Sstevel@tonic-gate 	}
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
482*7c478bd9Sstevel@tonic-gate }
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate /*
486*7c478bd9Sstevel@tonic-gate  * Look up target table_name in hashtable and return its db_table_desc.
487*7c478bd9Sstevel@tonic-gate  * Return NULL if not found.
488*7c478bd9Sstevel@tonic-gate  */
489*7c478bd9Sstevel@tonic-gate static db_table_desc *
490*7c478bd9Sstevel@tonic-gate search_dictionary(db_dict_desc *dd, char *target)
491*7c478bd9Sstevel@tonic-gate {
492*7c478bd9Sstevel@tonic-gate 	register unsigned long hval;
493*7c478bd9Sstevel@tonic-gate 	unsigned long bucket;
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	if (target == NULL || dd == NULL || dd->tables.tables_len == 0)
496*7c478bd9Sstevel@tonic-gate 		return (NULL);
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	hval = get_hashval(target);
499*7c478bd9Sstevel@tonic-gate 	bucket = hval % dd->tables.tables_len;
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	db_table_desc_p fst = dd->tables.tables_val[bucket];
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	if (fst != NULL)
504*7c478bd9Sstevel@tonic-gate 		return (search_bucket(fst, hval, target));
505*7c478bd9Sstevel@tonic-gate 	else
506*7c478bd9Sstevel@tonic-gate 		return (NULL);
507*7c478bd9Sstevel@tonic-gate }
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate /*
510*7c478bd9Sstevel@tonic-gate  * Remove the entry with the target table_name from the dictionary.
511*7c478bd9Sstevel@tonic-gate  * If successful, return DB_SUCCESS; otherwise DB_NOTUNIQUE if target
512*7c478bd9Sstevel@tonic-gate  * is null; DB_NOTFOUND if entry is not found.
513*7c478bd9Sstevel@tonic-gate  * If successful, decrement count of number of entries in hash table.
514*7c478bd9Sstevel@tonic-gate  */
515*7c478bd9Sstevel@tonic-gate static db_status
516*7c478bd9Sstevel@tonic-gate remove_from_dictionary(db_dict_desc *dd, char *target, bool_t remove_storage)
517*7c478bd9Sstevel@tonic-gate {
518*7c478bd9Sstevel@tonic-gate 	register unsigned long hval;
519*7c478bd9Sstevel@tonic-gate 	unsigned long bucket;
520*7c478bd9Sstevel@tonic-gate 	register db_table_desc *fst;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	if (target == NULL)
523*7c478bd9Sstevel@tonic-gate 		return (DB_NOTUNIQUE);
524*7c478bd9Sstevel@tonic-gate 	if (dd == NULL || dd->tables.tables_len == 0)
525*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
526*7c478bd9Sstevel@tonic-gate 	hval = get_hashval(target);
527*7c478bd9Sstevel@tonic-gate 	bucket = hval % dd->tables.tables_len;
528*7c478bd9Sstevel@tonic-gate 	fst = dd->tables.tables_val[bucket];
529*7c478bd9Sstevel@tonic-gate 	if (fst == NULL)
530*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
531*7c478bd9Sstevel@tonic-gate 	if (remove_from_bucket(fst, &dd->tables.tables_val[bucket],
532*7c478bd9Sstevel@tonic-gate 			hval, target, remove_storage)) {
533*7c478bd9Sstevel@tonic-gate 		--(dd->count);
534*7c478bd9Sstevel@tonic-gate 		return (DB_SUCCESS);
535*7c478bd9Sstevel@tonic-gate 	} else
536*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
537*7c478bd9Sstevel@tonic-gate }
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate /*
540*7c478bd9Sstevel@tonic-gate  * Add a new db_table_desc to the dictionary.
541*7c478bd9Sstevel@tonic-gate  * Return DB_NOTUNIQUE, if entry with identical table_name
542*7c478bd9Sstevel@tonic-gate  * already exists.  If entry is added, return DB_SUCCESS.
543*7c478bd9Sstevel@tonic-gate  * Increment count of number of entries in index table and grow table
544*7c478bd9Sstevel@tonic-gate  * if number of entries equals size of table.
545*7c478bd9Sstevel@tonic-gate  *
546*7c478bd9Sstevel@tonic-gate  * Inputs: db_dict_desc_p dd	pointer to dictionary to add to.
547*7c478bd9Sstevel@tonic-gate  *	   db_table_desc *td	pointer to table entry to be added. The
548*7c478bd9Sstevel@tonic-gate  * 				db_table_desc.next field will be altered
549*7c478bd9Sstevel@tonic-gate  *				without regard to it's current setting.
550*7c478bd9Sstevel@tonic-gate  *				This means that if next points to a list of
551*7c478bd9Sstevel@tonic-gate  *				table entries, they may be either linked into
552*7c478bd9Sstevel@tonic-gate  *				the dictionary unexpectly or cut off (leaked).
553*7c478bd9Sstevel@tonic-gate  */
554*7c478bd9Sstevel@tonic-gate static db_status
555*7c478bd9Sstevel@tonic-gate add_to_dictionary(db_dict_desc_p dd, db_table_desc *td)
556*7c478bd9Sstevel@tonic-gate {
557*7c478bd9Sstevel@tonic-gate 	register unsigned long hval;
558*7c478bd9Sstevel@tonic-gate 	char *target;
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	if (dd == NULL)
561*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
562*7c478bd9Sstevel@tonic-gate 
563*7c478bd9Sstevel@tonic-gate 	if (td == NULL)
564*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
565*7c478bd9Sstevel@tonic-gate 	target = td->table_name;
566*7c478bd9Sstevel@tonic-gate 	if (target == NULL)
567*7c478bd9Sstevel@tonic-gate 		return (DB_NOTUNIQUE);
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	hval = get_hashval(target);
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	if (dd->tables.tables_val == NULL)
572*7c478bd9Sstevel@tonic-gate 		grow_dictionary(dd);
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate 	db_table_desc_p fst;
575*7c478bd9Sstevel@tonic-gate 	unsigned long bucket;
576*7c478bd9Sstevel@tonic-gate 	bucket = hval % dd->tables.tables_len;
577*7c478bd9Sstevel@tonic-gate 	fst = dd->tables.tables_val[bucket];
578*7c478bd9Sstevel@tonic-gate 	td->hashval = hval;
579*7c478bd9Sstevel@tonic-gate 	if (fst == NULL)  { /* Empty bucket */
580*7c478bd9Sstevel@tonic-gate 		dd->tables.tables_val[bucket] = td;
581*7c478bd9Sstevel@tonic-gate 	} else if (!add_to_bucket(fst, &dd->tables.tables_val[bucket], td)) {
582*7c478bd9Sstevel@tonic-gate 			return (DB_NOTUNIQUE);
583*7c478bd9Sstevel@tonic-gate 		}
584*7c478bd9Sstevel@tonic-gate 
585*7c478bd9Sstevel@tonic-gate 	/* increase hash table size if number of entries equals table size */
586*7c478bd9Sstevel@tonic-gate 	if (++(dd->count) > dd->tables.tables_len)
587*7c478bd9Sstevel@tonic-gate 		grow_dictionary(dd);
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
590*7c478bd9Sstevel@tonic-gate }
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate /* ******************* pickling routines for dictionary ******************* */
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate /* Does the actual writing to/from file specific for db_dict_desc structure. */
596*7c478bd9Sstevel@tonic-gate static bool_t
597*7c478bd9Sstevel@tonic-gate transfer_aux(XDR* x, pptr tbl)
598*7c478bd9Sstevel@tonic-gate {
599*7c478bd9Sstevel@tonic-gate 	return (xdr_db_dict_desc_p(x, (db_dict_desc_p *) tbl));
600*7c478bd9Sstevel@tonic-gate }
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate class pickle_dict_desc: public pickle_file {
603*7c478bd9Sstevel@tonic-gate     public:
604*7c478bd9Sstevel@tonic-gate 	pickle_dict_desc(char *f, pickle_mode m) : pickle_file(f, m) {}
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate 	/* Transfers db_dict_desc structure pointed to by dp to/from file. */
607*7c478bd9Sstevel@tonic-gate 	int transfer(db_dict_desc_p * dp)
608*7c478bd9Sstevel@tonic-gate 		{ return (pickle_file::transfer((pptr) dp, &transfer_aux)); }
609*7c478bd9Sstevel@tonic-gate };
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate /* ************************ dictionary methods *************************** */
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate db_dictionary::db_dictionary()
614*7c478bd9Sstevel@tonic-gate {
615*7c478bd9Sstevel@tonic-gate 	dictionary = NULL;
616*7c478bd9Sstevel@tonic-gate 	initialized = FALSE;
617*7c478bd9Sstevel@tonic-gate 	filename = NULL;
618*7c478bd9Sstevel@tonic-gate 	tmpfilename = NULL;
619*7c478bd9Sstevel@tonic-gate 	logfilename = NULL;
620*7c478bd9Sstevel@tonic-gate 	logfile = NULL;
621*7c478bd9Sstevel@tonic-gate 	logfile_opened = FALSE;
622*7c478bd9Sstevel@tonic-gate 	changed = FALSE;
623*7c478bd9Sstevel@tonic-gate 	INITRW(dict);
624*7c478bd9Sstevel@tonic-gate 	READLOCKOK(dict);
625*7c478bd9Sstevel@tonic-gate }
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate /*
628*7c478bd9Sstevel@tonic-gate  * This routine clones an entire hash bucket chain. If you clone a
629*7c478bd9Sstevel@tonic-gate  * data dictionary entry with the ->next pointer set, you will get a
630*7c478bd9Sstevel@tonic-gate  * clone of that entry, as well as the entire linked list. This can cause
631*7c478bd9Sstevel@tonic-gate  * pain if you then pass the cloned bucket to routines such as
632*7c478bd9Sstevel@tonic-gate  * add_to_dictionary(), which do not expect nor handle dictionary hash
633*7c478bd9Sstevel@tonic-gate  * entries with the ->next pointer set. You might either get duplicate
634*7c478bd9Sstevel@tonic-gate  * entires or lose entries. If you wish to clone the entire bucket chain
635*7c478bd9Sstevel@tonic-gate  * and add it to a new dictionary, loop through the db_table_desc->next list
636*7c478bd9Sstevel@tonic-gate  * and call add_to_dictionary() for each item.
637*7c478bd9Sstevel@tonic-gate  */
638*7c478bd9Sstevel@tonic-gate int
639*7c478bd9Sstevel@tonic-gate db_dictionary::db_clone_bucket(db_table_desc *bucket, db_table_desc **clone)
640*7c478bd9Sstevel@tonic-gate {
641*7c478bd9Sstevel@tonic-gate 	u_long		size;
642*7c478bd9Sstevel@tonic-gate 	XDR		xdrs;
643*7c478bd9Sstevel@tonic-gate 	char		*bufin = NULL;
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 	READLOCK(this, DB_LOCK_ERROR, "r db_dictionary::db_clone_bucket");
646*7c478bd9Sstevel@tonic-gate 	db_func use_this = xdr_db_table_desc;
647*7c478bd9Sstevel@tonic-gate 	size = xdr_sizeof((xdrproc_t) use_this, (void *) bucket);
648*7c478bd9Sstevel@tonic-gate 	bufin = (char *) calloc(1, (size_t) size * sizeof (char));
649*7c478bd9Sstevel@tonic-gate 	if (!bufin) {
650*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, DB_MEMORY_LIMIT,
651*7c478bd9Sstevel@tonic-gate 			"db_dictionary::insert_modified_table: out of memory");
652*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::insert_modified_table: out of memory",
653*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, 0);
654*7c478bd9Sstevel@tonic-gate 	}
655*7c478bd9Sstevel@tonic-gate 	xdrmem_create(&xdrs, bufin, (size_t) size, XDR_ENCODE);
656*7c478bd9Sstevel@tonic-gate 	if (!xdr_db_table_desc(&xdrs, bucket)) {
657*7c478bd9Sstevel@tonic-gate 		free(bufin);
658*7c478bd9Sstevel@tonic-gate 		xdr_destroy(&xdrs);
659*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, DB_MEMORY_LIMIT,
660*7c478bd9Sstevel@tonic-gate 		"db_dictionary::insert_modified_table: xdr encode failed");
661*7c478bd9Sstevel@tonic-gate 		FATAL3(
662*7c478bd9Sstevel@tonic-gate 		"db_dictionary::insert_modified_table: xdr encode failed.",
663*7c478bd9Sstevel@tonic-gate 		DB_MEMORY_LIMIT, 0);
664*7c478bd9Sstevel@tonic-gate 	}
665*7c478bd9Sstevel@tonic-gate 	*clone = (db_table_desc *) calloc(1, (size_t) size * sizeof (char));
666*7c478bd9Sstevel@tonic-gate 	if (!*clone) {
667*7c478bd9Sstevel@tonic-gate 		xdr_destroy(&xdrs);
668*7c478bd9Sstevel@tonic-gate 		free(bufin);
669*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, DB_MEMORY_LIMIT,
670*7c478bd9Sstevel@tonic-gate 			"db_dictionary::insert_modified_table: out of memory");
671*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::insert_modified_table: out of memory",
672*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, 0);
673*7c478bd9Sstevel@tonic-gate 	}
674*7c478bd9Sstevel@tonic-gate 
675*7c478bd9Sstevel@tonic-gate 	xdrmem_create(&xdrs, bufin, (size_t) size, XDR_DECODE);
676*7c478bd9Sstevel@tonic-gate 	if (!xdr_db_table_desc(&xdrs, *clone)) {
677*7c478bd9Sstevel@tonic-gate 		free(bufin);
678*7c478bd9Sstevel@tonic-gate 		free(*clone);
679*7c478bd9Sstevel@tonic-gate 		xdr_destroy(&xdrs);
680*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, DB_MEMORY_LIMIT,
681*7c478bd9Sstevel@tonic-gate 		"db_dictionary::insert_modified_table: xdr encode failed");
682*7c478bd9Sstevel@tonic-gate 		FATAL3(
683*7c478bd9Sstevel@tonic-gate 		"db_dictionary::insert_modified_table: xdr encode failed.",
684*7c478bd9Sstevel@tonic-gate 		DB_MEMORY_LIMIT, 0);
685*7c478bd9Sstevel@tonic-gate 	}
686*7c478bd9Sstevel@tonic-gate 	free(bufin);
687*7c478bd9Sstevel@tonic-gate 	xdr_destroy(&xdrs);
688*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, DB_LOCK_ERROR, "ru db_dictionary::db_clone_bucket");
689*7c478bd9Sstevel@tonic-gate 	return (1);
690*7c478bd9Sstevel@tonic-gate }
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate int
694*7c478bd9Sstevel@tonic-gate db_dictionary::change_table_name(db_table_desc *clone, char *tok, char *repl)
695*7c478bd9Sstevel@tonic-gate {
696*7c478bd9Sstevel@tonic-gate 	char 	*newname;
697*7c478bd9Sstevel@tonic-gate 	char	*loc_end, *loc_beg;
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::change_table_name");
700*7c478bd9Sstevel@tonic-gate 	while (clone) {
701*7c478bd9Sstevel@tonic-gate 		/*
702*7c478bd9Sstevel@tonic-gate 		 * Special case for a tok="". This is used for the
703*7c478bd9Sstevel@tonic-gate 		 * nisrestore(1M), when restoring a replica in another
704*7c478bd9Sstevel@tonic-gate 		 * domain. This routine is used to change the datafile
705*7c478bd9Sstevel@tonic-gate 		 * names in the data.dict (see bugid #4031273). This will not
706*7c478bd9Sstevel@tonic-gate 		 * effect massage_dict(), since it never generates an empty
707*7c478bd9Sstevel@tonic-gate 		 * string for tok.
708*7c478bd9Sstevel@tonic-gate 		 */
709*7c478bd9Sstevel@tonic-gate 		if (strlen(tok) == 0) {
710*7c478bd9Sstevel@tonic-gate 			strcat(clone->table_name, repl);
711*7c478bd9Sstevel@tonic-gate 			clone = clone->next;
712*7c478bd9Sstevel@tonic-gate 			continue;
713*7c478bd9Sstevel@tonic-gate 		}
714*7c478bd9Sstevel@tonic-gate 		newname = (char *) calloc(1, sizeof (char) *
715*7c478bd9Sstevel@tonic-gate 				strlen(clone->table_name) +
716*7c478bd9Sstevel@tonic-gate 				strlen(repl) - strlen(tok) + 1);
717*7c478bd9Sstevel@tonic-gate 		if (!newname) {
718*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, DB_MEMORY_LIMIT,
719*7c478bd9Sstevel@tonic-gate 			"db_dictionary::change_table_name: out of memory");
720*7c478bd9Sstevel@tonic-gate 		    FATAL3("db_dictionary::change_table_name: out of memory.",
721*7c478bd9Sstevel@tonic-gate 				DB_MEMORY_LIMIT, 0);
722*7c478bd9Sstevel@tonic-gate 		}
723*7c478bd9Sstevel@tonic-gate 		if (loc_beg = strstr(clone->table_name, tok)) {
724*7c478bd9Sstevel@tonic-gate 			loc_end = loc_beg + strlen(tok);
725*7c478bd9Sstevel@tonic-gate 			int s = loc_beg - clone->table_name;
726*7c478bd9Sstevel@tonic-gate 			memcpy(newname, clone->table_name, s);
727*7c478bd9Sstevel@tonic-gate 			strcat(newname + s, repl);
728*7c478bd9Sstevel@tonic-gate 			strcat(newname, loc_end);
729*7c478bd9Sstevel@tonic-gate 			free(clone->table_name);
730*7c478bd9Sstevel@tonic-gate 			clone->table_name = newname;
731*7c478bd9Sstevel@tonic-gate 		} else {
732*7c478bd9Sstevel@tonic-gate 			free(newname);
733*7c478bd9Sstevel@tonic-gate 		}
734*7c478bd9Sstevel@tonic-gate 		clone = clone->next;
735*7c478bd9Sstevel@tonic-gate 	}
736*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, DB_LOCK_ERROR,
737*7c478bd9Sstevel@tonic-gate 			"wu db_dictionary::change_table_name");
738*7c478bd9Sstevel@tonic-gate 	return (1);
739*7c478bd9Sstevel@tonic-gate }
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate #ifdef	curdict
743*7c478bd9Sstevel@tonic-gate #undef	curdict
744*7c478bd9Sstevel@tonic-gate #endif
745*7c478bd9Sstevel@tonic-gate /*
746*7c478bd9Sstevel@tonic-gate  * A function to initialize the temporary dictionary from the real
747*7c478bd9Sstevel@tonic-gate  * dictionary.
748*7c478bd9Sstevel@tonic-gate  */
749*7c478bd9Sstevel@tonic-gate bool_t
750*7c478bd9Sstevel@tonic-gate db_dictionary::inittemp(char *dictname, db_dictionary& curdict)
751*7c478bd9Sstevel@tonic-gate {
752*7c478bd9Sstevel@tonic-gate 	int status;
753*7c478bd9Sstevel@tonic-gate 	db_table_desc_p	*newtab;
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate 	db_shutdown();
756*7c478bd9Sstevel@tonic-gate 
757*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db_dictionary::inittemp");
758*7c478bd9Sstevel@tonic-gate 	if (initialized) {
759*7c478bd9Sstevel@tonic-gate 		/* Someone else got in between db_shutdown() and lock() */
760*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE, "wu db_dictionary::inittemp");
761*7c478bd9Sstevel@tonic-gate 		return (TRUE);
762*7c478bd9Sstevel@tonic-gate 	}
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 	pickle_dict_desc f(dictname, PICKLE_READ);
765*7c478bd9Sstevel@tonic-gate 	filename = strdup(dictname);
766*7c478bd9Sstevel@tonic-gate 	if (filename == NULL) {
767*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE,
768*7c478bd9Sstevel@tonic-gate 			"db_dictionary::inittemp: could not allocate space");
769*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::inittemp: could not allocate space",
770*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, FALSE);
771*7c478bd9Sstevel@tonic-gate 	}
772*7c478bd9Sstevel@tonic-gate 	int len = strlen(filename);
773*7c478bd9Sstevel@tonic-gate 	tmpfilename = new char[len+5];
774*7c478bd9Sstevel@tonic-gate 	if (tmpfilename == NULL) {
775*7c478bd9Sstevel@tonic-gate 		delete filename;
776*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE,
777*7c478bd9Sstevel@tonic-gate 			"db_dictionary::inittemp: could not allocate space");
778*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::inittemp: could not allocate space",
779*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, FALSE);
780*7c478bd9Sstevel@tonic-gate 	}
781*7c478bd9Sstevel@tonic-gate 	logfilename = new char[len+5];
782*7c478bd9Sstevel@tonic-gate 	if (logfilename == NULL) {
783*7c478bd9Sstevel@tonic-gate 		delete filename;
784*7c478bd9Sstevel@tonic-gate 		delete tmpfilename;
785*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE,
786*7c478bd9Sstevel@tonic-gate 			"db_dictionary::inittemp: cannot allocate space");
787*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::inittemp: cannot allocate space",
788*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, FALSE);
789*7c478bd9Sstevel@tonic-gate 	}
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate 	sprintf(tmpfilename, "%s.tmp", filename);
792*7c478bd9Sstevel@tonic-gate 	sprintf(logfilename, "%s.log", filename);
793*7c478bd9Sstevel@tonic-gate 	unlink(tmpfilename);  /* get rid of partial checkpoints */
794*7c478bd9Sstevel@tonic-gate 	dictionary = NULL;
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 	if ((status = f.transfer(&dictionary)) < 0) {
797*7c478bd9Sstevel@tonic-gate 		initialized = FALSE;
798*7c478bd9Sstevel@tonic-gate 	} else if (status == 1) { /* no dictionary exists, create one */
799*7c478bd9Sstevel@tonic-gate 		dictionary = new db_dict_desc;
800*7c478bd9Sstevel@tonic-gate 		if (dictionary == NULL) {
801*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, FALSE,
802*7c478bd9Sstevel@tonic-gate 			"db_dictionary::inittemp: could not allocate space");
803*7c478bd9Sstevel@tonic-gate 			FATAL3(
804*7c478bd9Sstevel@tonic-gate 			"db_dictionary::inittemp: could not allocate space",
805*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, FALSE);
806*7c478bd9Sstevel@tonic-gate 		}
807*7c478bd9Sstevel@tonic-gate 		dictionary->tables.tables_len =
808*7c478bd9Sstevel@tonic-gate 				curdict.dictionary->tables.tables_len;
809*7c478bd9Sstevel@tonic-gate 		if ((newtab = (db_table_desc_p *) calloc(
810*7c478bd9Sstevel@tonic-gate 			(unsigned int) dictionary->tables.tables_len,
811*7c478bd9Sstevel@tonic-gate 			sizeof (db_table_desc_p))) == NULL) {
812*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, FALSE,
813*7c478bd9Sstevel@tonic-gate 			"db_dictionary::inittemp: cannot allocate space");
814*7c478bd9Sstevel@tonic-gate 			FATAL3(
815*7c478bd9Sstevel@tonic-gate 			"db_dictionary::inittemp: cannot allocate space",
816*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, 0);
817*7c478bd9Sstevel@tonic-gate 		}
818*7c478bd9Sstevel@tonic-gate 		dictionary->tables.tables_val = newtab;
819*7c478bd9Sstevel@tonic-gate 		dictionary->count = 0;
820*7c478bd9Sstevel@tonic-gate 		dictionary->impl_vers = curdict.dictionary->impl_vers;
821*7c478bd9Sstevel@tonic-gate 		initialized = TRUE;
822*7c478bd9Sstevel@tonic-gate 	} else	/* dictionary loaded successfully */
823*7c478bd9Sstevel@tonic-gate 		initialized = TRUE;
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 	if (initialized == TRUE) {
826*7c478bd9Sstevel@tonic-gate 		changed = FALSE;
827*7c478bd9Sstevel@tonic-gate 		reset_log();
828*7c478bd9Sstevel@tonic-gate 	}
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, FALSE, "wu db_dictionary::inittemp");
831*7c478bd9Sstevel@tonic-gate 	return (initialized);
832*7c478bd9Sstevel@tonic-gate }
833*7c478bd9Sstevel@tonic-gate 
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate /*
836*7c478bd9Sstevel@tonic-gate  * This method replaces the token string specified with the replacment
837*7c478bd9Sstevel@tonic-gate  * string specified. It assumes that at least one and only one instance of
838*7c478bd9Sstevel@tonic-gate  * the token exists. It is the responsibility of the caller to ensure that
839*7c478bd9Sstevel@tonic-gate  * the above assumption stays valid.
840*7c478bd9Sstevel@tonic-gate  */
841*7c478bd9Sstevel@tonic-gate db_status
842*7c478bd9Sstevel@tonic-gate db_dictionary::massage_dict(char *newdictname, char *tok, char *repl)
843*7c478bd9Sstevel@tonic-gate {
844*7c478bd9Sstevel@tonic-gate 	int		retval;
845*7c478bd9Sstevel@tonic-gate 	u_int		i, tbl_count;
846*7c478bd9Sstevel@tonic-gate 	db_status	status;
847*7c478bd9Sstevel@tonic-gate 	db_table_desc 	*bucket, *np, *clone, *next_np;
848*7c478bd9Sstevel@tonic-gate 	char		tail[NIS_MAXNAMELEN];
849*7c478bd9Sstevel@tonic-gate 	db_dictionary	*tmpptr;
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::massage_dict");
852*7c478bd9Sstevel@tonic-gate 	if (dictionary == NULL) {
853*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_INTERNAL_ERROR,
854*7c478bd9Sstevel@tonic-gate 		"db_dictionary::massage_dict: uninitialized dictionary file");
855*7c478bd9Sstevel@tonic-gate 		FATAL3(
856*7c478bd9Sstevel@tonic-gate 		"db_dictionary::massage_dict: uninitialized dictionary file.",
857*7c478bd9Sstevel@tonic-gate 		DB_INTERNAL_ERROR, DB_INTERNAL_ERROR);
858*7c478bd9Sstevel@tonic-gate 	}
859*7c478bd9Sstevel@tonic-gate 
860*7c478bd9Sstevel@tonic-gate 	if ((tbl_count = dictionary->count) == 0) {
861*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_SUCCESS,
862*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::massage_dict");
863*7c478bd9Sstevel@tonic-gate 		return (DB_SUCCESS);
864*7c478bd9Sstevel@tonic-gate 	}
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	/* First checkpoint */
867*7c478bd9Sstevel@tonic-gate 	if ((status = checkpoint()) != DB_SUCCESS) {
868*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, status, "wu db_dictionary::massage_dict");
869*7c478bd9Sstevel@tonic-gate 		return (status);
870*7c478bd9Sstevel@tonic-gate 	}
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
873*7c478bd9Sstevel@tonic-gate 	enumerate_dictionary(dictionary, &print_table);
874*7c478bd9Sstevel@tonic-gate #endif
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 	/* Initialize the free dictionary so that we can start populating it */
877*7c478bd9Sstevel@tonic-gate 	FreeDictionary->inittemp(newdictname, *this);
878*7c478bd9Sstevel@tonic-gate 
879*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < dictionary->tables.tables_len; i++) {
880*7c478bd9Sstevel@tonic-gate 		bucket = dictionary->tables.tables_val[i];
881*7c478bd9Sstevel@tonic-gate 		if (bucket) {
882*7c478bd9Sstevel@tonic-gate 			np = bucket;
883*7c478bd9Sstevel@tonic-gate 			while (np != NULL) {
884*7c478bd9Sstevel@tonic-gate 				next_np = np->next;
885*7c478bd9Sstevel@tonic-gate 				retval = db_clone_bucket(np, &clone);
886*7c478bd9Sstevel@tonic-gate 				if (retval != 1) {
887*7c478bd9Sstevel@tonic-gate 					WRITEUNLOCK(this, DB_INTERNAL_ERROR,
888*7c478bd9Sstevel@tonic-gate 					"wu db_dictionary::massage_dict");
889*7c478bd9Sstevel@tonic-gate 					return (DB_INTERNAL_ERROR);
890*7c478bd9Sstevel@tonic-gate 				}
891*7c478bd9Sstevel@tonic-gate 				if (change_table_name(clone, tok, repl) == -1) {
892*7c478bd9Sstevel@tonic-gate 					delete_table_desc(clone);
893*7c478bd9Sstevel@tonic-gate 					WRITEUNLOCK(this, DB_INTERNAL_ERROR,
894*7c478bd9Sstevel@tonic-gate 					"wu db_dictionary::massage_dict");
895*7c478bd9Sstevel@tonic-gate 					return (DB_INTERNAL_ERROR);
896*7c478bd9Sstevel@tonic-gate 				}
897*7c478bd9Sstevel@tonic-gate 				/*
898*7c478bd9Sstevel@tonic-gate 				 * We know we don't have a log file, so we will
899*7c478bd9Sstevel@tonic-gate 				 * just add to the in-memory database and dump
900*7c478bd9Sstevel@tonic-gate 				 * all of it once we are done.
901*7c478bd9Sstevel@tonic-gate 				 */
902*7c478bd9Sstevel@tonic-gate 				status = add_to_dictionary
903*7c478bd9Sstevel@tonic-gate 						(FreeDictionary->dictionary,
904*7c478bd9Sstevel@tonic-gate 						clone);
905*7c478bd9Sstevel@tonic-gate 				if (status != DB_SUCCESS) {
906*7c478bd9Sstevel@tonic-gate 					delete_table_desc(clone);
907*7c478bd9Sstevel@tonic-gate 					WRITEUNLOCK(this, DB_INTERNAL_ERROR,
908*7c478bd9Sstevel@tonic-gate 					"wu db_dictionary::massage_dict");
909*7c478bd9Sstevel@tonic-gate 					return (DB_INTERNAL_ERROR);
910*7c478bd9Sstevel@tonic-gate 				}
911*7c478bd9Sstevel@tonic-gate 				status = remove_from_dictionary(dictionary,
912*7c478bd9Sstevel@tonic-gate 							np->table_name, TRUE);
913*7c478bd9Sstevel@tonic-gate 				if (status != DB_SUCCESS) {
914*7c478bd9Sstevel@tonic-gate 					delete_table_desc(clone);
915*7c478bd9Sstevel@tonic-gate 					WRITEUNLOCK(this, DB_INTERNAL_ERROR,
916*7c478bd9Sstevel@tonic-gate 					"wu db_dictionary::massage_dict");
917*7c478bd9Sstevel@tonic-gate 					return (DB_INTERNAL_ERROR);
918*7c478bd9Sstevel@tonic-gate 				}
919*7c478bd9Sstevel@tonic-gate 				np = next_np;
920*7c478bd9Sstevel@tonic-gate 			}
921*7c478bd9Sstevel@tonic-gate 		}
922*7c478bd9Sstevel@tonic-gate 	}
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 	if (FreeDictionary->dump() != DB_SUCCESS) {
925*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_INTERNAL_ERROR,
926*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::massage_dict");
927*7c478bd9Sstevel@tonic-gate 		FATAL3(
928*7c478bd9Sstevel@tonic-gate 		"db_dictionary::massage_dict: Unable to dump new dictionary.",
929*7c478bd9Sstevel@tonic-gate 		DB_INTERNAL_ERROR, DB_INTERNAL_ERROR);
930*7c478bd9Sstevel@tonic-gate 	}
931*7c478bd9Sstevel@tonic-gate 
932*7c478bd9Sstevel@tonic-gate 	/*
933*7c478bd9Sstevel@tonic-gate 	 * Now, shutdown the inuse dictionary and update the FreeDictionary
934*7c478bd9Sstevel@tonic-gate 	 * and InUseDictionary pointers as well. Also, delete the old dictionary
935*7c478bd9Sstevel@tonic-gate 	 * file.
936*7c478bd9Sstevel@tonic-gate 	 */
937*7c478bd9Sstevel@tonic-gate 	unlink(filename); /* There shouldn't be a tmpfile or logfile */
938*7c478bd9Sstevel@tonic-gate 	db_shutdown();
939*7c478bd9Sstevel@tonic-gate 	tmpptr = InUseDictionary;
940*7c478bd9Sstevel@tonic-gate 	InUseDictionary = FreeDictionary;
941*7c478bd9Sstevel@tonic-gate 	FreeDictionary = tmpptr;
942*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, DB_LOCK_ERROR, "wu db_dictionary::massage_dict");
943*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
944*7c478bd9Sstevel@tonic-gate }
945*7c478bd9Sstevel@tonic-gate 
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate db_status
948*7c478bd9Sstevel@tonic-gate db_dictionary::merge_dict(db_dictionary& tempdict, char *tok, char *repl)
949*7c478bd9Sstevel@tonic-gate {
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 	db_status	dbstat = DB_SUCCESS;
952*7c478bd9Sstevel@tonic-gate 
953*7c478bd9Sstevel@tonic-gate 	db_table_desc	*tbl = NULL, *clone = NULL, *next_td = NULL;
954*7c478bd9Sstevel@tonic-gate 	int		retval, i;
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::merge_dict");
957*7c478bd9Sstevel@tonic-gate 
958*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < tempdict.dictionary->tables.tables_len; ++i) {
959*7c478bd9Sstevel@tonic-gate 		tbl = tempdict.dictionary->tables.tables_val[i];
960*7c478bd9Sstevel@tonic-gate 		if (!tbl)
961*7c478bd9Sstevel@tonic-gate 			continue;
962*7c478bd9Sstevel@tonic-gate 		retval = db_clone_bucket(tbl, &clone);
963*7c478bd9Sstevel@tonic-gate 		if (retval != 1) {
964*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, DB_INTERNAL_ERROR,
965*7c478bd9Sstevel@tonic-gate 					"wu db_dictionary::merge_dict");
966*7c478bd9Sstevel@tonic-gate 			return (DB_INTERNAL_ERROR);
967*7c478bd9Sstevel@tonic-gate 		}
968*7c478bd9Sstevel@tonic-gate 		while (clone) {
969*7c478bd9Sstevel@tonic-gate 			next_td = clone->next;
970*7c478bd9Sstevel@tonic-gate 			clone->next = NULL;
971*7c478bd9Sstevel@tonic-gate 			if ((tok) &&
972*7c478bd9Sstevel@tonic-gate 				(change_table_name(clone, tok, repl) == -1)) {
973*7c478bd9Sstevel@tonic-gate 				delete_table_desc(clone);
974*7c478bd9Sstevel@tonic-gate 				if (next_td)
975*7c478bd9Sstevel@tonic-gate 					delete_table_desc(next_td);
976*7c478bd9Sstevel@tonic-gate 				WRITEUNLOCK(this, DB_INTERNAL_ERROR,
977*7c478bd9Sstevel@tonic-gate 					"wu db_dictionary::merge_dict");
978*7c478bd9Sstevel@tonic-gate 				return (DB_INTERNAL_ERROR);
979*7c478bd9Sstevel@tonic-gate 			}
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 			dbstat = add_to_dictionary(dictionary, clone);
982*7c478bd9Sstevel@tonic-gate 			if (dbstat == DB_NOTUNIQUE) {
983*7c478bd9Sstevel@tonic-gate 				/* Overide */
984*7c478bd9Sstevel@tonic-gate 				dbstat = remove_from_dictionary(dictionary,
985*7c478bd9Sstevel@tonic-gate 						clone->table_name, TRUE);
986*7c478bd9Sstevel@tonic-gate 				if (dbstat != DB_SUCCESS) {
987*7c478bd9Sstevel@tonic-gate 					WRITEUNLOCK(this, dbstat,
988*7c478bd9Sstevel@tonic-gate 					"wu db_dictionary::merge_dict");
989*7c478bd9Sstevel@tonic-gate 					return (dbstat);
990*7c478bd9Sstevel@tonic-gate 				}
991*7c478bd9Sstevel@tonic-gate 				dbstat = add_to_dictionary(dictionary,
992*7c478bd9Sstevel@tonic-gate 								clone);
993*7c478bd9Sstevel@tonic-gate 			} else {
994*7c478bd9Sstevel@tonic-gate 				if (dbstat != DB_SUCCESS) {
995*7c478bd9Sstevel@tonic-gate 					WRITEUNLOCK(this, dbstat,
996*7c478bd9Sstevel@tonic-gate 					"wu db_dictionary::merge_dict");
997*7c478bd9Sstevel@tonic-gate 					return (dbstat);
998*7c478bd9Sstevel@tonic-gate 				}
999*7c478bd9Sstevel@tonic-gate 			}
1000*7c478bd9Sstevel@tonic-gate 			clone = next_td;
1001*7c478bd9Sstevel@tonic-gate 		}
1002*7c478bd9Sstevel@tonic-gate 	}
1003*7c478bd9Sstevel@tonic-gate /*
1004*7c478bd9Sstevel@tonic-gate  * If we were successful in merging the dictionaries, then mark the
1005*7c478bd9Sstevel@tonic-gate  * dictionary changed, so that it will be properly checkpointed and
1006*7c478bd9Sstevel@tonic-gate  * dumped to disk.
1007*7c478bd9Sstevel@tonic-gate  */
1008*7c478bd9Sstevel@tonic-gate 	if (dbstat == DB_SUCCESS)
1009*7c478bd9Sstevel@tonic-gate 		changed = TRUE;
1010*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, DB_LOCK_ERROR, "wu db_dictionary::merge_dict");
1011*7c478bd9Sstevel@tonic-gate 	return (dbstat);
1012*7c478bd9Sstevel@tonic-gate }
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate int
1015*7c478bd9Sstevel@tonic-gate db_dictionary::copyfile(char *infile, char *outfile)
1016*7c478bd9Sstevel@tonic-gate {
1017*7c478bd9Sstevel@tonic-gate 	db_table_desc	*tbl = NULL;
1018*7c478bd9Sstevel@tonic-gate 	db	*dbase;
1019*7c478bd9Sstevel@tonic-gate 	int	ret;
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 	READLOCK(this, DB_LOCK_ERROR, "r db_dictionary::copyfile");
1022*7c478bd9Sstevel@tonic-gate 	/*
1023*7c478bd9Sstevel@tonic-gate 	 * We need to hold the read-lock until the dump() is done.
1024*7c478bd9Sstevel@tonic-gate 	 * However, we must avoid the lock migration (read -> write)
1025*7c478bd9Sstevel@tonic-gate 	 * that would happen in find_table() if the db must be loaded.
1026*7c478bd9Sstevel@tonic-gate 	 * Hence, look first look for an already loaded db.
1027*7c478bd9Sstevel@tonic-gate 	 */
1028*7c478bd9Sstevel@tonic-gate 	dbase  = find_table(infile, &tbl, TRUE, TRUE, FALSE);
1029*7c478bd9Sstevel@tonic-gate 	if (dbase == NULL) {
1030*7c478bd9Sstevel@tonic-gate 		/* Release the read-lock, and try again, allowing load */
1031*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, DB_LOCK_ERROR, "ru db_dictionary::copyfile");
1032*7c478bd9Sstevel@tonic-gate 		dbase  = find_table(infile, &tbl, TRUE, TRUE, TRUE);
1033*7c478bd9Sstevel@tonic-gate 		if (dbase == NULL)
1034*7c478bd9Sstevel@tonic-gate 			return (DB_NOTFOUND);
1035*7c478bd9Sstevel@tonic-gate 		/*
1036*7c478bd9Sstevel@tonic-gate 		 * Read-lock again, and get a 'tbl' we can use since we're
1037*7c478bd9Sstevel@tonic-gate 		 * still holding the lock.
1038*7c478bd9Sstevel@tonic-gate 		 */
1039*7c478bd9Sstevel@tonic-gate 		READLOCK(this, DB_LOCK_ERROR, "r db_dictionary::copyfile");
1040*7c478bd9Sstevel@tonic-gate 		dbase  = find_table(infile, &tbl, TRUE, TRUE, FALSE);
1041*7c478bd9Sstevel@tonic-gate 		if (dbase == NULL) {
1042*7c478bd9Sstevel@tonic-gate 			READUNLOCK(this, DB_NOTFOUND,
1043*7c478bd9Sstevel@tonic-gate 					"ru db_dictionary::copyfile");
1044*7c478bd9Sstevel@tonic-gate 			return (DB_NOTFOUND);
1045*7c478bd9Sstevel@tonic-gate 		}
1046*7c478bd9Sstevel@tonic-gate 	}
1047*7c478bd9Sstevel@tonic-gate 	ret = tbl->database->dump(outfile) ? DB_SUCCESS : DB_INTERNAL_ERROR;
1048*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, ret, "ru db_dictionary::copyfile");
1049*7c478bd9Sstevel@tonic-gate 	return (ret);
1050*7c478bd9Sstevel@tonic-gate }
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate bool_t
1054*7c478bd9Sstevel@tonic-gate db_dictionary::extract_entries(db_dictionary& tempdict, char **fs, int fscnt)
1055*7c478bd9Sstevel@tonic-gate {
1056*7c478bd9Sstevel@tonic-gate 	int		i, retval;
1057*7c478bd9Sstevel@tonic-gate 	db_table_desc	*tbl, *clone;
1058*7c478bd9Sstevel@tonic-gate 	db_table_desc	tbl_ent;
1059*7c478bd9Sstevel@tonic-gate 	db_status	dbstat;
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	READLOCK(this, FALSE, "r db_dictionary::extract_entries");
1062*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < fscnt; ++i) {
1063*7c478bd9Sstevel@tonic-gate 		tbl = find_table_desc(fs[i]);
1064*7c478bd9Sstevel@tonic-gate 		if (!tbl) {
1065*7c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
1066*7c478bd9Sstevel@tonic-gate 				"extract_entries: no dictionary entry for %s",
1067*7c478bd9Sstevel@tonic-gate 				fs[i]);
1068*7c478bd9Sstevel@tonic-gate 			READUNLOCK(this, FALSE,
1069*7c478bd9Sstevel@tonic-gate 					"ru db_dictionary::extract_entries");
1070*7c478bd9Sstevel@tonic-gate 			return (FALSE);
1071*7c478bd9Sstevel@tonic-gate 		} else {
1072*7c478bd9Sstevel@tonic-gate 			tbl_ent.table_name = tbl->table_name;
1073*7c478bd9Sstevel@tonic-gate 			tbl_ent.hashval = tbl->hashval;
1074*7c478bd9Sstevel@tonic-gate 			tbl_ent.scheme = tbl->scheme;
1075*7c478bd9Sstevel@tonic-gate 			tbl_ent.database = tbl->database;
1076*7c478bd9Sstevel@tonic-gate 			tbl_ent.next = NULL;
1077*7c478bd9Sstevel@tonic-gate 		}
1078*7c478bd9Sstevel@tonic-gate 		retval = db_clone_bucket(&tbl_ent, &clone);
1079*7c478bd9Sstevel@tonic-gate 		if (retval != 1) {
1080*7c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
1081*7c478bd9Sstevel@tonic-gate 			"extract_entries: unable to clone entry for %s",
1082*7c478bd9Sstevel@tonic-gate 			fs[i]);
1083*7c478bd9Sstevel@tonic-gate 			READUNLOCK(this, FALSE,
1084*7c478bd9Sstevel@tonic-gate 					"ru db_dictionary::extract_entries");
1085*7c478bd9Sstevel@tonic-gate 			return (FALSE);
1086*7c478bd9Sstevel@tonic-gate 		}
1087*7c478bd9Sstevel@tonic-gate 		dbstat = add_to_dictionary(tempdict.dictionary, clone);
1088*7c478bd9Sstevel@tonic-gate 		if (dbstat != DB_SUCCESS) {
1089*7c478bd9Sstevel@tonic-gate 			delete_table_desc(clone);
1090*7c478bd9Sstevel@tonic-gate 			READUNLOCK(this, FALSE,
1091*7c478bd9Sstevel@tonic-gate 					"ru db_dictionary::extract_entries");
1092*7c478bd9Sstevel@tonic-gate 			return (FALSE);
1093*7c478bd9Sstevel@tonic-gate 		}
1094*7c478bd9Sstevel@tonic-gate 	}
1095*7c478bd9Sstevel@tonic-gate 	if (tempdict.dump() != DB_SUCCESS) {
1096*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, FALSE,
1097*7c478bd9Sstevel@tonic-gate 				"ru db_dictionary::extract_entries");
1098*7c478bd9Sstevel@tonic-gate 		return (FALSE);
1099*7c478bd9Sstevel@tonic-gate 	}
1100*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, FALSE,
1101*7c478bd9Sstevel@tonic-gate 			"ru db_dictionary::extract_entries");
1102*7c478bd9Sstevel@tonic-gate 	return (TRUE);
1103*7c478bd9Sstevel@tonic-gate }
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 
1106*7c478bd9Sstevel@tonic-gate /*
1107*7c478bd9Sstevel@tonic-gate  * Initialize dictionary from contents in 'file'.
1108*7c478bd9Sstevel@tonic-gate  * If there is already information in this dictionary, it is removed.
1109*7c478bd9Sstevel@tonic-gate  * Therefore, regardless of whether the load from the file succeeds,
1110*7c478bd9Sstevel@tonic-gate  * the contents of this dictionary will be altered.  Returns
1111*7c478bd9Sstevel@tonic-gate  * whether table has been initialized successfully.
1112*7c478bd9Sstevel@tonic-gate  */
1113*7c478bd9Sstevel@tonic-gate bool_t
1114*7c478bd9Sstevel@tonic-gate db_dictionary::init(char *file)
1115*7c478bd9Sstevel@tonic-gate {
1116*7c478bd9Sstevel@tonic-gate 	int status;
1117*7c478bd9Sstevel@tonic-gate 
1118*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db_dictionary::init");
1119*7c478bd9Sstevel@tonic-gate 	db_shutdown();
1120*7c478bd9Sstevel@tonic-gate 
1121*7c478bd9Sstevel@tonic-gate 	pickle_dict_desc f(file, PICKLE_READ);
1122*7c478bd9Sstevel@tonic-gate 	filename = strdup(file);
1123*7c478bd9Sstevel@tonic-gate 	if (filename == NULL) {
1124*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE,
1125*7c478bd9Sstevel@tonic-gate 			"db_dictionary::init: could not allocate space");
1126*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::init: could not allocate space",
1127*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, FALSE);
1128*7c478bd9Sstevel@tonic-gate 	}
1129*7c478bd9Sstevel@tonic-gate 	int len = strlen(filename);
1130*7c478bd9Sstevel@tonic-gate 	tmpfilename = new char[len+5];
1131*7c478bd9Sstevel@tonic-gate 	if (tmpfilename == NULL) {
1132*7c478bd9Sstevel@tonic-gate 		delete filename;
1133*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE,
1134*7c478bd9Sstevel@tonic-gate 			"db_dictionary::init: could not allocate space");
1135*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::init: could not allocate space",
1136*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, FALSE);
1137*7c478bd9Sstevel@tonic-gate 	}
1138*7c478bd9Sstevel@tonic-gate 	logfilename = new char[len+5];
1139*7c478bd9Sstevel@tonic-gate 	if (logfilename == NULL) {
1140*7c478bd9Sstevel@tonic-gate 		delete filename;
1141*7c478bd9Sstevel@tonic-gate 		delete tmpfilename;
1142*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE,
1143*7c478bd9Sstevel@tonic-gate 				"db_dictionary::init: cannot allocate space");
1144*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::init: cannot allocate space",
1145*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, FALSE);
1146*7c478bd9Sstevel@tonic-gate 	}
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate 	sprintf(tmpfilename, "%s.tmp", filename);
1149*7c478bd9Sstevel@tonic-gate 	sprintf(logfilename, "%s.log", filename);
1150*7c478bd9Sstevel@tonic-gate 	unlink(tmpfilename);  /* get rid of partial checkpoints */
1151*7c478bd9Sstevel@tonic-gate 	dictionary = NULL;
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate 	/* load dictionary */
1154*7c478bd9Sstevel@tonic-gate 	if ((status = f.transfer(&dictionary)) < 0) {
1155*7c478bd9Sstevel@tonic-gate 	    initialized = FALSE;
1156*7c478bd9Sstevel@tonic-gate 	} else if (status == 1) {  /* no dictionary exists, create one */
1157*7c478bd9Sstevel@tonic-gate 	    dictionary = new db_dict_desc;
1158*7c478bd9Sstevel@tonic-gate 	    if (dictionary == NULL) {
1159*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE,
1160*7c478bd9Sstevel@tonic-gate 			"db_dictionary::init: could not allocate space");
1161*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::init: could not allocate space",
1162*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, FALSE);
1163*7c478bd9Sstevel@tonic-gate 	    }
1164*7c478bd9Sstevel@tonic-gate 	    dictionary->tables.tables_len = 0;
1165*7c478bd9Sstevel@tonic-gate 	    dictionary->tables.tables_val = NULL;
1166*7c478bd9Sstevel@tonic-gate 	    dictionary->count = 0;
1167*7c478bd9Sstevel@tonic-gate 	    dictionary->impl_vers = DB_CURRENT_VERSION;
1168*7c478bd9Sstevel@tonic-gate 	    initialized = TRUE;
1169*7c478bd9Sstevel@tonic-gate 	} else  /* dictionary loaded successfully */
1170*7c478bd9Sstevel@tonic-gate 	    initialized = TRUE;
1171*7c478bd9Sstevel@tonic-gate 
1172*7c478bd9Sstevel@tonic-gate 	if (initialized == TRUE) {
1173*7c478bd9Sstevel@tonic-gate 	    int num_changes = 0;
1174*7c478bd9Sstevel@tonic-gate 	    changed = FALSE;
1175*7c478bd9Sstevel@tonic-gate 	    reset_log();
1176*7c478bd9Sstevel@tonic-gate 	    if ((num_changes = incorporate_log(logfilename)) < 0)
1177*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
1178*7c478bd9Sstevel@tonic-gate 			"incorporation of dictionary logfile '%s' failed",
1179*7c478bd9Sstevel@tonic-gate 			logfilename);
1180*7c478bd9Sstevel@tonic-gate 	    changed = (num_changes > 0);
1181*7c478bd9Sstevel@tonic-gate 	}
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, initialized, "wu db_dictionary::init");
1184*7c478bd9Sstevel@tonic-gate 	return (initialized);
1185*7c478bd9Sstevel@tonic-gate }
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate /*
1188*7c478bd9Sstevel@tonic-gate  * Execute log entry 'j' on the dictionary identified by 'dict' if the
1189*7c478bd9Sstevel@tonic-gate  * version of j is later than that of the dictionary.  If 'j' is executed,
1190*7c478bd9Sstevel@tonic-gate  * 'count' is incremented and the dictionary's verison is updated to
1191*7c478bd9Sstevel@tonic-gate  * that of 'j'.
1192*7c478bd9Sstevel@tonic-gate  * Returns TRUE always for valid log entries; FALSE otherwise.
1193*7c478bd9Sstevel@tonic-gate  */
1194*7c478bd9Sstevel@tonic-gate static bool_t
1195*7c478bd9Sstevel@tonic-gate apply_log_entry(db_dictlog_entry *j, char *dictchar, int *count)
1196*7c478bd9Sstevel@tonic-gate {
1197*7c478bd9Sstevel@tonic-gate 	db_dictionary *dict = (db_dictionary*) dictchar;
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 	WRITELOCK(dict, FALSE, "w apply_log_entry");
1200*7c478bd9Sstevel@tonic-gate 	if (db_update_version.earlier_than(j->get_version())) {
1201*7c478bd9Sstevel@tonic-gate 		++ *count;
1202*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
1203*7c478bd9Sstevel@tonic-gate 		j->print();
1204*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
1205*7c478bd9Sstevel@tonic-gate 		switch (j->get_action()) {
1206*7c478bd9Sstevel@tonic-gate 		case DB_ADD_TABLE:
1207*7c478bd9Sstevel@tonic-gate 			dict->add_table_aux(j->get_table_name(),
1208*7c478bd9Sstevel@tonic-gate 				j->get_table_object(), INMEMORY_ONLY);
1209*7c478bd9Sstevel@tonic-gate 			// ignore status
1210*7c478bd9Sstevel@tonic-gate 			break;
1211*7c478bd9Sstevel@tonic-gate 
1212*7c478bd9Sstevel@tonic-gate 		case DB_REMOVE_TABLE:
1213*7c478bd9Sstevel@tonic-gate 			dict->delete_table_aux(j->get_table_name(),
1214*7c478bd9Sstevel@tonic-gate 							INMEMORY_ONLY);
1215*7c478bd9Sstevel@tonic-gate 			// ignore status
1216*7c478bd9Sstevel@tonic-gate 			break;
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate 		default:
1219*7c478bd9Sstevel@tonic-gate 			WARNING("db::apply_log_entry: unknown action_type");
1220*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(dict, FALSE, "wu apply_log_entry");
1221*7c478bd9Sstevel@tonic-gate 			return (FALSE);
1222*7c478bd9Sstevel@tonic-gate 		}
1223*7c478bd9Sstevel@tonic-gate 		db_update_version.assign(j->get_version());
1224*7c478bd9Sstevel@tonic-gate 	}
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(dict, TRUE, "wu apply_log_entry");
1227*7c478bd9Sstevel@tonic-gate 	return (TRUE);
1228*7c478bd9Sstevel@tonic-gate }
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate int
1231*7c478bd9Sstevel@tonic-gate db_dictionary::incorporate_log(char *file_name)
1232*7c478bd9Sstevel@tonic-gate {
1233*7c478bd9Sstevel@tonic-gate 	db_dictlog f(file_name, PICKLE_READ);
1234*7c478bd9Sstevel@tonic-gate 	int	ret;
1235*7c478bd9Sstevel@tonic-gate 
1236*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db_dictionary::incorporate_log");
1237*7c478bd9Sstevel@tonic-gate 	setNoWriteThrough();
1238*7c478bd9Sstevel@tonic-gate 	ret = f.execute_on_log(&(apply_log_entry), (char *) this);
1239*7c478bd9Sstevel@tonic-gate 	clearNoWriteThrough();
1240*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db_dictionary::incorporate_log");
1241*7c478bd9Sstevel@tonic-gate 	return (ret);
1242*7c478bd9Sstevel@tonic-gate }
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate /* Frees memory of filename and tables.  Has no effect on disk storage. */
1246*7c478bd9Sstevel@tonic-gate db_status
1247*7c478bd9Sstevel@tonic-gate db_dictionary::db_shutdown()
1248*7c478bd9Sstevel@tonic-gate {
1249*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::db_shutdown");
1250*7c478bd9Sstevel@tonic-gate 	if (!initialized) {
1251*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_LOCK_ERROR,
1252*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::db_shutdown");
1253*7c478bd9Sstevel@tonic-gate 		return (DB_SUCCESS); /* DB_NOTFOUND? */
1254*7c478bd9Sstevel@tonic-gate 	}
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 	if (filename) {
1257*7c478bd9Sstevel@tonic-gate 		delete filename;
1258*7c478bd9Sstevel@tonic-gate 		filename = NULL;
1259*7c478bd9Sstevel@tonic-gate 	}
1260*7c478bd9Sstevel@tonic-gate 	if (tmpfilename) {
1261*7c478bd9Sstevel@tonic-gate 		delete tmpfilename;
1262*7c478bd9Sstevel@tonic-gate 		tmpfilename = NULL;
1263*7c478bd9Sstevel@tonic-gate 	}
1264*7c478bd9Sstevel@tonic-gate 	if (logfilename) {
1265*7c478bd9Sstevel@tonic-gate 		delete logfilename;
1266*7c478bd9Sstevel@tonic-gate 		logfilename = NULL;
1267*7c478bd9Sstevel@tonic-gate 	}
1268*7c478bd9Sstevel@tonic-gate 	if (dictionary) {
1269*7c478bd9Sstevel@tonic-gate 		delete_dictionary(dictionary);
1270*7c478bd9Sstevel@tonic-gate 		dictionary = NULL;
1271*7c478bd9Sstevel@tonic-gate 	}
1272*7c478bd9Sstevel@tonic-gate 	initialized = FALSE;
1273*7c478bd9Sstevel@tonic-gate 	changed = FALSE;
1274*7c478bd9Sstevel@tonic-gate 	reset_log();
1275*7c478bd9Sstevel@tonic-gate 
1276*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, DB_LOCK_ERROR, "wu db_dictionary::db_shutdown");
1277*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
1278*7c478bd9Sstevel@tonic-gate }
1279*7c478bd9Sstevel@tonic-gate 
1280*7c478bd9Sstevel@tonic-gate /*
1281*7c478bd9Sstevel@tonic-gate  * Dump contents of this dictionary (minus the database representations)
1282*7c478bd9Sstevel@tonic-gate  * to its file. Returns 0 if operation succeeds, -1 otherwise.
1283*7c478bd9Sstevel@tonic-gate  */
1284*7c478bd9Sstevel@tonic-gate int
1285*7c478bd9Sstevel@tonic-gate db_dictionary::dump()
1286*7c478bd9Sstevel@tonic-gate {
1287*7c478bd9Sstevel@tonic-gate 	int status;
1288*7c478bd9Sstevel@tonic-gate 
1289*7c478bd9Sstevel@tonic-gate 	READLOCK(this, -1, "r db_dictionary::dump");
1290*7c478bd9Sstevel@tonic-gate 	if (!initialized) {
1291*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, -1, "ru db_dictionary::dump");
1292*7c478bd9Sstevel@tonic-gate 		return (-1);
1293*7c478bd9Sstevel@tonic-gate 	}
1294*7c478bd9Sstevel@tonic-gate 
1295*7c478bd9Sstevel@tonic-gate 	unlink(tmpfilename);  /* get rid of partial dumps */
1296*7c478bd9Sstevel@tonic-gate 	pickle_dict_desc f(tmpfilename, PICKLE_WRITE);
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 	status = f.transfer(&dictionary); 	/* dump table descs */
1299*7c478bd9Sstevel@tonic-gate 	if (status != 0) {
1300*7c478bd9Sstevel@tonic-gate 		WARNING("db_dictionary::dump: could not write out dictionary");
1301*7c478bd9Sstevel@tonic-gate 	} else if (rename(tmpfilename, filename) < 0) {
1302*7c478bd9Sstevel@tonic-gate 		WARNING_M("db_dictionary::dump: could not rename temp file: ");
1303*7c478bd9Sstevel@tonic-gate 		status = -1;
1304*7c478bd9Sstevel@tonic-gate 	}
1305*7c478bd9Sstevel@tonic-gate 
1306*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, -1, "ru db_dictionary::dump");
1307*7c478bd9Sstevel@tonic-gate 	return (status);
1308*7c478bd9Sstevel@tonic-gate }
1309*7c478bd9Sstevel@tonic-gate 
1310*7c478bd9Sstevel@tonic-gate /*
1311*7c478bd9Sstevel@tonic-gate  * Write out in-memory copy of dictionary to file.
1312*7c478bd9Sstevel@tonic-gate  * 1.  Update major version.
1313*7c478bd9Sstevel@tonic-gate  * 2.  Dump contents to temporary file.
1314*7c478bd9Sstevel@tonic-gate  * 3.  Rename temporary file to real dictionary file.
1315*7c478bd9Sstevel@tonic-gate  * 4.  Remove log file.
1316*7c478bd9Sstevel@tonic-gate  * A checkpoint is done only if it has changed since the previous checkpoint.
1317*7c478bd9Sstevel@tonic-gate  * Returns DB_SUCCESS if checkpoint was successful; error code otherwise
1318*7c478bd9Sstevel@tonic-gate  */
1319*7c478bd9Sstevel@tonic-gate db_status
1320*7c478bd9Sstevel@tonic-gate db_dictionary::checkpoint()
1321*7c478bd9Sstevel@tonic-gate {
1322*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::checkpoint");
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	if (changed == FALSE) {
1325*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_LOCK_ERROR,
1326*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::checkpoint");
1327*7c478bd9Sstevel@tonic-gate 		return (DB_SUCCESS);
1328*7c478bd9Sstevel@tonic-gate 	}
1329*7c478bd9Sstevel@tonic-gate 
1330*7c478bd9Sstevel@tonic-gate 	vers *oldv = new vers(db_update_version);	// copy
1331*7c478bd9Sstevel@tonic-gate 	vers * newv = db_update_version.nextmajor();	// get next version
1332*7c478bd9Sstevel@tonic-gate 	db_update_version.assign(newv);			// update version
1333*7c478bd9Sstevel@tonic-gate 	delete newv;
1334*7c478bd9Sstevel@tonic-gate 
1335*7c478bd9Sstevel@tonic-gate 	if (dump() != 0) {
1336*7c478bd9Sstevel@tonic-gate 		WARNING_M(
1337*7c478bd9Sstevel@tonic-gate 		    "db_dictionary::checkpoint: could not dump dictionary: ");
1338*7c478bd9Sstevel@tonic-gate 		db_update_version.assign(oldv);  // rollback
1339*7c478bd9Sstevel@tonic-gate 		delete oldv;
1340*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_INTERNAL_ERROR,
1341*7c478bd9Sstevel@tonic-gate 			"wu db_dictionary::checkpoint");
1342*7c478bd9Sstevel@tonic-gate 		return (DB_INTERNAL_ERROR);
1343*7c478bd9Sstevel@tonic-gate 	}
1344*7c478bd9Sstevel@tonic-gate 	unlink(logfilename);	/* should do atomic rename and log delete */
1345*7c478bd9Sstevel@tonic-gate 	reset_log();		/* should check for what? */
1346*7c478bd9Sstevel@tonic-gate 	delete oldv;
1347*7c478bd9Sstevel@tonic-gate 	changed = FALSE;
1348*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, DB_LOCK_ERROR, "wu db_dictionary::checkpoint");
1349*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
1350*7c478bd9Sstevel@tonic-gate }
1351*7c478bd9Sstevel@tonic-gate 
1352*7c478bd9Sstevel@tonic-gate /* close existing logfile and delete its structure */
1353*7c478bd9Sstevel@tonic-gate int
1354*7c478bd9Sstevel@tonic-gate db_dictionary::reset_log()
1355*7c478bd9Sstevel@tonic-gate {
1356*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db_dictionary::reset_log");
1357*7c478bd9Sstevel@tonic-gate 	/* try to close old log file */
1358*7c478bd9Sstevel@tonic-gate 	/* doesnot matter since we do synchronous writes only */
1359*7c478bd9Sstevel@tonic-gate 	if (logfile != NULL) {
1360*7c478bd9Sstevel@tonic-gate 		if (logfile_opened == TRUE) {
1361*7c478bd9Sstevel@tonic-gate 			if (logfile->close() < 0) {
1362*7c478bd9Sstevel@tonic-gate 				WARNING_M(
1363*7c478bd9Sstevel@tonic-gate 			"db_dictionary::reset_log: could not close log file: ");
1364*7c478bd9Sstevel@tonic-gate 			}
1365*7c478bd9Sstevel@tonic-gate 		}
1366*7c478bd9Sstevel@tonic-gate 		delete logfile;
1367*7c478bd9Sstevel@tonic-gate 		logfile = NULL;
1368*7c478bd9Sstevel@tonic-gate 	}
1369*7c478bd9Sstevel@tonic-gate 	logfile_opened = FALSE;
1370*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db_dictionary::reset_log");
1371*7c478bd9Sstevel@tonic-gate 	return (0);
1372*7c478bd9Sstevel@tonic-gate }
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate /* close existing logfile, but leave its structure if exists */
1375*7c478bd9Sstevel@tonic-gate int
1376*7c478bd9Sstevel@tonic-gate db_dictionary::close_log()
1377*7c478bd9Sstevel@tonic-gate {
1378*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db_dictionary::close_log");
1379*7c478bd9Sstevel@tonic-gate 	if (logfile != NULL && logfile_opened == TRUE) {
1380*7c478bd9Sstevel@tonic-gate 		logfile->close();
1381*7c478bd9Sstevel@tonic-gate 	}
1382*7c478bd9Sstevel@tonic-gate 	logfile_opened = FALSE;
1383*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db_dictionary::close_log");
1384*7c478bd9Sstevel@tonic-gate 	return (0);
1385*7c478bd9Sstevel@tonic-gate }
1386*7c478bd9Sstevel@tonic-gate 
1387*7c478bd9Sstevel@tonic-gate /* open logfile, creating its structure if it does not exist */
1388*7c478bd9Sstevel@tonic-gate int
1389*7c478bd9Sstevel@tonic-gate db_dictionary::open_log()
1390*7c478bd9Sstevel@tonic-gate {
1391*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db_dictionary::open_log");
1392*7c478bd9Sstevel@tonic-gate 	if (logfile == NULL) {
1393*7c478bd9Sstevel@tonic-gate 		if ((logfile = new db_dictlog(logfilename, PICKLE_APPEND)) ==
1394*7c478bd9Sstevel@tonic-gate 				NULL) {
1395*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, -1, "wu db_dictionary::open_log");
1396*7c478bd9Sstevel@tonic-gate 			FATAL3(
1397*7c478bd9Sstevel@tonic-gate 			"db_dictionary::reset_log: cannot allocate space",
1398*7c478bd9Sstevel@tonic-gate 				DB_MEMORY_LIMIT, -1);
1399*7c478bd9Sstevel@tonic-gate 		}
1400*7c478bd9Sstevel@tonic-gate 	}
1401*7c478bd9Sstevel@tonic-gate 
1402*7c478bd9Sstevel@tonic-gate 	if (logfile_opened == TRUE) {
1403*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, -1, "wu db_dictionary::open_log");
1404*7c478bd9Sstevel@tonic-gate 		return (0);
1405*7c478bd9Sstevel@tonic-gate 	}
1406*7c478bd9Sstevel@tonic-gate 
1407*7c478bd9Sstevel@tonic-gate 	if ((logfile->open()) == NULL) {
1408*7c478bd9Sstevel@tonic-gate 		WARNING_M("db_dictionary::open_log: could not open log file: ");
1409*7c478bd9Sstevel@tonic-gate 		delete logfile;
1410*7c478bd9Sstevel@tonic-gate 		logfile = NULL;
1411*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, -1, "wu db_dictionary::open_log");
1412*7c478bd9Sstevel@tonic-gate 		return (-1);
1413*7c478bd9Sstevel@tonic-gate 	}
1414*7c478bd9Sstevel@tonic-gate 
1415*7c478bd9Sstevel@tonic-gate 	logfile_opened = TRUE;
1416*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db_dictionary::open_log");
1417*7c478bd9Sstevel@tonic-gate 	return (0);
1418*7c478bd9Sstevel@tonic-gate }
1419*7c478bd9Sstevel@tonic-gate 
1420*7c478bd9Sstevel@tonic-gate /*
1421*7c478bd9Sstevel@tonic-gate  * closes any open log files for all tables in dictionary or 'tab'.
1422*7c478bd9Sstevel@tonic-gate  * "tab" is an optional argument.
1423*7c478bd9Sstevel@tonic-gate  */
1424*7c478bd9Sstevel@tonic-gate static int close_standby_list();
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate db_status
1427*7c478bd9Sstevel@tonic-gate db_dictionary::db_standby(char *tab)
1428*7c478bd9Sstevel@tonic-gate {
1429*7c478bd9Sstevel@tonic-gate 	db_table_desc *tbl;
1430*7c478bd9Sstevel@tonic-gate 
1431*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::db_standby");
1432*7c478bd9Sstevel@tonic-gate 	if (!initialized) {
1433*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_BADDICTIONARY,
1434*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::db_standby");
1435*7c478bd9Sstevel@tonic-gate 		return (DB_BADDICTIONARY);
1436*7c478bd9Sstevel@tonic-gate 	}
1437*7c478bd9Sstevel@tonic-gate 
1438*7c478bd9Sstevel@tonic-gate 	if (tab == NULL) {
1439*7c478bd9Sstevel@tonic-gate 	    close_log();  // close dictionary log
1440*7c478bd9Sstevel@tonic-gate 	    close_standby_list();
1441*7c478bd9Sstevel@tonic-gate 	    WRITEUNLOCK(this, DB_LOCK_ERROR, "wu db_dictionary::db_standby");
1442*7c478bd9Sstevel@tonic-gate 	    return (DB_SUCCESS);
1443*7c478bd9Sstevel@tonic-gate 	}
1444*7c478bd9Sstevel@tonic-gate 
1445*7c478bd9Sstevel@tonic-gate 	if ((tbl = find_table_desc(tab)) == NULL) {
1446*7c478bd9Sstevel@tonic-gate 	    WRITEUNLOCK(this, DB_LOCK_ERROR, "wu db_dictionary::db_standby");
1447*7c478bd9Sstevel@tonic-gate 	    return (DB_BADTABLE);
1448*7c478bd9Sstevel@tonic-gate 	}
1449*7c478bd9Sstevel@tonic-gate 
1450*7c478bd9Sstevel@tonic-gate 	if (tbl->database != NULL)
1451*7c478bd9Sstevel@tonic-gate 	    tbl->database->close_log();
1452*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, DB_LOCK_ERROR, "wu db_dictionary::db_standby");
1453*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
1454*7c478bd9Sstevel@tonic-gate }
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate /*
1457*7c478bd9Sstevel@tonic-gate  * Returns db_table_desc of table name 'tab'.  'prev', if supplied,
1458*7c478bd9Sstevel@tonic-gate  * is set to the entry located ahead of 'tab's entry in the dictionary.
1459*7c478bd9Sstevel@tonic-gate  */
1460*7c478bd9Sstevel@tonic-gate db_table_desc*
1461*7c478bd9Sstevel@tonic-gate db_dictionary::find_table_desc(char *tab)
1462*7c478bd9Sstevel@tonic-gate {
1463*7c478bd9Sstevel@tonic-gate 	db_table_desc	*ret;
1464*7c478bd9Sstevel@tonic-gate 
1465*7c478bd9Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_dictionary::find_table_desc");
1466*7c478bd9Sstevel@tonic-gate 	if (initialized)
1467*7c478bd9Sstevel@tonic-gate 		ret = search_dictionary(dictionary, tab);
1468*7c478bd9Sstevel@tonic-gate 	else
1469*7c478bd9Sstevel@tonic-gate 		ret = NULL;
1470*7c478bd9Sstevel@tonic-gate 
1471*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, ret, "r db_dictionary::find_table_desc");
1472*7c478bd9Sstevel@tonic-gate 	return (ret);
1473*7c478bd9Sstevel@tonic-gate }
1474*7c478bd9Sstevel@tonic-gate 
1475*7c478bd9Sstevel@tonic-gate db_table_desc *
1476*7c478bd9Sstevel@tonic-gate db_dictionary::find_table_desc(char *tab, bool_t searchDeferred) {
1477*7c478bd9Sstevel@tonic-gate 	db_table_desc	*ret = NULL;
1478*7c478bd9Sstevel@tonic-gate 
1479*7c478bd9Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_dictionary::find_table_desc_d");
1480*7c478bd9Sstevel@tonic-gate 
1481*7c478bd9Sstevel@tonic-gate 	/* If desired, look in the deferred dictionary first */
1482*7c478bd9Sstevel@tonic-gate 	if (initialized && searchDeferred && deferred.dictionary != NULL)
1483*7c478bd9Sstevel@tonic-gate 		ret = search_dictionary(deferred.dictionary, tab);
1484*7c478bd9Sstevel@tonic-gate 
1485*7c478bd9Sstevel@tonic-gate 	/* No result yet => search the "normal" dictionary */
1486*7c478bd9Sstevel@tonic-gate 	if (ret == NULL)
1487*7c478bd9Sstevel@tonic-gate 		ret = find_table_desc(tab);
1488*7c478bd9Sstevel@tonic-gate 
1489*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, ret, "r db_dictionary::find_table_desc_d");
1490*7c478bd9Sstevel@tonic-gate 	return (ret);
1491*7c478bd9Sstevel@tonic-gate }
1492*7c478bd9Sstevel@tonic-gate 
1493*7c478bd9Sstevel@tonic-gate db *
1494*7c478bd9Sstevel@tonic-gate db_dictionary::find_table(char *tab, db_table_desc **where) {
1495*7c478bd9Sstevel@tonic-gate 	/* Most operations should use the deferred dictionary if it exists */
1496*7c478bd9Sstevel@tonic-gate 	return (find_table(tab, where, TRUE, TRUE, TRUE));
1497*7c478bd9Sstevel@tonic-gate }
1498*7c478bd9Sstevel@tonic-gate 
1499*7c478bd9Sstevel@tonic-gate db *
1500*7c478bd9Sstevel@tonic-gate db_dictionary::find_table(char *tab, db_table_desc **where,
1501*7c478bd9Sstevel@tonic-gate 				bool_t searchDeferred) {
1502*7c478bd9Sstevel@tonic-gate 	return (find_table(tab, where, searchDeferred, TRUE, TRUE));
1503*7c478bd9Sstevel@tonic-gate }
1504*7c478bd9Sstevel@tonic-gate 
1505*7c478bd9Sstevel@tonic-gate db *
1506*7c478bd9Sstevel@tonic-gate db_dictionary::find_table(char *tab, db_table_desc **where,
1507*7c478bd9Sstevel@tonic-gate 				bool_t searchDeferred, bool_t doLDAP,
1508*7c478bd9Sstevel@tonic-gate 				bool_t doLoad) {
1509*7c478bd9Sstevel@tonic-gate 	db			*res;
1510*7c478bd9Sstevel@tonic-gate 	int			lstat;
1511*7c478bd9Sstevel@tonic-gate 	db_status		dstat;
1512*7c478bd9Sstevel@tonic-gate 	char			*myself = "db_dictionary::find_table";
1513*7c478bd9Sstevel@tonic-gate 
1514*7c478bd9Sstevel@tonic-gate 	res = find_table_noLDAP(tab, where, searchDeferred, doLoad);
1515*7c478bd9Sstevel@tonic-gate 	/* If found, or shouldn't try LDAP, we're done */
1516*7c478bd9Sstevel@tonic-gate 	if (res != 0 || !doLDAP)
1517*7c478bd9Sstevel@tonic-gate 		return (res);
1518*7c478bd9Sstevel@tonic-gate 
1519*7c478bd9Sstevel@tonic-gate 	/* See if we can retrieve the object from LDAP */
1520*7c478bd9Sstevel@tonic-gate 	dstat = dbCreateFromLDAP(tab, &lstat);
1521*7c478bd9Sstevel@tonic-gate 	if (dstat != DB_SUCCESS) {
1522*7c478bd9Sstevel@tonic-gate 		if (dstat == DB_NOTFOUND) {
1523*7c478bd9Sstevel@tonic-gate 			if (lstat != LDAP_SUCCESS) {
1524*7c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_INFO,
1525*7c478bd9Sstevel@tonic-gate 					"%s: LDAP error for \"%s\": %s",
1526*7c478bd9Sstevel@tonic-gate 					myself, NIL(tab),
1527*7c478bd9Sstevel@tonic-gate 					ldap_err2string(lstat));
1528*7c478bd9Sstevel@tonic-gate 			}
1529*7c478bd9Sstevel@tonic-gate 		} else {
1530*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
1531*7c478bd9Sstevel@tonic-gate 				"%s: DB error %d for \"%s\"",
1532*7c478bd9Sstevel@tonic-gate 				myself, dstat, NIL(tab));
1533*7c478bd9Sstevel@tonic-gate 		}
1534*7c478bd9Sstevel@tonic-gate 		return (0);
1535*7c478bd9Sstevel@tonic-gate 	}
1536*7c478bd9Sstevel@tonic-gate 
1537*7c478bd9Sstevel@tonic-gate 	/* Try the dictionary again */
1538*7c478bd9Sstevel@tonic-gate 	res = find_table_noLDAP(tab, where, searchDeferred, doLoad);
1539*7c478bd9Sstevel@tonic-gate 
1540*7c478bd9Sstevel@tonic-gate 	return (res);
1541*7c478bd9Sstevel@tonic-gate }
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate /*
1544*7c478bd9Sstevel@tonic-gate  * Return database structure of table named by 'tab'.
1545*7c478bd9Sstevel@tonic-gate  * If 'where' is set, set it to the table_desc of 'tab.'
1546*7c478bd9Sstevel@tonic-gate  * If the database is loaded in from stable store if it has not been loaded.
1547*7c478bd9Sstevel@tonic-gate  * If it cannot be loaded, it is initialized using the scheme stored in
1548*7c478bd9Sstevel@tonic-gate  * the table_desc.  NULL is returned if the initialization fails.
1549*7c478bd9Sstevel@tonic-gate  */
1550*7c478bd9Sstevel@tonic-gate db *
1551*7c478bd9Sstevel@tonic-gate db_dictionary::find_table_noLDAP(char *tab, db_table_desc **where,
1552*7c478bd9Sstevel@tonic-gate 				bool_t searchDeferred, bool_t doLoad)
1553*7c478bd9Sstevel@tonic-gate {
1554*7c478bd9Sstevel@tonic-gate 	if (!initialized)
1555*7c478bd9Sstevel@tonic-gate 		return (NULL);
1556*7c478bd9Sstevel@tonic-gate 
1557*7c478bd9Sstevel@tonic-gate 	db_table_desc* tbl;
1558*7c478bd9Sstevel@tonic-gate 	db *dbase = NULL;
1559*7c478bd9Sstevel@tonic-gate 	int		lret;
1560*7c478bd9Sstevel@tonic-gate 
1561*7c478bd9Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_dictionary::find_table");
1562*7c478bd9Sstevel@tonic-gate 	tbl = find_table_desc(tab, searchDeferred);
1563*7c478bd9Sstevel@tonic-gate 	if (tbl == NULL) {
1564*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, NULL, "ru db_dictionary::find_table");
1565*7c478bd9Sstevel@tonic-gate 		return (NULL);		// not found
1566*7c478bd9Sstevel@tonic-gate 	}
1567*7c478bd9Sstevel@tonic-gate 
1568*7c478bd9Sstevel@tonic-gate 	if (tbl->database != NULL || !doLoad) {
1569*7c478bd9Sstevel@tonic-gate 		if (tbl->database && where) *where = tbl;
1570*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, NULL, "ru db_dictionary::find_table");
1571*7c478bd9Sstevel@tonic-gate 		return (tbl->database);  // return handle
1572*7c478bd9Sstevel@tonic-gate 	}
1573*7c478bd9Sstevel@tonic-gate 
1574*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, NULL, "ru db_dictionary::find_table");
1575*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, NULL, "w db_dictionary::find_table");
1576*7c478bd9Sstevel@tonic-gate 	/* Re-check; some other thread might have loaded the db */
1577*7c478bd9Sstevel@tonic-gate 	if (tbl->database != NULL) {
1578*7c478bd9Sstevel@tonic-gate 		if (where) *where = tbl;
1579*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, NULL, "wu db_dictionary::find_table");
1580*7c478bd9Sstevel@tonic-gate 		return (tbl->database);  // return handle
1581*7c478bd9Sstevel@tonic-gate 	}
1582*7c478bd9Sstevel@tonic-gate 
1583*7c478bd9Sstevel@tonic-gate 	// need to load in/init database
1584*7c478bd9Sstevel@tonic-gate 	dbase = new db(tab);
1585*7c478bd9Sstevel@tonic-gate 
1586*7c478bd9Sstevel@tonic-gate 	if (dbase == NULL) {
1587*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, NULL,
1588*7c478bd9Sstevel@tonic-gate 			"db_dictionary::find_table: could not allocate space");
1589*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::find_table: could not allocate space",
1590*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, NULL);
1591*7c478bd9Sstevel@tonic-gate 	}
1592*7c478bd9Sstevel@tonic-gate 
1593*7c478bd9Sstevel@tonic-gate 	/*
1594*7c478bd9Sstevel@tonic-gate 	 * Lock the newly created 'dbase', so we can release the general
1595*7c478bd9Sstevel@tonic-gate 	 * db_dictionary lock.
1596*7c478bd9Sstevel@tonic-gate 	 */
1597*7c478bd9Sstevel@tonic-gate 	WRITELOCKNR(dbase, lret, "w dbase db_dictionary::find_table");
1598*7c478bd9Sstevel@tonic-gate 	if (lret != 0) {
1599*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, NULL,
1600*7c478bd9Sstevel@tonic-gate 			"db_dictionary::find_table: could not lock dbase");
1601*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::find_table: could not lock dbase",
1602*7c478bd9Sstevel@tonic-gate 			DB_LOCK_ERROR, NULL);
1603*7c478bd9Sstevel@tonic-gate 	}
1604*7c478bd9Sstevel@tonic-gate 	/* Assign tbl->database, and then release the 'this' lock */
1605*7c478bd9Sstevel@tonic-gate 	tbl->database = dbase;
1606*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, NULL, "wu db_dictionary::find_table");
1607*7c478bd9Sstevel@tonic-gate 
1608*7c478bd9Sstevel@tonic-gate 	if (dbase->load()) {			// try to load in database
1609*7c478bd9Sstevel@tonic-gate 		if (where) *where = tbl;
1610*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(dbase, dbase, "wu dbase db_dictionary::find_table");
1611*7c478bd9Sstevel@tonic-gate 		return (dbase);
1612*7c478bd9Sstevel@tonic-gate 	}
1613*7c478bd9Sstevel@tonic-gate 
1614*7c478bd9Sstevel@tonic-gate 	delete dbase;
1615*7c478bd9Sstevel@tonic-gate 	tbl->database = NULL;
1616*7c478bd9Sstevel@tonic-gate 	WARNING("db_dictionary::find_table: could not load database");
1617*7c478bd9Sstevel@tonic-gate 	return (NULL);
1618*7c478bd9Sstevel@tonic-gate }
1619*7c478bd9Sstevel@tonic-gate 
1620*7c478bd9Sstevel@tonic-gate /* Log action to be taken on the  dictionary and update db_update_version. */
1621*7c478bd9Sstevel@tonic-gate 
1622*7c478bd9Sstevel@tonic-gate db_status
1623*7c478bd9Sstevel@tonic-gate db_dictionary::log_action(int action, char *tab, table_obj *tobj)
1624*7c478bd9Sstevel@tonic-gate {
1625*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::log_action");
1626*7c478bd9Sstevel@tonic-gate 
1627*7c478bd9Sstevel@tonic-gate 	vers *newv = db_update_version.nextminor();
1628*7c478bd9Sstevel@tonic-gate 	db_dictlog_entry le(action, newv, tab, tobj);
1629*7c478bd9Sstevel@tonic-gate 
1630*7c478bd9Sstevel@tonic-gate 	if (open_log() < 0) {
1631*7c478bd9Sstevel@tonic-gate 		delete newv;
1632*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_STORAGE_LIMIT,
1633*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::log_action");
1634*7c478bd9Sstevel@tonic-gate 		return (DB_STORAGE_LIMIT);
1635*7c478bd9Sstevel@tonic-gate 	}
1636*7c478bd9Sstevel@tonic-gate 
1637*7c478bd9Sstevel@tonic-gate 	if (logfile->append(&le) < 0) {
1638*7c478bd9Sstevel@tonic-gate 		WARNING_M("db::log_action: could not add log entry: ");
1639*7c478bd9Sstevel@tonic-gate 		close_log();
1640*7c478bd9Sstevel@tonic-gate 		delete newv;
1641*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_STORAGE_LIMIT,
1642*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::log_action");
1643*7c478bd9Sstevel@tonic-gate 		return (DB_STORAGE_LIMIT);
1644*7c478bd9Sstevel@tonic-gate 	}
1645*7c478bd9Sstevel@tonic-gate 
1646*7c478bd9Sstevel@tonic-gate 	db_update_version.assign(newv);
1647*7c478bd9Sstevel@tonic-gate 	delete newv;
1648*7c478bd9Sstevel@tonic-gate 	changed = TRUE;
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, DB_LOCK_ERROR, "wu db_dictionary::log_action");
1651*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
1652*7c478bd9Sstevel@tonic-gate }
1653*7c478bd9Sstevel@tonic-gate 
1654*7c478bd9Sstevel@tonic-gate // For a complete 'delete' operation, we want the following behaviour:
1655*7c478bd9Sstevel@tonic-gate // 1. If there is an entry in the log, the physical table exists and is
1656*7c478bd9Sstevel@tonic-gate //    stable.
1657*7c478bd9Sstevel@tonic-gate // 2. If there is no entry in the log, the physical table may or may not
1658*7c478bd9Sstevel@tonic-gate //    exist.
1659*7c478bd9Sstevel@tonic-gate 
1660*7c478bd9Sstevel@tonic-gate db_status
1661*7c478bd9Sstevel@tonic-gate db_dictionary::delete_table_aux(char *tab, int mode)
1662*7c478bd9Sstevel@tonic-gate {
1663*7c478bd9Sstevel@tonic-gate 	db_status	ret;
1664*7c478bd9Sstevel@tonic-gate 
1665*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::delete_table_aux");
1666*7c478bd9Sstevel@tonic-gate 	if (!initialized) {
1667*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_LOCK_ERROR,
1668*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::delete_table_aux");
1669*7c478bd9Sstevel@tonic-gate 		return (DB_BADDICTIONARY);
1670*7c478bd9Sstevel@tonic-gate 	}
1671*7c478bd9Sstevel@tonic-gate 
1672*7c478bd9Sstevel@tonic-gate 	db_table_desc *tbl;
1673*7c478bd9Sstevel@tonic-gate 	if ((tbl = find_table_desc(tab)) == NULL) { // table not found
1674*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_LOCK_ERROR,
1675*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::delete_table_aux");
1676*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
1677*7c478bd9Sstevel@tonic-gate 	}
1678*7c478bd9Sstevel@tonic-gate 
1679*7c478bd9Sstevel@tonic-gate 	if (mode != INMEMORY_ONLY) {
1680*7c478bd9Sstevel@tonic-gate 		int need_free = 0;
1681*7c478bd9Sstevel@tonic-gate 
1682*7c478bd9Sstevel@tonic-gate 		// Update log.
1683*7c478bd9Sstevel@tonic-gate 		db_status status = log_action(DB_REMOVE_TABLE, tab);
1684*7c478bd9Sstevel@tonic-gate 		if (status != DB_SUCCESS) {
1685*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, status,
1686*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::delete_table_aux");
1687*7c478bd9Sstevel@tonic-gate 			return (status);
1688*7c478bd9Sstevel@tonic-gate 		}
1689*7c478bd9Sstevel@tonic-gate 
1690*7c478bd9Sstevel@tonic-gate 		// Remove physical structures
1691*7c478bd9Sstevel@tonic-gate 		db *dbase = tbl->database;
1692*7c478bd9Sstevel@tonic-gate 		if (dbase == NULL) {	// need to get desc to access files
1693*7c478bd9Sstevel@tonic-gate 			dbase = new db(tab);
1694*7c478bd9Sstevel@tonic-gate 			need_free = 1;
1695*7c478bd9Sstevel@tonic-gate 		}
1696*7c478bd9Sstevel@tonic-gate 		if (dbase == NULL) {
1697*7c478bd9Sstevel@tonic-gate 			WARNING(
1698*7c478bd9Sstevel@tonic-gate 		"db_dictionary::delete_table: could not create db structure");
1699*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, DB_MEMORY_LIMIT,
1700*7c478bd9Sstevel@tonic-gate 					"wu db_dictionary::delete_table_aux");
1701*7c478bd9Sstevel@tonic-gate 			return (DB_MEMORY_LIMIT);
1702*7c478bd9Sstevel@tonic-gate 		}
1703*7c478bd9Sstevel@tonic-gate 		dbase->remove_files();	// remove physical files
1704*7c478bd9Sstevel@tonic-gate 		if (need_free)
1705*7c478bd9Sstevel@tonic-gate 			delete dbase;
1706*7c478bd9Sstevel@tonic-gate 	}
1707*7c478bd9Sstevel@tonic-gate 
1708*7c478bd9Sstevel@tonic-gate 	// Remove in-memory structures
1709*7c478bd9Sstevel@tonic-gate 	ret = remove_from_dictionary(dictionary, tab, TRUE);
1710*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, ret, "wu db_dictionary::delete_table_aux");
1711*7c478bd9Sstevel@tonic-gate 	return (ret);
1712*7c478bd9Sstevel@tonic-gate }
1713*7c478bd9Sstevel@tonic-gate 
1714*7c478bd9Sstevel@tonic-gate /*
1715*7c478bd9Sstevel@tonic-gate  * Delete table with given name 'tab' from dictionary.
1716*7c478bd9Sstevel@tonic-gate  * Returns error code if table does not exist or if dictionary has not been
1717*7c478bd9Sstevel@tonic-gate  * initialized.   Dictionary is updated to stable store if deletion is
1718*7c478bd9Sstevel@tonic-gate  * successful.  Fatal error occurs if dictionary cannot be saved.
1719*7c478bd9Sstevel@tonic-gate  * Returns DB_SUCCESS if dictionary has been updated successfully.
1720*7c478bd9Sstevel@tonic-gate  * Note that the files associated with the table are also removed.
1721*7c478bd9Sstevel@tonic-gate  */
1722*7c478bd9Sstevel@tonic-gate db_status
1723*7c478bd9Sstevel@tonic-gate db_dictionary::delete_table(char *tab)
1724*7c478bd9Sstevel@tonic-gate {
1725*7c478bd9Sstevel@tonic-gate 	return (delete_table_aux(tab, !INMEMORY_ONLY));
1726*7c478bd9Sstevel@tonic-gate }
1727*7c478bd9Sstevel@tonic-gate 
1728*7c478bd9Sstevel@tonic-gate // For a complete 'add' operation, we want the following behaviour:
1729*7c478bd9Sstevel@tonic-gate // 1. If there is an entry in the log, then the physical table exists and
1730*7c478bd9Sstevel@tonic-gate //    has been initialized properly.
1731*7c478bd9Sstevel@tonic-gate // 2. If there is no entry in the log, the physical table may or may not
1732*7c478bd9Sstevel@tonic-gate //    exist.  In this case, we don't really care because we cannot get at
1733*7c478bd9Sstevel@tonic-gate //    it.  The next time we add a table with the same name to the dictionary,
1734*7c478bd9Sstevel@tonic-gate //    it will be initialized properly.
1735*7c478bd9Sstevel@tonic-gate // This mode is used when the table is first created.
1736*7c478bd9Sstevel@tonic-gate //
1737*7c478bd9Sstevel@tonic-gate // For an INMEMORY_ONLY operation, only the internal structure is created and
1738*7c478bd9Sstevel@tonic-gate // updated.  This mode is used when the database gets loaded and the internal
1739*7c478bd9Sstevel@tonic-gate // dictionary gets updated from the log entries.
1740*7c478bd9Sstevel@tonic-gate 
1741*7c478bd9Sstevel@tonic-gate db_status
1742*7c478bd9Sstevel@tonic-gate db_dictionary::add_table_aux(char *tab, table_obj* tobj, int mode)
1743*7c478bd9Sstevel@tonic-gate {
1744*7c478bd9Sstevel@tonic-gate 	db_status	ret;
1745*7c478bd9Sstevel@tonic-gate 
1746*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::add_table_aux");
1747*7c478bd9Sstevel@tonic-gate 	if (!initialized) {
1748*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_LOCK_ERROR,
1749*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::add_table_aux");
1750*7c478bd9Sstevel@tonic-gate 		return (DB_BADDICTIONARY);
1751*7c478bd9Sstevel@tonic-gate 	}
1752*7c478bd9Sstevel@tonic-gate 
1753*7c478bd9Sstevel@tonic-gate 	if (find_table_desc(tab) != NULL) {
1754*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_LOCK_ERROR,
1755*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::add_table_aux");
1756*7c478bd9Sstevel@tonic-gate 		return (DB_NOTUNIQUE);		// table already exists
1757*7c478bd9Sstevel@tonic-gate 	}
1758*7c478bd9Sstevel@tonic-gate 
1759*7c478bd9Sstevel@tonic-gate 	// create data structures for table
1760*7c478bd9Sstevel@tonic-gate 	db_table_desc *new_table = 0;
1761*7c478bd9Sstevel@tonic-gate 	db_status status = create_table_desc(tab, tobj, &new_table);
1762*7c478bd9Sstevel@tonic-gate 
1763*7c478bd9Sstevel@tonic-gate 	if (status != DB_SUCCESS) {
1764*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_LOCK_ERROR,
1765*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::add_table_aux");
1766*7c478bd9Sstevel@tonic-gate 		return (status);
1767*7c478bd9Sstevel@tonic-gate 	}
1768*7c478bd9Sstevel@tonic-gate 
1769*7c478bd9Sstevel@tonic-gate 	if (mode != INMEMORY_ONLY) {
1770*7c478bd9Sstevel@tonic-gate 		// create physical structures for table
1771*7c478bd9Sstevel@tonic-gate 		new_table->database = new db(tab);
1772*7c478bd9Sstevel@tonic-gate 		if (new_table->database == NULL) {
1773*7c478bd9Sstevel@tonic-gate 			delete_table_desc(new_table);
1774*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, DB_MEMORY_LIMIT,
1775*7c478bd9Sstevel@tonic-gate 		"db_dictionary::add_table: could not allocate space for db");
1776*7c478bd9Sstevel@tonic-gate 			FATAL3(
1777*7c478bd9Sstevel@tonic-gate 		    "db_dictionary::add_table: could not allocate space for db",
1778*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, DB_MEMORY_LIMIT);
1779*7c478bd9Sstevel@tonic-gate 		}
1780*7c478bd9Sstevel@tonic-gate 		if (new_table->database->init(new_table->scheme) == 0) {
1781*7c478bd9Sstevel@tonic-gate 			WARNING(
1782*7c478bd9Sstevel@tonic-gate 	"db_dictionary::add_table: could not initialize database from scheme");
1783*7c478bd9Sstevel@tonic-gate 			new_table->database->remove_files();
1784*7c478bd9Sstevel@tonic-gate 			delete_table_desc(new_table);
1785*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, DB_STORAGE_LIMIT,
1786*7c478bd9Sstevel@tonic-gate 				"wu db_dictionary::add_table_aux");
1787*7c478bd9Sstevel@tonic-gate 			return (DB_STORAGE_LIMIT);
1788*7c478bd9Sstevel@tonic-gate 		}
1789*7c478bd9Sstevel@tonic-gate 
1790*7c478bd9Sstevel@tonic-gate 		// update 'external' copy of dictionary
1791*7c478bd9Sstevel@tonic-gate 		status = log_action(DB_ADD_TABLE, tab, tobj);
1792*7c478bd9Sstevel@tonic-gate 
1793*7c478bd9Sstevel@tonic-gate 		if (status != DB_SUCCESS) {
1794*7c478bd9Sstevel@tonic-gate 			new_table->database->remove_files();
1795*7c478bd9Sstevel@tonic-gate 			delete_table_desc(new_table);
1796*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, status,
1797*7c478bd9Sstevel@tonic-gate 					"wu db_dictionary::add_table_aux");
1798*7c478bd9Sstevel@tonic-gate 			return (status);
1799*7c478bd9Sstevel@tonic-gate 		}
1800*7c478bd9Sstevel@tonic-gate 	}
1801*7c478bd9Sstevel@tonic-gate 
1802*7c478bd9Sstevel@tonic-gate 	// finally, update in-memory copy of dictionary
1803*7c478bd9Sstevel@tonic-gate 	ret = add_to_dictionary(dictionary, new_table);
1804*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, ret, "wu db_dictionary::add_table_aux");
1805*7c478bd9Sstevel@tonic-gate 	return (ret);
1806*7c478bd9Sstevel@tonic-gate }
1807*7c478bd9Sstevel@tonic-gate 
1808*7c478bd9Sstevel@tonic-gate /*
1809*7c478bd9Sstevel@tonic-gate  * Add table with given name 'tab' and description 'zdesc' to dictionary.
1810*7c478bd9Sstevel@tonic-gate  * Returns errror code if table already exists, or if no memory can be found
1811*7c478bd9Sstevel@tonic-gate  * to store the descriptor, or if dictionary has not been intialized.
1812*7c478bd9Sstevel@tonic-gate  * Dictionary is updated to stable store if addition is successful.
1813*7c478bd9Sstevel@tonic-gate  * Fatal error occurs if dictionary cannot be saved.
1814*7c478bd9Sstevel@tonic-gate  * Returns DB_SUCCESS if dictionary has been updated successfully.
1815*7c478bd9Sstevel@tonic-gate */
1816*7c478bd9Sstevel@tonic-gate db_status
1817*7c478bd9Sstevel@tonic-gate db_dictionary::add_table(char *tab, table_obj* tobj)
1818*7c478bd9Sstevel@tonic-gate {
1819*7c478bd9Sstevel@tonic-gate 	return (add_table_aux(tab, tobj, !INMEMORY_ONLY));
1820*7c478bd9Sstevel@tonic-gate }
1821*7c478bd9Sstevel@tonic-gate 
1822*7c478bd9Sstevel@tonic-gate /*
1823*7c478bd9Sstevel@tonic-gate  * Translate given NIS attribute list to a db_query structure.
1824*7c478bd9Sstevel@tonic-gate  * Return FALSE if dictionary has not been initialized, or
1825*7c478bd9Sstevel@tonic-gate  * table does not have a scheme (which should be a fatal error?).
1826*7c478bd9Sstevel@tonic-gate  */
1827*7c478bd9Sstevel@tonic-gate db_query*
1828*7c478bd9Sstevel@tonic-gate db_dictionary::translate_to_query(db_table_desc* tbl, int numattrs,
1829*7c478bd9Sstevel@tonic-gate 				nis_attr* attrlist)
1830*7c478bd9Sstevel@tonic-gate {
1831*7c478bd9Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_dictionary::translate_to_query");
1832*7c478bd9Sstevel@tonic-gate 	if (!initialized ||
1833*7c478bd9Sstevel@tonic-gate 		tbl->scheme == NULL || numattrs == 0 || attrlist == NULL) {
1834*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, NULL, "ru db_dictionary::translate_to_query");
1835*7c478bd9Sstevel@tonic-gate 		return (NULL);
1836*7c478bd9Sstevel@tonic-gate 	}
1837*7c478bd9Sstevel@tonic-gate 
1838*7c478bd9Sstevel@tonic-gate 	db_query *q = new db_query(tbl->scheme, numattrs, attrlist);
1839*7c478bd9Sstevel@tonic-gate 	if (q == NULL) {
1840*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, NULL,
1841*7c478bd9Sstevel@tonic-gate 			"db_dictionary::translate: could not allocate space");
1842*7c478bd9Sstevel@tonic-gate 		FATAL3("db_dictionary::translate: could not allocate space",
1843*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, NULL);
1844*7c478bd9Sstevel@tonic-gate 	}
1845*7c478bd9Sstevel@tonic-gate 
1846*7c478bd9Sstevel@tonic-gate 	if (q->size() == 0) {
1847*7c478bd9Sstevel@tonic-gate 		delete q;
1848*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, NULL, "ru db_dictionary::translate_to_query");
1849*7c478bd9Sstevel@tonic-gate 		return (NULL);
1850*7c478bd9Sstevel@tonic-gate 	}
1851*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, NULL, "ru db_dictionary::translate_to_query");
1852*7c478bd9Sstevel@tonic-gate 	return (q);
1853*7c478bd9Sstevel@tonic-gate }
1854*7c478bd9Sstevel@tonic-gate 
1855*7c478bd9Sstevel@tonic-gate static db_table_names gt_answer;
1856*7c478bd9Sstevel@tonic-gate static int gt_posn;
1857*7c478bd9Sstevel@tonic-gate 
1858*7c478bd9Sstevel@tonic-gate static db_status
1859*7c478bd9Sstevel@tonic-gate get_table_name(db_table_desc* tbl)
1860*7c478bd9Sstevel@tonic-gate {
1861*7c478bd9Sstevel@tonic-gate 	if (tbl)
1862*7c478bd9Sstevel@tonic-gate 		return (DB_BADTABLE);
1863*7c478bd9Sstevel@tonic-gate 
1864*7c478bd9Sstevel@tonic-gate 	if (gt_posn < gt_answer.db_table_names_len)
1865*7c478bd9Sstevel@tonic-gate 		gt_answer.db_table_names_val[gt_posn++] =
1866*7c478bd9Sstevel@tonic-gate 			strdup(tbl->table_name);
1867*7c478bd9Sstevel@tonic-gate 	else
1868*7c478bd9Sstevel@tonic-gate 		return (DB_BADTABLE);
1869*7c478bd9Sstevel@tonic-gate 
1870*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
1871*7c478bd9Sstevel@tonic-gate }
1872*7c478bd9Sstevel@tonic-gate 
1873*7c478bd9Sstevel@tonic-gate 
1874*7c478bd9Sstevel@tonic-gate /*
1875*7c478bd9Sstevel@tonic-gate  * Return the names of tables in this dictionary.
1876*7c478bd9Sstevel@tonic-gate  * XXX This routine is used only for testing only;
1877*7c478bd9Sstevel@tonic-gate  *	if to be used for real, need to free memory sensibly, or
1878*7c478bd9Sstevel@tonic-gate  *	caller of get_table_names should have freed them.
1879*7c478bd9Sstevel@tonic-gate  */
1880*7c478bd9Sstevel@tonic-gate db_table_names*
1881*7c478bd9Sstevel@tonic-gate db_dictionary::get_table_names()
1882*7c478bd9Sstevel@tonic-gate {
1883*7c478bd9Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_dictionary::get_table_names");
1884*7c478bd9Sstevel@tonic-gate 	gt_answer.db_table_names_len = dictionary->count;
1885*7c478bd9Sstevel@tonic-gate 	gt_answer.db_table_names_val = new db_table_namep[dictionary->count];
1886*7c478bd9Sstevel@tonic-gate 	gt_posn = 0;
1887*7c478bd9Sstevel@tonic-gate 	if ((gt_answer.db_table_names_val) == NULL) {
1888*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, NULL,
1889*7c478bd9Sstevel@tonic-gate 	"db_dictionary::get_table_names: could not allocate space for names");
1890*7c478bd9Sstevel@tonic-gate 		FATAL3(
1891*7c478bd9Sstevel@tonic-gate 	"db_dictionary::get_table_names: could not allocate space for names",
1892*7c478bd9Sstevel@tonic-gate 		DB_MEMORY_LIMIT, NULL);
1893*7c478bd9Sstevel@tonic-gate 	}
1894*7c478bd9Sstevel@tonic-gate 
1895*7c478bd9Sstevel@tonic-gate 	enumerate_dictionary(dictionary, &get_table_name);
1896*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, NULL, "ru db_dictionary::get_table_names");
1897*7c478bd9Sstevel@tonic-gate 	return (&gt_answer);
1898*7c478bd9Sstevel@tonic-gate }
1899*7c478bd9Sstevel@tonic-gate 
1900*7c478bd9Sstevel@tonic-gate static db_status
1901*7c478bd9Sstevel@tonic-gate db_checkpoint_aux(db_table_desc *current)
1902*7c478bd9Sstevel@tonic-gate {
1903*7c478bd9Sstevel@tonic-gate 	db *dbase;
1904*7c478bd9Sstevel@tonic-gate 	int status;
1905*7c478bd9Sstevel@tonic-gate 
1906*7c478bd9Sstevel@tonic-gate 	if (current == NULL)
1907*7c478bd9Sstevel@tonic-gate 		return (DB_BADTABLE);
1908*7c478bd9Sstevel@tonic-gate 
1909*7c478bd9Sstevel@tonic-gate 	if (current->database == NULL) {  /* need to load it in */
1910*7c478bd9Sstevel@tonic-gate 		dbase = new db(current->table_name);
1911*7c478bd9Sstevel@tonic-gate 		if (dbase == NULL) {
1912*7c478bd9Sstevel@tonic-gate 			FATAL3(
1913*7c478bd9Sstevel@tonic-gate 		    "db_dictionary::db_checkpoint: could not allocate space",
1914*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, DB_MEMORY_LIMIT);
1915*7c478bd9Sstevel@tonic-gate 		}
1916*7c478bd9Sstevel@tonic-gate 		if (dbase->load() == 0) {
1917*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
1918*7c478bd9Sstevel@tonic-gate 			"db_dictionary::db_checkpoint: could not load table %s",
1919*7c478bd9Sstevel@tonic-gate 							current->table_name);
1920*7c478bd9Sstevel@tonic-gate 			delete dbase;
1921*7c478bd9Sstevel@tonic-gate 			return (DB_BADTABLE);
1922*7c478bd9Sstevel@tonic-gate 		}
1923*7c478bd9Sstevel@tonic-gate 		status = dbase->checkpoint();
1924*7c478bd9Sstevel@tonic-gate 		delete dbase;  // unload
1925*7c478bd9Sstevel@tonic-gate 	} else
1926*7c478bd9Sstevel@tonic-gate 	    status = current->database->checkpoint();
1927*7c478bd9Sstevel@tonic-gate 
1928*7c478bd9Sstevel@tonic-gate 	if (status == 0)
1929*7c478bd9Sstevel@tonic-gate 		return (DB_STORAGE_LIMIT);
1930*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
1931*7c478bd9Sstevel@tonic-gate }
1932*7c478bd9Sstevel@tonic-gate 
1933*7c478bd9Sstevel@tonic-gate /* Like db_checkpoint_aux except only stops on LIMIT errors */
1934*7c478bd9Sstevel@tonic-gate static db_status
1935*7c478bd9Sstevel@tonic-gate db_checkpoint_aux_cont(db_table_desc *current)
1936*7c478bd9Sstevel@tonic-gate {
1937*7c478bd9Sstevel@tonic-gate 	db_status status = db_checkpoint_aux(current);
1938*7c478bd9Sstevel@tonic-gate 
1939*7c478bd9Sstevel@tonic-gate 	if (status == DB_STORAGE_LIMIT || status == DB_MEMORY_LIMIT)
1940*7c478bd9Sstevel@tonic-gate 		return (status);
1941*7c478bd9Sstevel@tonic-gate 	else
1942*7c478bd9Sstevel@tonic-gate 		return (DB_SUCCESS);
1943*7c478bd9Sstevel@tonic-gate }
1944*7c478bd9Sstevel@tonic-gate 
1945*7c478bd9Sstevel@tonic-gate db_status
1946*7c478bd9Sstevel@tonic-gate db_dictionary::db_checkpoint(char *tab)
1947*7c478bd9Sstevel@tonic-gate {
1948*7c478bd9Sstevel@tonic-gate 	db_table_desc *tbl;
1949*7c478bd9Sstevel@tonic-gate 	db_status	ret;
1950*7c478bd9Sstevel@tonic-gate 	bool_t		init;
1951*7c478bd9Sstevel@tonic-gate 
1952*7c478bd9Sstevel@tonic-gate 	READLOCK(this, DB_LOCK_ERROR, "r db_dictionary::db_checkpoint");
1953*7c478bd9Sstevel@tonic-gate 	init = initialized;
1954*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, DB_LOCK_ERROR, "ru db_dictionary::db_checkpoint");
1955*7c478bd9Sstevel@tonic-gate 	if (!init)
1956*7c478bd9Sstevel@tonic-gate 		return (DB_BADDICTIONARY);
1957*7c478bd9Sstevel@tonic-gate 
1958*7c478bd9Sstevel@tonic-gate 	checkpoint();	// checkpoint dictionary first
1959*7c478bd9Sstevel@tonic-gate 
1960*7c478bd9Sstevel@tonic-gate 	READLOCK(this, DB_LOCK_ERROR, "r db_dictionary::db_checkpoint");
1961*7c478bd9Sstevel@tonic-gate 
1962*7c478bd9Sstevel@tonic-gate 	if (tab == NULL) {
1963*7c478bd9Sstevel@tonic-gate 	    ret = enumerate_dictionary(dictionary, &db_checkpoint_aux_cont);
1964*7c478bd9Sstevel@tonic-gate 	    READUNLOCK(this, ret, "ru db_dictionary::db_checkpoint");
1965*7c478bd9Sstevel@tonic-gate 	    return (ret);
1966*7c478bd9Sstevel@tonic-gate 	}
1967*7c478bd9Sstevel@tonic-gate 
1968*7c478bd9Sstevel@tonic-gate 	if ((tbl = find_table_desc(tab)) == NULL) {
1969*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, DB_LOCK_ERROR,
1970*7c478bd9Sstevel@tonic-gate 				"ru db_dictionary::db_checkpoint");
1971*7c478bd9Sstevel@tonic-gate 	    return (DB_BADTABLE);
1972*7c478bd9Sstevel@tonic-gate 	}
1973*7c478bd9Sstevel@tonic-gate 
1974*7c478bd9Sstevel@tonic-gate 	ret = db_checkpoint_aux(tbl);
1975*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, ret, "ru db_dictionary::db_checkpoint");
1976*7c478bd9Sstevel@tonic-gate 	return (ret);
1977*7c478bd9Sstevel@tonic-gate }
1978*7c478bd9Sstevel@tonic-gate 
1979*7c478bd9Sstevel@tonic-gate /* *********************** db_standby **************************** */
1980*7c478bd9Sstevel@tonic-gate /* Deal with list of tables that need to be 'closed' */
1981*7c478bd9Sstevel@tonic-gate 
1982*7c478bd9Sstevel@tonic-gate #define	OPENED_DBS_CHUNK	12
1983*7c478bd9Sstevel@tonic-gate static db	**db_standby_list;
1984*7c478bd9Sstevel@tonic-gate static uint_t	db_standby_size = 0;
1985*7c478bd9Sstevel@tonic-gate static uint_t	db_standby_count = 0;
1986*7c478bd9Sstevel@tonic-gate DECLMUTEXLOCK(db_standby_list);
1987*7c478bd9Sstevel@tonic-gate 
1988*7c478bd9Sstevel@tonic-gate /*
1989*7c478bd9Sstevel@tonic-gate  * Returns 1 if all databases on the list could be closed, 0
1990*7c478bd9Sstevel@tonic-gate  * otherwise.
1991*7c478bd9Sstevel@tonic-gate  */
1992*7c478bd9Sstevel@tonic-gate static int
1993*7c478bd9Sstevel@tonic-gate close_standby_list()
1994*7c478bd9Sstevel@tonic-gate {
1995*7c478bd9Sstevel@tonic-gate 	db	*database;
1996*7c478bd9Sstevel@tonic-gate 	int	i, ret;
1997*7c478bd9Sstevel@tonic-gate 	char	*myself = "close_standby_list";
1998*7c478bd9Sstevel@tonic-gate 
1999*7c478bd9Sstevel@tonic-gate 	MUTEXLOCK(db_standby_list, "close_standby_list");
2000*7c478bd9Sstevel@tonic-gate 
2001*7c478bd9Sstevel@tonic-gate 	if (db_standby_count == 0) {
2002*7c478bd9Sstevel@tonic-gate 		MUTEXUNLOCK(db_standby_list, "close_standby_list");
2003*7c478bd9Sstevel@tonic-gate 		return (1);
2004*7c478bd9Sstevel@tonic-gate 	}
2005*7c478bd9Sstevel@tonic-gate 
2006*7c478bd9Sstevel@tonic-gate 	for (i = 0, ret = 0; i < db_standby_size; i++) {
2007*7c478bd9Sstevel@tonic-gate 		if ((database = db_standby_list[i])) {
2008*7c478bd9Sstevel@tonic-gate 			/*
2009*7c478bd9Sstevel@tonic-gate 			 * In order to avoid a potential dead-lock, we
2010*7c478bd9Sstevel@tonic-gate 			 * check to see if close_log() would be able to
2011*7c478bd9Sstevel@tonic-gate 			 * lock the db; if not, just skip the db.
2012*7c478bd9Sstevel@tonic-gate 			 */
2013*7c478bd9Sstevel@tonic-gate 			int	lockok;
2014*7c478bd9Sstevel@tonic-gate 
2015*7c478bd9Sstevel@tonic-gate 			TRYWRITELOCK(database, lockok,
2016*7c478bd9Sstevel@tonic-gate 				"try w db_dictionary::close_standby_list");
2017*7c478bd9Sstevel@tonic-gate 
2018*7c478bd9Sstevel@tonic-gate 			if (lockok == 0) {
2019*7c478bd9Sstevel@tonic-gate 				database->close_log(1);
2020*7c478bd9Sstevel@tonic-gate 				db_standby_list[i] = (db*)NULL;
2021*7c478bd9Sstevel@tonic-gate 				--db_standby_count;
2022*7c478bd9Sstevel@tonic-gate 				WRITEUNLOCK(database, db_standby_count == 0,
2023*7c478bd9Sstevel@tonic-gate 					"db_dictionary::close_standby_list");
2024*7c478bd9Sstevel@tonic-gate 				if (db_standby_count == 0) {
2025*7c478bd9Sstevel@tonic-gate 					ret = 1;
2026*7c478bd9Sstevel@tonic-gate 					break;
2027*7c478bd9Sstevel@tonic-gate 				}
2028*7c478bd9Sstevel@tonic-gate 			} else if (lockok != EBUSY) {
2029*7c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_INFO,
2030*7c478bd9Sstevel@tonic-gate 					"%s: try-lock error %d",
2031*7c478bd9Sstevel@tonic-gate 					myself, lockok);
2032*7c478bd9Sstevel@tonic-gate 			} /* else it's EBUSY; skip to the next one */
2033*7c478bd9Sstevel@tonic-gate 		}
2034*7c478bd9Sstevel@tonic-gate 	}
2035*7c478bd9Sstevel@tonic-gate 
2036*7c478bd9Sstevel@tonic-gate 	MUTEXUNLOCK(db_standby_list, "close_standby_list");
2037*7c478bd9Sstevel@tonic-gate 
2038*7c478bd9Sstevel@tonic-gate 	return (ret);
2039*7c478bd9Sstevel@tonic-gate }
2040*7c478bd9Sstevel@tonic-gate 
2041*7c478bd9Sstevel@tonic-gate /*
2042*7c478bd9Sstevel@tonic-gate  * Add given database to list of databases that have been opened for updates.
2043*7c478bd9Sstevel@tonic-gate  * If size of list exceeds maximum, close opened databases first.
2044*7c478bd9Sstevel@tonic-gate  */
2045*7c478bd9Sstevel@tonic-gate 
2046*7c478bd9Sstevel@tonic-gate int
2047*7c478bd9Sstevel@tonic-gate add_to_standby_list(db* database)
2048*7c478bd9Sstevel@tonic-gate {
2049*7c478bd9Sstevel@tonic-gate 	int	i;
2050*7c478bd9Sstevel@tonic-gate 	char	*myself = "add_to_standby_list";
2051*7c478bd9Sstevel@tonic-gate 
2052*7c478bd9Sstevel@tonic-gate 	MUTEXLOCK(db_standby_list, "add_to_standby_list");
2053*7c478bd9Sstevel@tonic-gate 
2054*7c478bd9Sstevel@tonic-gate 	if (database == 0) {
2055*7c478bd9Sstevel@tonic-gate 		MUTEXUNLOCK(db_standby_list, "add_to_standby_list");
2056*7c478bd9Sstevel@tonic-gate 		return (1);
2057*7c478bd9Sstevel@tonic-gate 	}
2058*7c478bd9Sstevel@tonic-gate 
2059*7c478bd9Sstevel@tonic-gate 	/* Try to keep the list below OPENED_DBS_CHUNK */
2060*7c478bd9Sstevel@tonic-gate 	if (db_standby_count >= OPENED_DBS_CHUNK) {
2061*7c478bd9Sstevel@tonic-gate 		MUTEXUNLOCK(db_standby_list, "add_to_standby_list");
2062*7c478bd9Sstevel@tonic-gate 		close_standby_list();
2063*7c478bd9Sstevel@tonic-gate 		MUTEXLOCK(db_standby_list, "add_to_standby_list");
2064*7c478bd9Sstevel@tonic-gate 	}
2065*7c478bd9Sstevel@tonic-gate 
2066*7c478bd9Sstevel@tonic-gate 	if (db_standby_count >= db_standby_size) {
2067*7c478bd9Sstevel@tonic-gate 		db	**ndsl = (db **)realloc(db_standby_list,
2068*7c478bd9Sstevel@tonic-gate 					(db_standby_size+OPENED_DBS_CHUNK) *
2069*7c478bd9Sstevel@tonic-gate 						sizeof (ndsl[0]));
2070*7c478bd9Sstevel@tonic-gate 
2071*7c478bd9Sstevel@tonic-gate 		if (ndsl == 0) {
2072*7c478bd9Sstevel@tonic-gate 			MUTEXUNLOCK(db_standby_list, "add_to_standby_list");
2073*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOMEM, LOG_ERR,
2074*7c478bd9Sstevel@tonic-gate 				"%s: realloc(%d) => NULL",
2075*7c478bd9Sstevel@tonic-gate 				myself, (db_standby_size+OPENED_DBS_CHUNK) *
2076*7c478bd9Sstevel@tonic-gate 				sizeof (ndsl[0]));
2077*7c478bd9Sstevel@tonic-gate 			return (0);
2078*7c478bd9Sstevel@tonic-gate 		}
2079*7c478bd9Sstevel@tonic-gate 
2080*7c478bd9Sstevel@tonic-gate 		db_standby_list = ndsl;
2081*7c478bd9Sstevel@tonic-gate 
2082*7c478bd9Sstevel@tonic-gate 		for (i = db_standby_size; i < db_standby_size+OPENED_DBS_CHUNK;
2083*7c478bd9Sstevel@tonic-gate 				i++)
2084*7c478bd9Sstevel@tonic-gate 			db_standby_list[i] = 0;
2085*7c478bd9Sstevel@tonic-gate 
2086*7c478bd9Sstevel@tonic-gate 		db_standby_size += OPENED_DBS_CHUNK;
2087*7c478bd9Sstevel@tonic-gate 	}
2088*7c478bd9Sstevel@tonic-gate 
2089*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < db_standby_size; i++) {
2090*7c478bd9Sstevel@tonic-gate 		if (db_standby_list[i] == (db*)NULL) {
2091*7c478bd9Sstevel@tonic-gate 			db_standby_list[i] = database;
2092*7c478bd9Sstevel@tonic-gate 			++db_standby_count;
2093*7c478bd9Sstevel@tonic-gate 			MUTEXUNLOCK(db_standby_list, "add_to_standby_list");
2094*7c478bd9Sstevel@tonic-gate 			return (1);
2095*7c478bd9Sstevel@tonic-gate 		}
2096*7c478bd9Sstevel@tonic-gate 	}
2097*7c478bd9Sstevel@tonic-gate 
2098*7c478bd9Sstevel@tonic-gate 	MUTEXUNLOCK(db_standby_list, "add_to_standby_list");
2099*7c478bd9Sstevel@tonic-gate 
2100*7c478bd9Sstevel@tonic-gate 	return (0);
2101*7c478bd9Sstevel@tonic-gate }
2102*7c478bd9Sstevel@tonic-gate 
2103*7c478bd9Sstevel@tonic-gate int
2104*7c478bd9Sstevel@tonic-gate remove_from_standby_list(db* database)
2105*7c478bd9Sstevel@tonic-gate {
2106*7c478bd9Sstevel@tonic-gate 	int i;
2107*7c478bd9Sstevel@tonic-gate 
2108*7c478bd9Sstevel@tonic-gate 	MUTEXLOCK(db_standby_list, "remove_from_standby_list");
2109*7c478bd9Sstevel@tonic-gate 
2110*7c478bd9Sstevel@tonic-gate 	if (database == 0) {
2111*7c478bd9Sstevel@tonic-gate 		MUTEXUNLOCK(db_standby_list, "remove_from_standby_list");
2112*7c478bd9Sstevel@tonic-gate 		return (1);
2113*7c478bd9Sstevel@tonic-gate 	}
2114*7c478bd9Sstevel@tonic-gate 
2115*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < db_standby_size; i++) {
2116*7c478bd9Sstevel@tonic-gate 		if ((database == db_standby_list[i])) {
2117*7c478bd9Sstevel@tonic-gate 			db_standby_list[i] = (db*)NULL;
2118*7c478bd9Sstevel@tonic-gate 			--db_standby_count;
2119*7c478bd9Sstevel@tonic-gate 			MUTEXUNLOCK(db_standby_list,
2120*7c478bd9Sstevel@tonic-gate 					"remove_from_standby_list");
2121*7c478bd9Sstevel@tonic-gate 			return (1);
2122*7c478bd9Sstevel@tonic-gate 		}
2123*7c478bd9Sstevel@tonic-gate 	}
2124*7c478bd9Sstevel@tonic-gate 
2125*7c478bd9Sstevel@tonic-gate 	MUTEXUNLOCK(db_standby_list, "remove_from_standby_list");
2126*7c478bd9Sstevel@tonic-gate 
2127*7c478bd9Sstevel@tonic-gate 	return (0);
2128*7c478bd9Sstevel@tonic-gate }
2129*7c478bd9Sstevel@tonic-gate 
2130*7c478bd9Sstevel@tonic-gate /* Release space for copied dictionary */
2131*7c478bd9Sstevel@tonic-gate static void
2132*7c478bd9Sstevel@tonic-gate db_release_dictionary(db_dict_desc_p d) {
2133*7c478bd9Sstevel@tonic-gate 
2134*7c478bd9Sstevel@tonic-gate 	int	i;
2135*7c478bd9Sstevel@tonic-gate 
2136*7c478bd9Sstevel@tonic-gate 	if (d != NULL) {
2137*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < d->tables.tables_len; i++) {
2138*7c478bd9Sstevel@tonic-gate 			db_table_desc_p	n, t = d->tables.tables_val[i];
2139*7c478bd9Sstevel@tonic-gate 			while (t != NULL) {
2140*7c478bd9Sstevel@tonic-gate 				n = t->next;
2141*7c478bd9Sstevel@tonic-gate 				delete_table_desc(t);
2142*7c478bd9Sstevel@tonic-gate 				t = n;
2143*7c478bd9Sstevel@tonic-gate 			}
2144*7c478bd9Sstevel@tonic-gate 		}
2145*7c478bd9Sstevel@tonic-gate 		delete d;
2146*7c478bd9Sstevel@tonic-gate 	}
2147*7c478bd9Sstevel@tonic-gate 
2148*7c478bd9Sstevel@tonic-gate 	return;
2149*7c478bd9Sstevel@tonic-gate }
2150*7c478bd9Sstevel@tonic-gate 
2151*7c478bd9Sstevel@tonic-gate /*
2152*7c478bd9Sstevel@tonic-gate  * Make a copy of the dictionary
2153*7c478bd9Sstevel@tonic-gate  */
2154*7c478bd9Sstevel@tonic-gate db_dict_desc_p
2155*7c478bd9Sstevel@tonic-gate db_dictionary::db_copy_dictionary(void) {
2156*7c478bd9Sstevel@tonic-gate 
2157*7c478bd9Sstevel@tonic-gate 	db_dict_desc_p	tmp;
2158*7c478bd9Sstevel@tonic-gate 	int		i, ok = 1, count = 0;
2159*7c478bd9Sstevel@tonic-gate 
2160*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, NULL, "db_dictionary::db_copy_dictionary w");
2161*7c478bd9Sstevel@tonic-gate 
2162*7c478bd9Sstevel@tonic-gate 	if (dictionary == NULL) {
2163*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, NULL,
2164*7c478bd9Sstevel@tonic-gate 			"db_dictionary::db_copy_dictionary wu");
2165*7c478bd9Sstevel@tonic-gate 		return (NULL);
2166*7c478bd9Sstevel@tonic-gate 	}
2167*7c478bd9Sstevel@tonic-gate 
2168*7c478bd9Sstevel@tonic-gate 	tmp = new db_dict_desc;
2169*7c478bd9Sstevel@tonic-gate 	if (tmp == NULL) {
2170*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, NULL,
2171*7c478bd9Sstevel@tonic-gate 			"db_dictionary::db_copy_dictionary wu: no memory");
2172*7c478bd9Sstevel@tonic-gate 		return (NULL);
2173*7c478bd9Sstevel@tonic-gate 	}
2174*7c478bd9Sstevel@tonic-gate 
2175*7c478bd9Sstevel@tonic-gate 	tmp->tables.tables_val = (db_table_desc_p *)calloc(
2176*7c478bd9Sstevel@tonic-gate 						tmp->tables.tables_len,
2177*7c478bd9Sstevel@tonic-gate 					sizeof (tmp->tables.tables_val[0]));
2178*7c478bd9Sstevel@tonic-gate 	if (tmp->tables.tables_val == NULL) {
2179*7c478bd9Sstevel@tonic-gate 		delete tmp;
2180*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, NULL,
2181*7c478bd9Sstevel@tonic-gate 			"db_dictionary::db_copy_dictionary wu: no memory");
2182*7c478bd9Sstevel@tonic-gate 		return (NULL);
2183*7c478bd9Sstevel@tonic-gate 	}
2184*7c478bd9Sstevel@tonic-gate 
2185*7c478bd9Sstevel@tonic-gate 	tmp->impl_vers = dictionary->impl_vers;
2186*7c478bd9Sstevel@tonic-gate 	tmp->tables.tables_len = 0;
2187*7c478bd9Sstevel@tonic-gate 	tmp->count = 0;
2188*7c478bd9Sstevel@tonic-gate 
2189*7c478bd9Sstevel@tonic-gate 	/* For each table ... */
2190*7c478bd9Sstevel@tonic-gate 	for (i = 0; ok && i < dictionary->tables.tables_len; i++) {
2191*7c478bd9Sstevel@tonic-gate 		db_table_desc_p	tbl = NULL,
2192*7c478bd9Sstevel@tonic-gate 				t = dictionary->tables.tables_val[i];
2193*7c478bd9Sstevel@tonic-gate 		/* ... and each bucket in the chain ... */
2194*7c478bd9Sstevel@tonic-gate 		while (ok && t != NULL) {
2195*7c478bd9Sstevel@tonic-gate 			db_table_desc_p		n, savenext = t->next;
2196*7c478bd9Sstevel@tonic-gate 			t->next = NULL;
2197*7c478bd9Sstevel@tonic-gate 			if (db_clone_bucket(t, &n)) {
2198*7c478bd9Sstevel@tonic-gate 				if (tbl != NULL) {
2199*7c478bd9Sstevel@tonic-gate 					tbl->next = n;
2200*7c478bd9Sstevel@tonic-gate 				} else {
2201*7c478bd9Sstevel@tonic-gate 					tmp->tables.tables_val[i] = n;
2202*7c478bd9Sstevel@tonic-gate 				}
2203*7c478bd9Sstevel@tonic-gate 				tbl = n;
2204*7c478bd9Sstevel@tonic-gate 				tmp->count++;
2205*7c478bd9Sstevel@tonic-gate 			} else {
2206*7c478bd9Sstevel@tonic-gate 				ok = 0;
2207*7c478bd9Sstevel@tonic-gate 			}
2208*7c478bd9Sstevel@tonic-gate 			t->next = savenext;
2209*7c478bd9Sstevel@tonic-gate 		}
2210*7c478bd9Sstevel@tonic-gate 		tmp->tables.tables_len++;
2211*7c478bd9Sstevel@tonic-gate 	}
2212*7c478bd9Sstevel@tonic-gate 
2213*7c478bd9Sstevel@tonic-gate 	if (ok) {
2214*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_LDAP_DEBUG
2215*7c478bd9Sstevel@tonic-gate 		if ((tmp->tables.tables_len !=
2216*7c478bd9Sstevel@tonic-gate 				dictionary->tables.tables_len) ||
2217*7c478bd9Sstevel@tonic-gate 			(tmp->count != dictionary->count))
2218*7c478bd9Sstevel@tonic-gate 			abort();
2219*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_LDAP_DEBUG */
2220*7c478bd9Sstevel@tonic-gate 	} else {
2221*7c478bd9Sstevel@tonic-gate 		db_release_dictionary(tmp);
2222*7c478bd9Sstevel@tonic-gate 		tmp = NULL;
2223*7c478bd9Sstevel@tonic-gate 	}
2224*7c478bd9Sstevel@tonic-gate 
2225*7c478bd9Sstevel@tonic-gate 	return (tmp);
2226*7c478bd9Sstevel@tonic-gate }
2227*7c478bd9Sstevel@tonic-gate 
2228*7c478bd9Sstevel@tonic-gate /*
2229*7c478bd9Sstevel@tonic-gate  * Set deferred commit mode. To do this, we make a copy of the table
2230*7c478bd9Sstevel@tonic-gate  * (structures and data), and put that on the deferred dictionary list.
2231*7c478bd9Sstevel@tonic-gate  * This list is used for lookups during a resync, so clients continue
2232*7c478bd9Sstevel@tonic-gate  * to see the pre-resync data. Meanwhile, any changes (including table
2233*7c478bd9Sstevel@tonic-gate  * deletes) are done to the (temporarily hidden to clients) table in
2234*7c478bd9Sstevel@tonic-gate  * the normal dictionary.
2235*7c478bd9Sstevel@tonic-gate  */
2236*7c478bd9Sstevel@tonic-gate db_status
2237*7c478bd9Sstevel@tonic-gate db_dictionary::defer(char *table) {
2238*7c478bd9Sstevel@tonic-gate 	db_status	ret = DB_SUCCESS;
2239*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::defer");
2240*7c478bd9Sstevel@tonic-gate 	db_table_desc	*tbl = find_table_desc(table);
2241*7c478bd9Sstevel@tonic-gate 	int		res;
2242*7c478bd9Sstevel@tonic-gate 	char		*myself = "db_dictionary::defer";
2243*7c478bd9Sstevel@tonic-gate 
2244*7c478bd9Sstevel@tonic-gate 	if (tbl != NULL) {
2245*7c478bd9Sstevel@tonic-gate 		db_table_desc	*clone, *savenext = tbl->next;
2246*7c478bd9Sstevel@tonic-gate 		/*
2247*7c478bd9Sstevel@tonic-gate 		 * Only want to clone one db_table_desc, so temporarily
2248*7c478bd9Sstevel@tonic-gate 		 * unlink the tail.
2249*7c478bd9Sstevel@tonic-gate 		 */
2250*7c478bd9Sstevel@tonic-gate 		tbl->next = NULL;
2251*7c478bd9Sstevel@tonic-gate 		res = db_clone_bucket(tbl, &clone);
2252*7c478bd9Sstevel@tonic-gate 		/* Restore link to tail */
2253*7c478bd9Sstevel@tonic-gate 		tbl->next = savenext;
2254*7c478bd9Sstevel@tonic-gate 		if (res == 1) {
2255*7c478bd9Sstevel@tonic-gate 			db_status	stat;
2256*7c478bd9Sstevel@tonic-gate 			if (deferred.dictionary == NULL) {
2257*7c478bd9Sstevel@tonic-gate 				deferred.dictionary = new db_dict_desc;
2258*7c478bd9Sstevel@tonic-gate 				if (deferred.dictionary == NULL) {
2259*7c478bd9Sstevel@tonic-gate 					WRITEUNLOCK(this, DB_MEMORY_LIMIT,
2260*7c478bd9Sstevel@tonic-gate 						"wu db_dictionary::defer");
2261*7c478bd9Sstevel@tonic-gate 					return (DB_MEMORY_LIMIT);
2262*7c478bd9Sstevel@tonic-gate 				}
2263*7c478bd9Sstevel@tonic-gate 				deferred.dictionary->tables.tables_len = 0;
2264*7c478bd9Sstevel@tonic-gate 				deferred.dictionary->tables.tables_val = NULL;
2265*7c478bd9Sstevel@tonic-gate 				deferred.dictionary->count = 0;
2266*7c478bd9Sstevel@tonic-gate 				deferred.dictionary->impl_vers =
2267*7c478bd9Sstevel@tonic-gate 							DB_CURRENT_VERSION;
2268*7c478bd9Sstevel@tonic-gate 			}
2269*7c478bd9Sstevel@tonic-gate 			ret = DB_SUCCESS;
2270*7c478bd9Sstevel@tonic-gate 			/* Initialize and load the database for the clone */
2271*7c478bd9Sstevel@tonic-gate 			if (clone->database == 0) {
2272*7c478bd9Sstevel@tonic-gate 				clone->database = new db(table);
2273*7c478bd9Sstevel@tonic-gate 				if (clone->database != 0) {
2274*7c478bd9Sstevel@tonic-gate 					if (clone->database->load()) {
2275*7c478bd9Sstevel@tonic-gate 						logmsg(MSG_NOTIMECHECK,
2276*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_LDAP_DEBUG
2277*7c478bd9Sstevel@tonic-gate 							LOG_WARNING,
2278*7c478bd9Sstevel@tonic-gate #else
2279*7c478bd9Sstevel@tonic-gate 							LOG_INFO,
2280*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_LDAP_DEBUG */
2281*7c478bd9Sstevel@tonic-gate 					"%s: Clone DB for \"%s\" loaded",
2282*7c478bd9Sstevel@tonic-gate 							myself, NIL(table));
2283*7c478bd9Sstevel@tonic-gate 					} else {
2284*7c478bd9Sstevel@tonic-gate 						logmsg(MSG_NOTIMECHECK, LOG_ERR,
2285*7c478bd9Sstevel@tonic-gate 					"%s: Error loading clone DB for \"%s\"",
2286*7c478bd9Sstevel@tonic-gate 							myself, NIL(table));
2287*7c478bd9Sstevel@tonic-gate 						delete clone->database;
2288*7c478bd9Sstevel@tonic-gate 						clone->database = 0;
2289*7c478bd9Sstevel@tonic-gate 						ret = DB_INTERNAL_ERROR;
2290*7c478bd9Sstevel@tonic-gate 					}
2291*7c478bd9Sstevel@tonic-gate 				} else {
2292*7c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_ERR,
2293*7c478bd9Sstevel@tonic-gate 					"%s: Unable to clone DB for \"%s\"",
2294*7c478bd9Sstevel@tonic-gate 						myself, NIL(table));
2295*7c478bd9Sstevel@tonic-gate 					ret = DB_MEMORY_LIMIT;
2296*7c478bd9Sstevel@tonic-gate 				}
2297*7c478bd9Sstevel@tonic-gate 			}
2298*7c478bd9Sstevel@tonic-gate 			if (clone->database != 0) {
2299*7c478bd9Sstevel@tonic-gate 				clone->database->markDeferred();
2300*7c478bd9Sstevel@tonic-gate 				stat = add_to_dictionary(deferred.dictionary,
2301*7c478bd9Sstevel@tonic-gate 							clone);
2302*7c478bd9Sstevel@tonic-gate 				ret = stat;
2303*7c478bd9Sstevel@tonic-gate 				if (stat != DB_SUCCESS) {
2304*7c478bd9Sstevel@tonic-gate 					delete clone->database;
2305*7c478bd9Sstevel@tonic-gate 					clone->database = 0;
2306*7c478bd9Sstevel@tonic-gate 					delete clone;
2307*7c478bd9Sstevel@tonic-gate 					if (stat == DB_NOTUNIQUE) {
2308*7c478bd9Sstevel@tonic-gate 						/* Already deferred */
2309*7c478bd9Sstevel@tonic-gate 						ret = DB_SUCCESS;
2310*7c478bd9Sstevel@tonic-gate 					}
2311*7c478bd9Sstevel@tonic-gate 				}
2312*7c478bd9Sstevel@tonic-gate 			} else {
2313*7c478bd9Sstevel@tonic-gate 				delete clone;
2314*7c478bd9Sstevel@tonic-gate 				/* Return value already set above */
2315*7c478bd9Sstevel@tonic-gate 			}
2316*7c478bd9Sstevel@tonic-gate 		} else {
2317*7c478bd9Sstevel@tonic-gate 			ret = DB_INTERNAL_ERROR;
2318*7c478bd9Sstevel@tonic-gate 		}
2319*7c478bd9Sstevel@tonic-gate 	} else {
2320*7c478bd9Sstevel@tonic-gate 		ret = DB_NOTFOUND;
2321*7c478bd9Sstevel@tonic-gate 	}
2322*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, ret, "wu db_dictionary::defer");
2323*7c478bd9Sstevel@tonic-gate 	return (ret);
2324*7c478bd9Sstevel@tonic-gate }
2325*7c478bd9Sstevel@tonic-gate 
2326*7c478bd9Sstevel@tonic-gate /*
2327*7c478bd9Sstevel@tonic-gate  * Unset deferred commit mode and roll back changes; doesn't recover the
2328*7c478bd9Sstevel@tonic-gate  * disk data, but that's OK, since we only want to be able to continue
2329*7c478bd9Sstevel@tonic-gate  * serving the table until we can try a full dump again.
2330*7c478bd9Sstevel@tonic-gate  *
2331*7c478bd9Sstevel@tonic-gate  * The rollback is done by removing (and deleting) the updated table from
2332*7c478bd9Sstevel@tonic-gate  * the dictionary, and then moving the saved table from the deferred
2333*7c478bd9Sstevel@tonic-gate  * dictionary list to the actual one.
2334*7c478bd9Sstevel@tonic-gate  */
2335*7c478bd9Sstevel@tonic-gate db_status
2336*7c478bd9Sstevel@tonic-gate db_dictionary::rollback(char *table) {
2337*7c478bd9Sstevel@tonic-gate 	db_status	ret = DB_SUCCESS;
2338*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::rollback");
2339*7c478bd9Sstevel@tonic-gate 	db_table_desc	*old = search_dictionary(deferred.dictionary, table);
2340*7c478bd9Sstevel@tonic-gate 	db_table_desc	*upd = search_dictionary(dictionary, table);
2341*7c478bd9Sstevel@tonic-gate 
2342*7c478bd9Sstevel@tonic-gate 	if (old == NULL) {
2343*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_NOTFOUND, "wu db_dictionary::rollback");
2344*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
2345*7c478bd9Sstevel@tonic-gate 	}
2346*7c478bd9Sstevel@tonic-gate 
2347*7c478bd9Sstevel@tonic-gate 	/*
2348*7c478bd9Sstevel@tonic-gate 	 * Remove old incarnation from deferred dictionary. We already hold
2349*7c478bd9Sstevel@tonic-gate 	 * a pointer ('old') to it, so don't delete.
2350*7c478bd9Sstevel@tonic-gate 	 */
2351*7c478bd9Sstevel@tonic-gate 	ret = remove_from_dictionary(deferred.dictionary, table, FALSE);
2352*7c478bd9Sstevel@tonic-gate 	if (ret != DB_SUCCESS) {
2353*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_LDAP_DEBUG
2354*7c478bd9Sstevel@tonic-gate 		abort();
2355*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_LDAP_DEBUG */
2356*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, ret, "wu db_dictionary::rollback");
2357*7c478bd9Sstevel@tonic-gate 		return (ret);
2358*7c478bd9Sstevel@tonic-gate 	}
2359*7c478bd9Sstevel@tonic-gate 
2360*7c478bd9Sstevel@tonic-gate 	if (old->database != 0)
2361*7c478bd9Sstevel@tonic-gate 		old->database->unmarkDeferred();
2362*7c478bd9Sstevel@tonic-gate 
2363*7c478bd9Sstevel@tonic-gate 	/*
2364*7c478bd9Sstevel@tonic-gate 	 * Remove updated incarnation from dictionary. If 'upd' is NULL,
2365*7c478bd9Sstevel@tonic-gate 	 * the table has been removed while we were in deferred mode, and
2366*7c478bd9Sstevel@tonic-gate 	 * that's OK; we just need to retain the old incarnation.
2367*7c478bd9Sstevel@tonic-gate 	 */
2368*7c478bd9Sstevel@tonic-gate 	if (upd != NULL) {
2369*7c478bd9Sstevel@tonic-gate 		ret = remove_from_dictionary(dictionary, table, FALSE);
2370*7c478bd9Sstevel@tonic-gate 		if (ret != DB_SUCCESS) {
2371*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_LDAP_DEBUG
2372*7c478bd9Sstevel@tonic-gate 			abort();
2373*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_LDAP_DEBUG */
2374*7c478bd9Sstevel@tonic-gate 			/*
2375*7c478bd9Sstevel@tonic-gate 			 * Cut our losses; delete old incarnation, and leave
2376*7c478bd9Sstevel@tonic-gate 			 * updated one in place.
2377*7c478bd9Sstevel@tonic-gate 			 */
2378*7c478bd9Sstevel@tonic-gate 			delete_table_desc(old);
2379*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, ret, "wu db_dictionary::rollback");
2380*7c478bd9Sstevel@tonic-gate 			return (ret);
2381*7c478bd9Sstevel@tonic-gate 		}
2382*7c478bd9Sstevel@tonic-gate 		/* Throw away updates */
2383*7c478bd9Sstevel@tonic-gate 		delete_table_desc(upd);
2384*7c478bd9Sstevel@tonic-gate 	}
2385*7c478bd9Sstevel@tonic-gate 
2386*7c478bd9Sstevel@tonic-gate 	/* (Re-)insert old incarnation in the dictionary */
2387*7c478bd9Sstevel@tonic-gate 	ret = add_to_dictionary(dictionary, old);
2388*7c478bd9Sstevel@tonic-gate 	if (ret != DB_SUCCESS) {
2389*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_LDAP_DEBUG
2390*7c478bd9Sstevel@tonic-gate 		abort();
2391*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_LDAP_DEBUG */
2392*7c478bd9Sstevel@tonic-gate 		/* At least avoid memory leak */
2393*7c478bd9Sstevel@tonic-gate 		delete_table_desc(old);
2394*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
2395*7c478bd9Sstevel@tonic-gate 	"db_dictionary::rollback: rollback error %d for \"%s\"", ret, table);
2396*7c478bd9Sstevel@tonic-gate 	}
2397*7c478bd9Sstevel@tonic-gate 
2398*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, ret, "wu db_dictionary::rollback");
2399*7c478bd9Sstevel@tonic-gate 	return (ret);
2400*7c478bd9Sstevel@tonic-gate }
2401*7c478bd9Sstevel@tonic-gate 
2402*7c478bd9Sstevel@tonic-gate /*
2403*7c478bd9Sstevel@tonic-gate  * Commit changes. Done by simply removing and deleting the pre-resync
2404*7c478bd9Sstevel@tonic-gate  * data from the deferred dictionary.
2405*7c478bd9Sstevel@tonic-gate  */
2406*7c478bd9Sstevel@tonic-gate db_status
2407*7c478bd9Sstevel@tonic-gate db_dictionary::commit(char *table) {
2408*7c478bd9Sstevel@tonic-gate 	db_status	ret = DB_SUCCESS;
2409*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_dictionary::commit");
2410*7c478bd9Sstevel@tonic-gate 	db_table_desc	*old = search_dictionary(deferred.dictionary, table);
2411*7c478bd9Sstevel@tonic-gate 
2412*7c478bd9Sstevel@tonic-gate 	if (old == NULL) {
2413*7c478bd9Sstevel@tonic-gate 		/* Fine (we hope); nothing to do */
2414*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, ret, "wu db_dictionary::commit");
2415*7c478bd9Sstevel@tonic-gate 		return (DB_SUCCESS);
2416*7c478bd9Sstevel@tonic-gate 	}
2417*7c478bd9Sstevel@tonic-gate 
2418*7c478bd9Sstevel@tonic-gate 	ret = remove_from_dictionary(deferred.dictionary, table, FALSE);
2419*7c478bd9Sstevel@tonic-gate 	if (ret == DB_SUCCESS)
2420*7c478bd9Sstevel@tonic-gate 		delete_table_desc(old);
2421*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_LDAP_DEBUG
2422*7c478bd9Sstevel@tonic-gate 	else
2423*7c478bd9Sstevel@tonic-gate 		abort();
2424*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_LDAP_DEBUG */
2425*7c478bd9Sstevel@tonic-gate 
2426*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, ret, "wu db_dictionary::commit");
2427*7c478bd9Sstevel@tonic-gate 	return (ret);
2428*7c478bd9Sstevel@tonic-gate }
2429*7c478bd9Sstevel@tonic-gate 
2430*7c478bd9Sstevel@tonic-gate /*
2431*7c478bd9Sstevel@tonic-gate  * The noWriteThrough flag is used to prevent modifies/updates to LDAP
2432*7c478bd9Sstevel@tonic-gate  * while we're incorporating log data into the in-memory tables.
2433*7c478bd9Sstevel@tonic-gate  */
2434*7c478bd9Sstevel@tonic-gate void
2435*7c478bd9Sstevel@tonic-gate db_dictionary::setNoWriteThrough(void) {
2436*7c478bd9Sstevel@tonic-gate 	ASSERTWHELD(this->dict);
2437*7c478bd9Sstevel@tonic-gate 	noWriteThrough.flag++;
2438*7c478bd9Sstevel@tonic-gate }
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate void
2441*7c478bd9Sstevel@tonic-gate db_dictionary::clearNoWriteThrough(void) {
2442*7c478bd9Sstevel@tonic-gate 	ASSERTWHELD(this->dict);
2443*7c478bd9Sstevel@tonic-gate 	if (noWriteThrough.flag > 0)
2444*7c478bd9Sstevel@tonic-gate 		noWriteThrough.flag--;
2445*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_LDAP_DEBUG
2446*7c478bd9Sstevel@tonic-gate 	else
2447*7c478bd9Sstevel@tonic-gate 		abort();
2448*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_LDAP_DEBUG */
2449*7c478bd9Sstevel@tonic-gate }
2450