xref: /illumos-gate/usr/src/lib/libnisdb/db.cc (revision bc30fb4c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  *	db.cc
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
267c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #ifdef TDRPC
327c478bd9Sstevel@tonic-gate #include <sysent.h>
337c478bd9Sstevel@tonic-gate #else
347c478bd9Sstevel@tonic-gate #include <unistd.h>
357c478bd9Sstevel@tonic-gate #endif
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include "nisdb_mt.h"
387c478bd9Sstevel@tonic-gate #include "db_headers.h"
397c478bd9Sstevel@tonic-gate #include "db.h"
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate extern db_result *empty_result(db_status);
427c478bd9Sstevel@tonic-gate extern int add_to_standby_list(db*);
437c478bd9Sstevel@tonic-gate extern int remove_from_standby_list(db*);
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /* for db_next_desc */
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #define	LINEAR 1
487c478bd9Sstevel@tonic-gate #define	CHAINED 2
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate struct db_next_info {
517c478bd9Sstevel@tonic-gate 	int next_type;		/* linear or chained */
527c478bd9Sstevel@tonic-gate 	void* next_value;	/* linear: entryp; */
537c478bd9Sstevel@tonic-gate 				/* chained: db_next_index_desc* */
547c478bd9Sstevel@tonic-gate };
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /* Constructor:  Create a database using the given name, 'dbname.'
587c478bd9Sstevel@tonic-gate 	    The database is stored in a file named 'dbname'.
597c478bd9Sstevel@tonic-gate 	    The log file is stored in a file named 'dbname'.log.
607c478bd9Sstevel@tonic-gate 	    A temporary file 'dbname'.tmp is also used.   */
db(char * dbname)617c478bd9Sstevel@tonic-gate db::db(char* dbname)
627c478bd9Sstevel@tonic-gate {
637c478bd9Sstevel@tonic-gate 	int len = strlen(dbname);
647c478bd9Sstevel@tonic-gate 	dbfilename = new char[len+1];
657c478bd9Sstevel@tonic-gate 	if (dbfilename == NULL)
667c478bd9Sstevel@tonic-gate 		FATAL("db::db: cannot allocate space", DB_MEMORY_LIMIT);
677c478bd9Sstevel@tonic-gate 	logfilename = new char[len+5];
687c478bd9Sstevel@tonic-gate 	if (logfilename == NULL) {
697c478bd9Sstevel@tonic-gate 		delete dbfilename;
707c478bd9Sstevel@tonic-gate 		FATAL("db::db: cannot allocate space", DB_MEMORY_LIMIT);
717c478bd9Sstevel@tonic-gate 	}
727c478bd9Sstevel@tonic-gate 	tmpfilename = new char[len+5];
737c478bd9Sstevel@tonic-gate 	if (tmpfilename == NULL) {
747c478bd9Sstevel@tonic-gate 		delete dbfilename;
757c478bd9Sstevel@tonic-gate 		delete logfilename;
767c478bd9Sstevel@tonic-gate 		FATAL("db::db: cannot allocate space", DB_MEMORY_LIMIT);
777c478bd9Sstevel@tonic-gate 	}
787c478bd9Sstevel@tonic-gate 	sprintf(dbfilename, "%s", dbname);
797c478bd9Sstevel@tonic-gate 	sprintf(logfilename, "%s.log", dbname);
807c478bd9Sstevel@tonic-gate 	sprintf(tmpfilename, "%s.tmp", dbname);
817c478bd9Sstevel@tonic-gate 	logfile = NULL;
827c478bd9Sstevel@tonic-gate 	logfile_opened = FALSE;
837c478bd9Sstevel@tonic-gate 	changed = FALSE;
847c478bd9Sstevel@tonic-gate 	INITRW(db);
857c478bd9Sstevel@tonic-gate 	READLOCKOK(db);
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	internal_db.setDbPtr(this);
887c478bd9Sstevel@tonic-gate 	(void) internal_db.configure(dbname);
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /* destructor:  note that associated files should be removed separated  */
~db()927c478bd9Sstevel@tonic-gate db::~db()
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	(void)acqexcl();
957c478bd9Sstevel@tonic-gate 	internal_db.reset();  /* clear any associated data structures */
967c478bd9Sstevel@tonic-gate 	delete dbfilename;
977c478bd9Sstevel@tonic-gate 	delete logfilename;
987c478bd9Sstevel@tonic-gate 	delete tmpfilename;
997c478bd9Sstevel@tonic-gate 	close_log();
1007c478bd9Sstevel@tonic-gate 	delete logfile;
1017c478bd9Sstevel@tonic-gate 	(void)destroylock();
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate static void
assign_next_desc(db_next_desc * desc,entryp value)1067c478bd9Sstevel@tonic-gate assign_next_desc(db_next_desc* desc, entryp value)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate 	db_next_info * store = new db_next_info;
1097c478bd9Sstevel@tonic-gate 	if (store == NULL) {
1107c478bd9Sstevel@tonic-gate 		desc->db_next_desc_val =  NULL;
1117c478bd9Sstevel@tonic-gate 		desc->db_next_desc_len = 0;
1127c478bd9Sstevel@tonic-gate 		FATAL("db::assign_next_desc: cannot allocate space",
1137c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT);
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	store->next_type = LINEAR;
1177c478bd9Sstevel@tonic-gate 	store->next_value = (void*)value;
1187c478bd9Sstevel@tonic-gate 	desc->db_next_desc_val =  (char*) store;
1197c478bd9Sstevel@tonic-gate 	desc->db_next_desc_len = sizeof (db_next_info);
1207c478bd9Sstevel@tonic-gate }
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate static void
assign_next_desc(db_next_desc * desc,db_next_index_desc * value)1237c478bd9Sstevel@tonic-gate assign_next_desc(db_next_desc* desc, db_next_index_desc * value)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate 	db_next_info * store = new db_next_info;
1267c478bd9Sstevel@tonic-gate 	if (store == NULL) {
1277c478bd9Sstevel@tonic-gate 		desc->db_next_desc_val =  NULL;
1287c478bd9Sstevel@tonic-gate 		desc->db_next_desc_len = 0;
1297c478bd9Sstevel@tonic-gate 		FATAL("db::assign_next_desc: cannot allocate space (2)",
1307c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT);
1317c478bd9Sstevel@tonic-gate 	}
1327c478bd9Sstevel@tonic-gate 	store->next_type = CHAINED;
1337c478bd9Sstevel@tonic-gate 	store->next_value = (void*)value;
1347c478bd9Sstevel@tonic-gate 	desc->db_next_desc_val =  (char*) store;
1357c478bd9Sstevel@tonic-gate 	desc->db_next_desc_len = sizeof (db_next_info);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate static entryp
extract_next_desc(db_next_desc * desc,int * next_type,db_next_index_desc ** place2)1397c478bd9Sstevel@tonic-gate extract_next_desc(db_next_desc* desc, int *next_type,
1407c478bd9Sstevel@tonic-gate 		db_next_index_desc** place2)
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate 	entryp place;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	if (desc == NULL || desc->db_next_desc_len != sizeof (db_next_info)) {
1457c478bd9Sstevel@tonic-gate 		*next_type = 0;
1467c478bd9Sstevel@tonic-gate 		return (0);
1477c478bd9Sstevel@tonic-gate 	}
1487c478bd9Sstevel@tonic-gate 	*next_type = ((db_next_info*) desc->db_next_desc_val)->next_type;
1497c478bd9Sstevel@tonic-gate 	switch (*next_type) {
1507c478bd9Sstevel@tonic-gate 	case LINEAR:
1517c478bd9Sstevel@tonic-gate 		place = (entryp)
1527c478bd9Sstevel@tonic-gate 			((db_next_info*) desc->db_next_desc_val)->next_value;
1537c478bd9Sstevel@tonic-gate 		return (place);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	case CHAINED:
1567c478bd9Sstevel@tonic-gate 		*place2 = (db_next_index_desc*)
1577c478bd9Sstevel@tonic-gate 			((db_next_info*) desc->db_next_desc_val) ->next_value;
1587c478bd9Sstevel@tonic-gate 		return (0);
1597c478bd9Sstevel@tonic-gate 	default:
1607c478bd9Sstevel@tonic-gate 		*next_type = 0;   // invalid type
1617c478bd9Sstevel@tonic-gate 		return (0);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate }
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /* Execute the specified action using the rest of the arguments as input.
1667c478bd9Sstevel@tonic-gate 	    Return  a structure db_result containing the result. */
1677c478bd9Sstevel@tonic-gate db_result *
exec_action(db_action action,db_query * query,entry_object * content,db_next_desc * previous)1687c478bd9Sstevel@tonic-gate db::exec_action(db_action action, db_query *query,
1697c478bd9Sstevel@tonic-gate 		entry_object *content, db_next_desc* previous)
1707c478bd9Sstevel@tonic-gate {
1717c478bd9Sstevel@tonic-gate 	entryp where, prev;
1727c478bd9Sstevel@tonic-gate 	db_result *res = new db_result;
1737c478bd9Sstevel@tonic-gate 	long num_answers;
1747c478bd9Sstevel@tonic-gate 	entry_object_p * ans;
1757c478bd9Sstevel@tonic-gate 	entry_object * single;
1767c478bd9Sstevel@tonic-gate 	db_next_index_desc *index_desc;
1777c478bd9Sstevel@tonic-gate 	int next_type;
1787c478bd9Sstevel@tonic-gate 	db_next_index_desc *prev_desc;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if (res == NULL)
1817c478bd9Sstevel@tonic-gate 		FATAL3("db::exec_action: cannot allocate space for result",
1827c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, NULL);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	res->objects.objects_len = 0; /* default */
1857c478bd9Sstevel@tonic-gate 	res->objects.objects_val = NULL;  /* default */
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	switch (action) {
1887c478bd9Sstevel@tonic-gate 	case DB_LOOKUP:
1897c478bd9Sstevel@tonic-gate 		res->status = internal_db.lookup(query, &num_answers, &ans);
1907c478bd9Sstevel@tonic-gate 		res->objects.objects_len = (int) num_answers;
1917c478bd9Sstevel@tonic-gate 		res->objects.objects_val = ans;
1927c478bd9Sstevel@tonic-gate 		break;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	case DB_ADD:
1957c478bd9Sstevel@tonic-gate 		res->status = internal_db.add(query, content);
1967c478bd9Sstevel@tonic-gate 		break;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	case DB_REMOVE:
1997c478bd9Sstevel@tonic-gate 		res->status = internal_db.remove(query);
2007c478bd9Sstevel@tonic-gate 		break;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	case DB_FIRST:
2037c478bd9Sstevel@tonic-gate 		if (query == NULL) {
2047c478bd9Sstevel@tonic-gate 			res->status = internal_db.first(&where, &single);
2057c478bd9Sstevel@tonic-gate 			if (res->status == DB_SUCCESS)
2067c478bd9Sstevel@tonic-gate 				assign_next_desc(&(res->nextinfo), where);
2077c478bd9Sstevel@tonic-gate 		}  else {
2087c478bd9Sstevel@tonic-gate 			res->status = internal_db.first(query,
2097c478bd9Sstevel@tonic-gate 							&index_desc,
2107c478bd9Sstevel@tonic-gate 							&single);
2117c478bd9Sstevel@tonic-gate 			if (res->status == DB_SUCCESS)
2127c478bd9Sstevel@tonic-gate 				assign_next_desc(&(res->nextinfo), index_desc);
2137c478bd9Sstevel@tonic-gate 		}
2147c478bd9Sstevel@tonic-gate 		if (res->status == DB_SUCCESS) {
2157c478bd9Sstevel@tonic-gate 			res->objects.objects_val = new entry_object_p;
2167c478bd9Sstevel@tonic-gate 			if (res->objects.objects_val == NULL) {
2177c478bd9Sstevel@tonic-gate 				res->objects.objects_len = 0;
2187c478bd9Sstevel@tonic-gate 				delete res;
2197c478bd9Sstevel@tonic-gate 				FATAL3(
2207c478bd9Sstevel@tonic-gate 		"db::exec_action: cannot allocate space for DB_FIRST result",
2217c478bd9Sstevel@tonic-gate 		DB_MEMORY_LIMIT, NULL);
2227c478bd9Sstevel@tonic-gate 			}
2237c478bd9Sstevel@tonic-gate 			res->objects.objects_len = 1;
2247c478bd9Sstevel@tonic-gate 			res->objects.objects_val[0] = single;
2257c478bd9Sstevel@tonic-gate 		}
2267c478bd9Sstevel@tonic-gate 		break;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	case DB_NEXT:
2297c478bd9Sstevel@tonic-gate 		prev = extract_next_desc(previous, &next_type, &prev_desc);
2307c478bd9Sstevel@tonic-gate 		switch (next_type) {
2317c478bd9Sstevel@tonic-gate 		case LINEAR:
2327c478bd9Sstevel@tonic-gate 			if (prev != 0) {
2337c478bd9Sstevel@tonic-gate 				res->status = internal_db.next(prev, &where,
2347c478bd9Sstevel@tonic-gate 								&single);
2357c478bd9Sstevel@tonic-gate 				if (res->status == DB_SUCCESS)
2367c478bd9Sstevel@tonic-gate 					assign_next_desc(&(res->nextinfo),
2377c478bd9Sstevel@tonic-gate 								where);
2387c478bd9Sstevel@tonic-gate 			} else
2397c478bd9Sstevel@tonic-gate 					// invalid previous indicator
2407c478bd9Sstevel@tonic-gate 				res->status = DB_NOTFOUND;
2417c478bd9Sstevel@tonic-gate 			break;
2427c478bd9Sstevel@tonic-gate 		case CHAINED:
2437c478bd9Sstevel@tonic-gate 			if (prev_desc != NULL) {
2447c478bd9Sstevel@tonic-gate 				res->status = internal_db.next(prev_desc,
2457c478bd9Sstevel@tonic-gate 							&index_desc, &single);
2467c478bd9Sstevel@tonic-gate 				if (res->status == DB_SUCCESS)
2477c478bd9Sstevel@tonic-gate 					assign_next_desc(&(res->nextinfo),
2487c478bd9Sstevel@tonic-gate 								index_desc);
2497c478bd9Sstevel@tonic-gate 			} else
2507c478bd9Sstevel@tonic-gate 					// invalid previous indicator
2517c478bd9Sstevel@tonic-gate 				res->status = DB_NOTFOUND;
2527c478bd9Sstevel@tonic-gate 			break;
2537c478bd9Sstevel@tonic-gate 		default:
2547c478bd9Sstevel@tonic-gate 			WARNING("db::exec_action: invalid previous indicator");
2557c478bd9Sstevel@tonic-gate 			res->status = DB_BADQUERY;
2567c478bd9Sstevel@tonic-gate 		}
2577c478bd9Sstevel@tonic-gate 		if (previous && previous->db_next_desc_val) {
2587c478bd9Sstevel@tonic-gate 			delete previous->db_next_desc_val;
2597c478bd9Sstevel@tonic-gate 			previous->db_next_desc_len = 0;
2607c478bd9Sstevel@tonic-gate 			previous->db_next_desc_val = NULL;
2617c478bd9Sstevel@tonic-gate 		}
2627c478bd9Sstevel@tonic-gate 		if (res->status == DB_SUCCESS) {
2637c478bd9Sstevel@tonic-gate 			res->objects.objects_len = 1;
2647c478bd9Sstevel@tonic-gate 			res->objects.objects_val = new entry_object_p;
2657c478bd9Sstevel@tonic-gate 			if (res->objects.objects_val == NULL) {
2667c478bd9Sstevel@tonic-gate 				res->objects.objects_len = 0;
2677c478bd9Sstevel@tonic-gate 				delete res;
2687c478bd9Sstevel@tonic-gate 				FATAL3(
2697c478bd9Sstevel@tonic-gate 		    "db::exec_action: cannot allocate space for DB_NEXT result",
2707c478bd9Sstevel@tonic-gate 		    DB_MEMORY_LIMIT, NULL);
2717c478bd9Sstevel@tonic-gate 			}
2727c478bd9Sstevel@tonic-gate 			res->objects.objects_val[0] = single;
2737c478bd9Sstevel@tonic-gate 		}
2747c478bd9Sstevel@tonic-gate 		break;
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	case DB_RESET_NEXT:
2777c478bd9Sstevel@tonic-gate 		prev = extract_next_desc(previous, &next_type, &prev_desc);
2787c478bd9Sstevel@tonic-gate 		switch (next_type) {
2797c478bd9Sstevel@tonic-gate 		case LINEAR:
2807c478bd9Sstevel@tonic-gate 			res->status = DB_SUCCESS;
2817c478bd9Sstevel@tonic-gate 			if (previous->db_next_desc_val) {
2827c478bd9Sstevel@tonic-gate 	delete previous->db_next_desc_val;
2837c478bd9Sstevel@tonic-gate 	previous->db_next_desc_len = 0;
2847c478bd9Sstevel@tonic-gate 	previous->db_next_desc_val = NULL;
2857c478bd9Sstevel@tonic-gate 			}
2867c478bd9Sstevel@tonic-gate 			break;   // do nothing
2877c478bd9Sstevel@tonic-gate 		case CHAINED:
2887c478bd9Sstevel@tonic-gate 			res->status = internal_db.reset_next(prev_desc);
2897c478bd9Sstevel@tonic-gate 			if (previous->db_next_desc_val) {
2907c478bd9Sstevel@tonic-gate 	delete previous->db_next_desc_val;
2917c478bd9Sstevel@tonic-gate 	previous->db_next_desc_len = 0;
2927c478bd9Sstevel@tonic-gate 	previous->db_next_desc_val = NULL;
2937c478bd9Sstevel@tonic-gate 			}
2947c478bd9Sstevel@tonic-gate 			break;
2957c478bd9Sstevel@tonic-gate 		default:
2967c478bd9Sstevel@tonic-gate 			WARNING("db::exec_action: invalid previous indicator");
2977c478bd9Sstevel@tonic-gate 			res->status = DB_BADQUERY;
2987c478bd9Sstevel@tonic-gate 		}
2997c478bd9Sstevel@tonic-gate 		break;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	case DB_ALL:
3027c478bd9Sstevel@tonic-gate 		res->status = internal_db.all(&num_answers, &ans);
3037c478bd9Sstevel@tonic-gate 		res->objects.objects_len = (int) num_answers;
3047c478bd9Sstevel@tonic-gate 		res->objects.objects_val = ans;
3057c478bd9Sstevel@tonic-gate 		break;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	default:
3087c478bd9Sstevel@tonic-gate 		WARNING("unknown request");
3097c478bd9Sstevel@tonic-gate 		res->status = DB_BADQUERY;
3107c478bd9Sstevel@tonic-gate 		return (res);
3117c478bd9Sstevel@tonic-gate 	}
3127c478bd9Sstevel@tonic-gate 	return (res);
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate /*
3167c478bd9Sstevel@tonic-gate  * Log the given action and execute it.
3177c478bd9Sstevel@tonic-gate  * The minor version of the database is updated after the action has
3187c478bd9Sstevel@tonic-gate  * been executed and the database is flagged as being changed.
3197c478bd9Sstevel@tonic-gate  * Return the structure db_result, or NULL if the logging failed or the
3207c478bd9Sstevel@tonic-gate  * action is unknown.
3217c478bd9Sstevel@tonic-gate */
3227c478bd9Sstevel@tonic-gate db_result *
log_action(db_action action,db_query * query,entry_object * content)3237c478bd9Sstevel@tonic-gate db::log_action(db_action action, db_query *query, entry_object *content)
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate 	vers *v = internal_db.get_version()->nextminor();
3267c478bd9Sstevel@tonic-gate 	db_result * res;
3277c478bd9Sstevel@tonic-gate 	db_log_entry le(action, v, query, content);
3287c478bd9Sstevel@tonic-gate 	bool_t copylog = FALSE;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	WRITELOCK(this, empty_result(DB_LOCK_ERROR), "w db::log_action");
3317c478bd9Sstevel@tonic-gate 	/*
3327c478bd9Sstevel@tonic-gate 	 * If this is a synchronous operation on the master we should
3337c478bd9Sstevel@tonic-gate 	 * not copy the log for each operation.  Doing so causes
3347c478bd9Sstevel@tonic-gate 	 * massive disk IO that hampers the performance of these operations.
3357c478bd9Sstevel@tonic-gate 	 * Where as on the replica these operations are not synchronous
3367c478bd9Sstevel@tonic-gate 	 * (batched) and don't affect the performance as much.
3377c478bd9Sstevel@tonic-gate 	 */
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	if ((action == DB_ADD_NOSYNC) || (action == DB_REMOVE_NOSYNC))
3407c478bd9Sstevel@tonic-gate 		copylog = TRUE;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	if (open_log(copylog) < 0)  {
3437c478bd9Sstevel@tonic-gate 		delete v;
3447c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, empty_result(DB_LOCK_ERROR),
3457c478bd9Sstevel@tonic-gate 				"wu db::log_action DB_STORAGE_LIMIT");
3467c478bd9Sstevel@tonic-gate 		return (empty_result(DB_STORAGE_LIMIT));
3477c478bd9Sstevel@tonic-gate 	}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	if (logfile->append(&le) < 0) {
3507c478bd9Sstevel@tonic-gate 		close_log();
3517c478bd9Sstevel@tonic-gate 		WARNING_M("db::log_action: could not add log entry: ");
3527c478bd9Sstevel@tonic-gate 		delete v;
3537c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, empty_result(DB_LOCK_ERROR),
3547c478bd9Sstevel@tonic-gate 				"wu db::log_action DB_STORAGE_LIMIT");
3557c478bd9Sstevel@tonic-gate 		return (empty_result(DB_STORAGE_LIMIT));
3567c478bd9Sstevel@tonic-gate 	}
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	switch (action) {
3597c478bd9Sstevel@tonic-gate 	case DB_ADD_NOSYNC:
3607c478bd9Sstevel@tonic-gate 		action = DB_ADD;
3617c478bd9Sstevel@tonic-gate 		break;
3627c478bd9Sstevel@tonic-gate 	case DB_REMOVE_NOSYNC:
3637c478bd9Sstevel@tonic-gate 		action = DB_REMOVE;
3647c478bd9Sstevel@tonic-gate 		break;
3657c478bd9Sstevel@tonic-gate 	default:
3667c478bd9Sstevel@tonic-gate 		if (logfile->sync_log() < 0) {
3677c478bd9Sstevel@tonic-gate 			close_log();
3687c478bd9Sstevel@tonic-gate 			WARNING_M("db::log_action: could not add log entry: ");
3697c478bd9Sstevel@tonic-gate 			delete v;
3707c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, empty_result(DB_LOCK_ERROR),
3717c478bd9Sstevel@tonic-gate 					"wu db::log_action DB_STORAGE_LIMIT");
3727c478bd9Sstevel@tonic-gate 			return (empty_result(DB_STORAGE_LIMIT));
3737c478bd9Sstevel@tonic-gate 		}
3747c478bd9Sstevel@tonic-gate 		break;
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 	res = exec_action(action, query, content, NULL);
3777c478bd9Sstevel@tonic-gate 	internal_db.change_version(v);
3787c478bd9Sstevel@tonic-gate 	delete v;
3797c478bd9Sstevel@tonic-gate 	changed = TRUE;
3807c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, empty_result(DB_LOCK_ERROR), "wu db::log_action");
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	return (res);
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate  * Execute 'action' using the rest of the arguments as input.
3877c478bd9Sstevel@tonic-gate  * Return the result of the operation in a db_result structure;
3887c478bd9Sstevel@tonic-gate  * Return NULL if the request is unknown.
3897c478bd9Sstevel@tonic-gate  * If the action involves updates (ADD and REMOVE), it is logged first.
3907c478bd9Sstevel@tonic-gate  */
3917c478bd9Sstevel@tonic-gate db_result *
execute(db_action action,db_query * query,entry_object * content,db_next_desc * previous)3927c478bd9Sstevel@tonic-gate db::execute(db_action action, db_query *query,
3937c478bd9Sstevel@tonic-gate 		entry_object *content, db_next_desc* previous)
3947c478bd9Sstevel@tonic-gate {
3957c478bd9Sstevel@tonic-gate 	db_result	*res;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	switch (action) {
3987c478bd9Sstevel@tonic-gate 	case DB_LOOKUP:
3997c478bd9Sstevel@tonic-gate 	case DB_FIRST:
4007c478bd9Sstevel@tonic-gate 	case DB_NEXT:
4017c478bd9Sstevel@tonic-gate 	case DB_ALL:
4027c478bd9Sstevel@tonic-gate 	case DB_RESET_NEXT:
4037c478bd9Sstevel@tonic-gate 		READLOCK(this, empty_result(DB_LOCK_ERROR), "r db::execute");
4047c478bd9Sstevel@tonic-gate 		res = exec_action(action, query, content, previous);
4057c478bd9Sstevel@tonic-gate 		READUNLOCK(this, empty_result(DB_LOCK_ERROR),
4067c478bd9Sstevel@tonic-gate 				"ru db::execute");
4077c478bd9Sstevel@tonic-gate 		return (res);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	case DB_ADD_NOLOG:
4107c478bd9Sstevel@tonic-gate 		WRITELOCK(this, empty_result(DB_LOCK_ERROR), "w db::execute");
4117c478bd9Sstevel@tonic-gate 		changed = TRUE;
4127c478bd9Sstevel@tonic-gate 		res = exec_action(DB_ADD, query, content, previous);
4137c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, empty_result(DB_LOCK_ERROR),
4147c478bd9Sstevel@tonic-gate 				"wu db::execute");
4157c478bd9Sstevel@tonic-gate 		return (res);
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	case DB_ADD:
4187c478bd9Sstevel@tonic-gate 	case DB_REMOVE:
4197c478bd9Sstevel@tonic-gate 	case DB_ADD_NOSYNC:
4207c478bd9Sstevel@tonic-gate 	case DB_REMOVE_NOSYNC:
4217c478bd9Sstevel@tonic-gate 		/* log_action() will do the locking */
4227c478bd9Sstevel@tonic-gate 		return (log_action(action, query, content));
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	default:
4257c478bd9Sstevel@tonic-gate 		WARNING("db::execute: unknown request");
4267c478bd9Sstevel@tonic-gate 		return (empty_result(DB_INTERNAL_ERROR));
4277c478bd9Sstevel@tonic-gate 	}
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate /* close existing logfile and delete its structure */
4317c478bd9Sstevel@tonic-gate int
reset_log()4327c478bd9Sstevel@tonic-gate db::reset_log()
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db::reset_log");
4357c478bd9Sstevel@tonic-gate 	/* try to close old log file */
4367c478bd9Sstevel@tonic-gate 	/* doesnot matter since we do synchronous writes only */
4377c478bd9Sstevel@tonic-gate 	if (logfile != NULL) {
4387c478bd9Sstevel@tonic-gate 	    if (logfile_opened == TRUE) {
4397c478bd9Sstevel@tonic-gate 		    logfile->sync_log();
4407c478bd9Sstevel@tonic-gate 		    if (logfile->close() < 0) {
4417c478bd9Sstevel@tonic-gate 			WARNING_M("db::reset_log: could not close log file: ");
4427c478bd9Sstevel@tonic-gate 		    }
4437c478bd9Sstevel@tonic-gate 		    remove_from_standby_list(this);
4447c478bd9Sstevel@tonic-gate 	    }
4457c478bd9Sstevel@tonic-gate 	    delete logfile;
4467c478bd9Sstevel@tonic-gate 	    logfile = NULL;
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 	logfile_opened = FALSE;
4497c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db::reset_log");
4507c478bd9Sstevel@tonic-gate 	return (0);
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate /* close existing logfile, but leave its structure if exists */
4547c478bd9Sstevel@tonic-gate int
close_log(int bypass_standby)4557c478bd9Sstevel@tonic-gate db::close_log(int bypass_standby)
4567c478bd9Sstevel@tonic-gate {
4577c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db::close_log");
4587c478bd9Sstevel@tonic-gate 	if (logfile != NULL && logfile_opened == TRUE) {
4597c478bd9Sstevel@tonic-gate 		logfile->sync_log();
4607c478bd9Sstevel@tonic-gate 		logfile->close();
4617c478bd9Sstevel@tonic-gate 		if (!bypass_standby)
4627c478bd9Sstevel@tonic-gate 		    remove_from_standby_list(this);
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 	logfile_opened = FALSE;
4657c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db::close_log");
4667c478bd9Sstevel@tonic-gate 	return (0);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate /* open logfile, creating its structure if it does not exist */
4707c478bd9Sstevel@tonic-gate int
open_log(bool_t copylog)4717c478bd9Sstevel@tonic-gate db::open_log(bool_t copylog)
4727c478bd9Sstevel@tonic-gate {
4737c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db::open_log");
4747c478bd9Sstevel@tonic-gate 	if (logfile == NULL) {
4757c478bd9Sstevel@tonic-gate 		if ((logfile = new db_log(logfilename, PICKLE_APPEND))
4767c478bd9Sstevel@tonic-gate 		    == NULL)
4777c478bd9Sstevel@tonic-gate 			FATAL3("db::reset_log: cannot allocate space",
4787c478bd9Sstevel@tonic-gate 			    DB_MEMORY_LIMIT, -1);
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	if (logfile_opened == TRUE) {
4827c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, -1, "wu db::open_log");
4837c478bd9Sstevel@tonic-gate 		return (0);
4847c478bd9Sstevel@tonic-gate 	}
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	logfile->copylog = copylog;
4877c478bd9Sstevel@tonic-gate 
488*bc30fb4cSToomas Soome 	if ((logfile->open()) == FALSE){
4897c478bd9Sstevel@tonic-gate 		WARNING_M("db::open_log: could not open log file: ");
4907c478bd9Sstevel@tonic-gate 		delete logfile;
4917c478bd9Sstevel@tonic-gate 		logfile = NULL;
4927c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, -1, "wu db::open_log");
4937c478bd9Sstevel@tonic-gate 		return (-1);
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 	add_to_standby_list(this);
4967c478bd9Sstevel@tonic-gate 	logfile_opened = TRUE;
4977c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db::open_log");
4987c478bd9Sstevel@tonic-gate 	return (0);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate /*
5027c478bd9Sstevel@tonic-gate  * Execute log entry 'j' on the database identified by 'dbchar' if the
5037c478bd9Sstevel@tonic-gate  * version of j is later than that of the database.  If 'j' is executed,
5047c478bd9Sstevel@tonic-gate  * 'count' is incremented and the database's verison is updated to that of 'j'.
5057c478bd9Sstevel@tonic-gate  * Returns TRUE always for valid log entries; FALSE otherwise.
5067c478bd9Sstevel@tonic-gate  */
5077c478bd9Sstevel@tonic-gate static bool_t
apply_log_entry(db_log_entry * j,char * dbchar,int * count)5087c478bd9Sstevel@tonic-gate apply_log_entry(db_log_entry * j, char * dbchar, int *count)
5097c478bd9Sstevel@tonic-gate {
5107c478bd9Sstevel@tonic-gate 	db_mindex * db = (db_mindex *) dbchar;
5117c478bd9Sstevel@tonic-gate 	bool_t status = TRUE;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	WRITELOCK(db, FALSE, "db::apply_log_entry");
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	if (db->get_version()->earlier_than(j->get_version())) {
5167c478bd9Sstevel@tonic-gate 		++ *count;
5177c478bd9Sstevel@tonic-gate #ifdef DEBUG
5187c478bd9Sstevel@tonic-gate 		j->print();
5197c478bd9Sstevel@tonic-gate #endif /* DEBUG */
5207c478bd9Sstevel@tonic-gate 		switch (j->get_action()) {
5217c478bd9Sstevel@tonic-gate 		case DB_ADD:
5227c478bd9Sstevel@tonic-gate 		case DB_ADD_NOSYNC:
5237c478bd9Sstevel@tonic-gate 			db->add(j->get_query(), j->get_object());
5247c478bd9Sstevel@tonic-gate 			break;
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 		case DB_REMOVE:
5277c478bd9Sstevel@tonic-gate 		case DB_REMOVE_NOSYNC:
5287c478bd9Sstevel@tonic-gate 			db->remove(j->get_query());
5297c478bd9Sstevel@tonic-gate 			break;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 		default:
5327c478bd9Sstevel@tonic-gate 			WARNING("db::apply_log_entry: unknown action_type");
5337c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(db, FALSE, "db::apply_log_entry");
5347c478bd9Sstevel@tonic-gate 			return (FALSE);
5357c478bd9Sstevel@tonic-gate 		}
5367c478bd9Sstevel@tonic-gate 		db->change_version(j->get_version());
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(db, FALSE, "db::apply_log_entry");
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	return (TRUE);  /* always want to TRUE if action valid ? */
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /*
5457c478bd9Sstevel@tonic-gate  * Execute log entry 'j' on this db.  'j' is executed if its version is
5467c478bd9Sstevel@tonic-gate  * later than that of the database; if executed, the database's version
5477c478bd9Sstevel@tonic-gate  * will be changed to that of 'j', regardless of the status of the operation.
5487c478bd9Sstevel@tonic-gate  * Returns TRUE if 'j' was executed;   FALSE if it was not.
5497c478bd9Sstevel@tonic-gate  * Log entry is added to this database's log if log_entry is applied.
5507c478bd9Sstevel@tonic-gate  */
5517c478bd9Sstevel@tonic-gate bool_t
execute_log_entry(db_log_entry * j)5527c478bd9Sstevel@tonic-gate db::execute_log_entry(db_log_entry *j)
5537c478bd9Sstevel@tonic-gate {
5547c478bd9Sstevel@tonic-gate 	int count = 0;
5557c478bd9Sstevel@tonic-gate 	apply_log_entry (j, (char *) &internal_db, &count);
5567c478bd9Sstevel@tonic-gate 	bool_t copylog = FALSE;
5577c478bd9Sstevel@tonic-gate 	db_action action;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	/*
5607c478bd9Sstevel@tonic-gate 	 * If this is a synchronous operation on the master we should
5617c478bd9Sstevel@tonic-gate 	 * not copy the log for each operation.  Doing so causes
5627c478bd9Sstevel@tonic-gate 	 * massive disk IO that hampers the performance of these operations.
5637c478bd9Sstevel@tonic-gate 	 * Where as on the replica these operations are not synchronous
5647c478bd9Sstevel@tonic-gate 	 * (batched) and don't affect the performance as much.
5657c478bd9Sstevel@tonic-gate 	 */
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	action = j->get_action();
5687c478bd9Sstevel@tonic-gate 	if ((action == DB_ADD_NOSYNC) || (action == DB_REMOVE_NOSYNC))
5697c478bd9Sstevel@tonic-gate 		copylog = TRUE;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	/*
5727c478bd9Sstevel@tonic-gate 	 * should really record the log entry first, but can''t do that without
5737c478bd9Sstevel@tonic-gate 	 * knowing whether the log entry is applicable.
5747c478bd9Sstevel@tonic-gate 	 */
5757c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db::execute_log_entry");
5767c478bd9Sstevel@tonic-gate 	if (count == 1) {
5777c478bd9Sstevel@tonic-gate 		if (open_log(copylog) < 0) {
5787c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, FALSE, "wu db::execute_log_entry");
5797c478bd9Sstevel@tonic-gate 			return (FALSE);
5807c478bd9Sstevel@tonic-gate 		}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 		if (logfile->append(j) < 0) {
5837c478bd9Sstevel@tonic-gate 			close_log();
5847c478bd9Sstevel@tonic-gate 			WARNING_M(
5857c478bd9Sstevel@tonic-gate 			"db::execute_log_entry: could not add log entry: ");
5867c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(this, FALSE, "wu db::execute_log_entry");
5877c478bd9Sstevel@tonic-gate 			return (FALSE);
5887c478bd9Sstevel@tonic-gate 		}
5897c478bd9Sstevel@tonic-gate //	  close_log();  /* do this asynchronously */
5907c478bd9Sstevel@tonic-gate 	}
5917c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, FALSE, "wu db::execute_log_entry");
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	return (count == 1);
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate /* Incorporate updates in log to database already loaded.
5977c478bd9Sstevel@tonic-gate 	    Does not affect "logfile" */
5987c478bd9Sstevel@tonic-gate int
incorporate_log(char * filename)5997c478bd9Sstevel@tonic-gate db::incorporate_log(char* filename)
6007c478bd9Sstevel@tonic-gate {
6017c478bd9Sstevel@tonic-gate 	db_log f(filename, PICKLE_READ);
6027c478bd9Sstevel@tonic-gate 	int ret;
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db::incorporate_log");
6057c478bd9Sstevel@tonic-gate 	WRITELOCK2((&internal_db), -1, "w internal_db db::incorporate_log",
6067c478bd9Sstevel@tonic-gate 			this);
6077c478bd9Sstevel@tonic-gate 	internal_db.setNoWriteThrough();
6087c478bd9Sstevel@tonic-gate 	ret = f.execute_on_log(&(apply_log_entry), (char *) &internal_db);
6097c478bd9Sstevel@tonic-gate 	internal_db.clearNoWriteThrough();
6107c478bd9Sstevel@tonic-gate 	WRITEUNLOCK2(this, (&internal_db), ret, ret,
6117c478bd9Sstevel@tonic-gate 			"wu db::incorporate_log",
6127c478bd9Sstevel@tonic-gate 			"wu mindex db::incorporate_log");
6137c478bd9Sstevel@tonic-gate 	return (ret);
6147c478bd9Sstevel@tonic-gate }
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate /* Load database and incorporate any logged updates into the loaded copy.
6177c478bd9Sstevel@tonic-gate 	    Return TRUE if load succeeds; FALSE otherwise. */
6187c478bd9Sstevel@tonic-gate bool_t
load()6197c478bd9Sstevel@tonic-gate db::load()
6207c478bd9Sstevel@tonic-gate {
6217c478bd9Sstevel@tonic-gate 	int count;
6227c478bd9Sstevel@tonic-gate 	int load_status;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db::load");
6257c478bd9Sstevel@tonic-gate 	if (changed == TRUE)
6267c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
6277c478bd9Sstevel@tonic-gate 	"WARNING: the current db '%s' has been changed but not checkpointed",
6287c478bd9Sstevel@tonic-gate 			dbfilename);
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	unlink(tmpfilename);  /* get rid of partial checkpoints */
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	if ((load_status = internal_db.load(dbfilename)) != 0) {
6337c478bd9Sstevel@tonic-gate 	    if (load_status < 0)
6347c478bd9Sstevel@tonic-gate 		    syslog(LOG_ERR, "Load of db '%s' failed", dbfilename);
6357c478bd9Sstevel@tonic-gate 	    /* otherwise, there was just nothing to load */
6367c478bd9Sstevel@tonic-gate 	    WRITEUNLOCK(this, FALSE, "wu db::load");
6377c478bd9Sstevel@tonic-gate 	    return (FALSE);
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	changed = FALSE;
6417c478bd9Sstevel@tonic-gate 	reset_log();
6427c478bd9Sstevel@tonic-gate 	WRITELOCK2((&internal_db), FALSE, "w internal_db db::load", this);
6437c478bd9Sstevel@tonic-gate 	internal_db.setInitialLoad();
6447c478bd9Sstevel@tonic-gate 	if ((count = incorporate_log(logfilename)) < 0)
6457c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "incorporation of db logfile '%s' load failed",
6467c478bd9Sstevel@tonic-gate 	    logfilename);
6477c478bd9Sstevel@tonic-gate 	changed = (count > 0);
6487c478bd9Sstevel@tonic-gate 	internal_db.clearInitialLoad();
6497c478bd9Sstevel@tonic-gate 	WRITEUNLOCK2(this, (&internal_db),
6507c478bd9Sstevel@tonic-gate 			(changed ? TRUE : FALSE), (changed ? TRUE : FALSE),
6517c478bd9Sstevel@tonic-gate 			"wu db::load", "wu internal_db db::load");
6527c478bd9Sstevel@tonic-gate 	return (TRUE);
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate /*
6567c478bd9Sstevel@tonic-gate  * Initialize the database using table scheme 's'.
6577c478bd9Sstevel@tonic-gate  * Because the 'scheme' must be 'remembered' between restarts,
6587c478bd9Sstevel@tonic-gate  * after the initialization, the empty database is checkpointed to record
6597c478bd9Sstevel@tonic-gate  * the scheme. Returns TRUE if initialization succeeds; FALSE otherwise.
6607c478bd9Sstevel@tonic-gate  */
6617c478bd9Sstevel@tonic-gate bool_t
init(db_scheme * s)6627c478bd9Sstevel@tonic-gate db::init(db_scheme * s)
6637c478bd9Sstevel@tonic-gate {
6647c478bd9Sstevel@tonic-gate 	bool_t	ret = FALSE;
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db::init");
6677c478bd9Sstevel@tonic-gate 	internal_db.init(s);
6687c478bd9Sstevel@tonic-gate 	if (internal_db.good()) {
6697c478bd9Sstevel@tonic-gate 		unlink(tmpfilename);	/* delete partial checkpoints */
6707c478bd9Sstevel@tonic-gate 		unlink(logfilename);	/* delete previous logfile */
6717c478bd9Sstevel@tonic-gate 		reset_log();
6727c478bd9Sstevel@tonic-gate 		changed = TRUE;		/* force dump to get scheme stored. */
6737c478bd9Sstevel@tonic-gate 		ret = checkpoint();
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, FALSE, "wu db::init");
6767c478bd9Sstevel@tonic-gate 	return (ret);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate /*
6807c478bd9Sstevel@tonic-gate     Write out in-memory copy of database to file.
6817c478bd9Sstevel@tonic-gate 	    1.  Update major version.
6827c478bd9Sstevel@tonic-gate 	    2.  Dump contents to temporary file.
6837c478bd9Sstevel@tonic-gate 	    3.  Rename temporary file to real database file.
6847c478bd9Sstevel@tonic-gate 	    4.  Remove log file.
6857c478bd9Sstevel@tonic-gate     A checkpoint is done only if it has changed since the previous checkpoint.
6867c478bd9Sstevel@tonic-gate     Returns TRUE if checkpoint was successful; FALSE otherwise.
6877c478bd9Sstevel@tonic-gate */
6887c478bd9Sstevel@tonic-gate bool_t
checkpoint()6897c478bd9Sstevel@tonic-gate db::checkpoint()
6907c478bd9Sstevel@tonic-gate {
6917c478bd9Sstevel@tonic-gate 	WRITELOCK(this, FALSE, "w db::checkpoint");
6927c478bd9Sstevel@tonic-gate 	if (changed == FALSE) {
6937c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE, "wu db::checkpoint");
6947c478bd9Sstevel@tonic-gate 		return (TRUE);
6957c478bd9Sstevel@tonic-gate 	}
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	vers *oldversion = new vers(internal_db.get_version()); /* copy */
6987c478bd9Sstevel@tonic-gate 	vers *nextversion = oldversion->nextmajor();	/* get next version */
6997c478bd9Sstevel@tonic-gate 	internal_db.change_version(nextversion);	/* change version */
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	if (internal_db.dump(tmpfilename) < 0) {  	/* dump to tempfile */
7027c478bd9Sstevel@tonic-gate 		WARNING_M("db::checkpoint: could not dump database: ");
7037c478bd9Sstevel@tonic-gate 		internal_db.change_version(oldversion);	/* rollback */
7047c478bd9Sstevel@tonic-gate 		delete nextversion;
7057c478bd9Sstevel@tonic-gate 		delete oldversion;
7067c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE, "wu db::checkpoint");
7077c478bd9Sstevel@tonic-gate 		return (FALSE);
7087c478bd9Sstevel@tonic-gate 	}
7097c478bd9Sstevel@tonic-gate 	if (rename(tmpfilename, dbfilename) < 0){  	/* rename permanently */
7107c478bd9Sstevel@tonic-gate 		WARNING_M(
7117c478bd9Sstevel@tonic-gate 		    "db::checkpoint: could not rename temp file to db file: ");
7127c478bd9Sstevel@tonic-gate 		internal_db.change_version(oldversion);	/* rollback */
7137c478bd9Sstevel@tonic-gate 		delete nextversion;
7147c478bd9Sstevel@tonic-gate 		delete oldversion;
7157c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, FALSE, "wu db::checkpoint");
7167c478bd9Sstevel@tonic-gate 		return (FALSE);
7177c478bd9Sstevel@tonic-gate 	}
7187c478bd9Sstevel@tonic-gate 	reset_log();		/* should check for what? */
7197c478bd9Sstevel@tonic-gate 	unlink(logfilename);	/* should do atomic rename and log delete */
7207c478bd9Sstevel@tonic-gate 	delete nextversion;
7217c478bd9Sstevel@tonic-gate 	delete oldversion;
7227c478bd9Sstevel@tonic-gate 	changed = FALSE;
7237c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, FALSE, "wu db::checkpoint");
7247c478bd9Sstevel@tonic-gate 	return (TRUE);
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate /* For generating log_list */
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate struct traverse_info {
7317c478bd9Sstevel@tonic-gate 	vers *version;		// version to check for
7327c478bd9Sstevel@tonic-gate 	db_log_entry * head;	// head of list of log entries found
7337c478bd9Sstevel@tonic-gate 	db_log_entry * tail;	// tail of list of log entries found
7347c478bd9Sstevel@tonic-gate };
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate /*
7377c478bd9Sstevel@tonic-gate  * For the given entry determine, if it is later than the version supplied,
7387c478bd9Sstevel@tonic-gate  *	    1.  increment 'count'.
7397c478bd9Sstevel@tonic-gate  *	    2.  add the entry to the list of log entries found.
7407c478bd9Sstevel@tonic-gate  *
7417c478bd9Sstevel@tonic-gate  * Since traversal happens on an automatic (struct traverse_info) in
7427c478bd9Sstevel@tonic-gate  * db::get_log_entries_since(), no locking is necessary.
7437c478bd9Sstevel@tonic-gate  */
entry_since(db_log_entry * j,char * tichar,int * count)7447c478bd9Sstevel@tonic-gate static bool_t entry_since(db_log_entry * j, char * tichar, int *count)
7457c478bd9Sstevel@tonic-gate {
7467c478bd9Sstevel@tonic-gate 	traverse_info *ti = (traverse_info*) tichar;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	if (ti->version->earlier_than(j->get_version())) {
7497c478bd9Sstevel@tonic-gate 		++ *count;
7507c478bd9Sstevel@tonic-gate //    j->print();   // debug
7517c478bd9Sstevel@tonic-gate 		if (ti->head == NULL)
7527c478bd9Sstevel@tonic-gate 			ti->head = j;
7537c478bd9Sstevel@tonic-gate 		else {
7547c478bd9Sstevel@tonic-gate 			ti->tail->setnextptr(j); // make last entry point to j
7557c478bd9Sstevel@tonic-gate 		}
7567c478bd9Sstevel@tonic-gate 		ti->tail = j;			// make j new last entry
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	return (TRUE);
7607c478bd9Sstevel@tonic-gate }
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate /* Return structure db_log_list containing entries that are later
7637c478bd9Sstevel@tonic-gate 	    than the version 'v' given.  */
7647c478bd9Sstevel@tonic-gate db_log_list*
get_log_entries_since(vers * v)7657c478bd9Sstevel@tonic-gate db::get_log_entries_since(vers * v)
7667c478bd9Sstevel@tonic-gate {
7677c478bd9Sstevel@tonic-gate 	int count;
7687c478bd9Sstevel@tonic-gate 	struct traverse_info ti;
7697c478bd9Sstevel@tonic-gate 	db_log f(logfilename, PICKLE_READ);
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	ti.version = v;
7727c478bd9Sstevel@tonic-gate 	ti.head = ti.tail = NULL;
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	count = f.execute_on_log(&(entry_since), (char *) &ti, FALSE);
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	db_log_list * answer = new db_log_list;
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	if (answer == NULL)
7797c478bd9Sstevel@tonic-gate 		FATAL3("db::get_log_entries_since: cannot allocate space",
7807c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, NULL);
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	answer->list.list_len = count;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	if (count > 0) {
7857c478bd9Sstevel@tonic-gate 		db_log_entry_p *entries;
7867c478bd9Sstevel@tonic-gate 		db_log_entry_p currentry, nextentry;
7877c478bd9Sstevel@tonic-gate 		int i;
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 		entries = answer->list.list_val = new db_log_entry_p[count];
7907c478bd9Sstevel@tonic-gate 		if (entries == NULL) {
7917c478bd9Sstevel@tonic-gate 			delete answer;
7927c478bd9Sstevel@tonic-gate 			FATAL3(
7937c478bd9Sstevel@tonic-gate 		"db::get_log_entries_since: cannot allocate space for entries",
7947c478bd9Sstevel@tonic-gate 		DB_MEMORY_LIMIT, NULL);
7957c478bd9Sstevel@tonic-gate 			}
7967c478bd9Sstevel@tonic-gate 		currentry = ti.head;
7977c478bd9Sstevel@tonic-gate 		for (i = 0, currentry = ti.head;
7987c478bd9Sstevel@tonic-gate 			i < count && currentry != NULL;
7997c478bd9Sstevel@tonic-gate 			i++) {
8007c478bd9Sstevel@tonic-gate 			entries[i] = currentry;
8017c478bd9Sstevel@tonic-gate 			nextentry = currentry->getnextptr();
8027c478bd9Sstevel@tonic-gate 			currentry->setnextptr(NULL);
8037c478bd9Sstevel@tonic-gate 			currentry = nextentry;
8047c478bd9Sstevel@tonic-gate 		}
8057c478bd9Sstevel@tonic-gate 	} else
8067c478bd9Sstevel@tonic-gate 		answer->list.list_val = NULL;
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	return (answer);
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate /* Delete all files associated with database. */
8127c478bd9Sstevel@tonic-gate int
remove_files()8137c478bd9Sstevel@tonic-gate db::remove_files()
8147c478bd9Sstevel@tonic-gate {
8157c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db::remove_files");
8167c478bd9Sstevel@tonic-gate 	unlink(tmpfilename);  /* delete partial checkpoints */
8177c478bd9Sstevel@tonic-gate 	reset_log();
8187c478bd9Sstevel@tonic-gate 	unlink(logfilename);  /* delete logfile */
8197c478bd9Sstevel@tonic-gate 	unlink(dbfilename);   /* delete database file */
8207c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, -1, "wu db::remove_files");
8217c478bd9Sstevel@tonic-gate 	return (0);
8227c478bd9Sstevel@tonic-gate }
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate db_status
sync_log()8257c478bd9Sstevel@tonic-gate db::sync_log() {
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	db_status	ret;
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db::sync_log");
8307c478bd9Sstevel@tonic-gate 	if (logfile == 0) {
8317c478bd9Sstevel@tonic-gate 		ret = DB_BADTABLE;
8327c478bd9Sstevel@tonic-gate 	} else {
8337c478bd9Sstevel@tonic-gate 		if (logfile_opened == FALSE || logfile->sync_log())
8347c478bd9Sstevel@tonic-gate 			ret = DB_SUCCESS;
8357c478bd9Sstevel@tonic-gate 		else
8367c478bd9Sstevel@tonic-gate 			ret = DB_SYNC_FAILED;
8377c478bd9Sstevel@tonic-gate 	}
8387c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, DB_LOCK_ERROR, "wu db::sync_log");
8397c478bd9Sstevel@tonic-gate 	return (ret);
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate /* Pass configuration information to the db_mindex */
8437c478bd9Sstevel@tonic-gate bool_t
configure(char * objName)8447c478bd9Sstevel@tonic-gate db::configure(char *objName) {
8457c478bd9Sstevel@tonic-gate 	return (internal_db.configure(objName));
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate db_mindex *
mindex(void)8497c478bd9Sstevel@tonic-gate db::mindex(void) {
8507c478bd9Sstevel@tonic-gate 	return (&internal_db);
8517c478bd9Sstevel@tonic-gate }
852