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