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