00001 /*<std-header orig-src='shore'> 00002 00003 $Id: log_exceed.cpp,v 1.4 2010/07/01 00:08:25 nhall Exp $ 00004 00005 SHORE -- Scalable Heterogeneous Object REpository 00006 00007 Copyright (c) 1994-99 Computer Sciences Department, University of 00008 Wisconsin -- Madison 00009 All Rights Reserved. 00010 00011 Permission to use, copy, modify and distribute this software and its 00012 documentation is hereby granted, provided that both the copyright 00013 notice and this permission notice appear in all copies of the 00014 software, derivative works or modified versions, and any portions 00015 thereof, and that both notices appear in supporting documentation. 00016 00017 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY 00018 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS 00019 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND 00020 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 00021 00022 This software was developed with support by the Advanced Research 00023 Project Agency, ARPA order number 018 (formerly 8230), monitored by 00024 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518. 00025 Further funding for this work was provided by DARPA through 00026 Rome Research Laboratory Contract No. F30602-97-2-0247. 00027 00028 */ 00029 00030 #include "w_defines.h" 00031 00032 /* -- do not edit anything above this line -- </std-header>*/ 00033 00034 /* 00035 * This program is a test of out-of-log-space-warning facilities 00036 * It requires access to xct_t, so the #include files are a bit different. 00037 * We have to pretend we are an internal part of the SM before we #include the world. 00038 */ 00039 00040 #define SM_LEVEL 1 00041 #define SM_SOURCE 00042 #define XCT_C 00043 #include "sm_int_1.h" 00044 #include "sm_vas.h" 00045 00046 ss_m* ssm = 0; 00047 00048 extern w_rc_t out_of_log_space (xct_i*, xct_t*&, ss_m::fileoff_t, 00049 ss_m::fileoff_t, 00050 const char *logfile 00051 ); 00052 00053 extern w_rc_t get_archived_log_file (const char *logfile, ss_m::partition_number_t); 00054 00055 // shorten error code type name 00056 typedef w_rc_t rc_t; 00057 00058 // this is implemented in options.cpp 00059 w_rc_t init_config_options(option_group_t& options, 00060 const char* prog_type, 00061 int& argc, char** argv); 00062 00063 00064 struct file_info_t { 00065 static const char* key; 00066 stid_t fid; 00067 rid_t first_rid; 00068 int num_rec; 00069 int rec_size; 00070 }; 00071 const char* file_info_t::key = "SCANFILE"; 00072 00073 ostream & 00074 operator << (ostream &o, const file_info_t &info) 00075 { 00076 o << "key " << info.key 00077 << " fid " << info.fid 00078 << " first_rid " << info.first_rid 00079 << " num_rec " << info.num_rec 00080 << " rec_size " << info.rec_size ; 00081 return o; 00082 } 00083 00084 00085 typedef smlevel_0::smksize_t smksize_t; 00086 00087 00088 00089 void 00090 usage(option_group_t& options) 00091 { 00092 cerr << "Usage: log_exceed [-h] [options]" << endl; 00093 cerr << "Valid options are: " << endl; 00094 options.print_usage(true, cerr); 00095 } 00096 00097 /* create an smthread based class for all sm-related work */ 00098 class smthread_user_t : public smthread_t 00099 { 00100 int _argc; 00101 char **_argv; 00102 00103 const char *_device_name; 00104 smsize_t _quota; 00105 int _num_rec; 00106 smsize_t _rec_size; 00107 lvid_t _lvid; 00108 rid_t _start_rid; 00109 stid_t _fid; 00110 bool _initialize_device; 00111 option_group_t* _options; 00112 vid_t _vid; 00113 public: 00114 int retval; 00115 00116 smthread_user_t(int ac, char **av) 00117 : smthread_t(t_regular, "smthread_user_t"), 00118 _argc(ac), _argv(av), 00119 _device_name(NULL), 00120 _quota(0), 00121 _num_rec(0), 00122 _rec_size(0), 00123 _initialize_device(true), // always for this test 00124 _options(NULL), 00125 _vid(1), 00126 retval(0) { } 00127 00128 ~smthread_user_t() { if(_options) delete _options; } 00129 00130 void run(); 00131 00132 // helpers for run() 00133 w_rc_t handle_options(); 00134 w_rc_t find_file_info(); 00135 w_rc_t create_the_file(); 00136 w_rc_t scan_the_file(); 00137 w_rc_t scan_the_root_index(); 00138 w_rc_t do_work(); 00139 w_rc_t do_init(); 00140 w_rc_t no_init(); 00141 00142 }; 00143 00144 /* 00145 * looks up file info in the root index 00146 */ 00147 w_rc_t 00148 smthread_user_t::find_file_info() 00149 { 00150 file_info_t info; 00151 W_DO(ssm->begin_xct()); 00152 00153 bool found; 00154 stid_t _root_iid; 00155 W_DO(ss_m::vol_root_index(_vid, _root_iid)); 00156 00157 smsize_t info_len = sizeof(info); 00158 const vec_t key_vec_tmp(file_info_t::key, strlen(file_info_t::key)); 00159 W_DO(ss_m::find_assoc(_root_iid, 00160 key_vec_tmp, 00161 &info, info_len, found)); 00162 if (!found) { 00163 cerr << "No file information found" <<endl; 00164 return RC(fcASSERT); 00165 } else { 00166 cerr << " found assoc " 00167 << file_info_t::key << " --> " << info << endl; 00168 } 00169 00170 W_DO(ssm->commit_xct()); 00171 00172 _start_rid = info.first_rid; 00173 _fid = info.fid; 00174 _rec_size = info.rec_size; 00175 _num_rec = info.num_rec; 00176 return RCOK; 00177 } 00178 00179 /* 00180 * This function either formats a new device and creates a 00181 * volume on it, or mounts an already existing device and 00182 * returns the ID of the volume on it. 00183 * 00184 * It's borrowed from elsewhere; it can handle mounting 00185 * an already existing device, even though in this main program 00186 * we don't ever do that. 00187 */ 00188 rc_t 00189 smthread_user_t::create_the_file() 00190 { 00191 file_info_t info; // will be made persistent in the 00192 // volume root index. 00193 00194 // create and fill file to scan 00195 cout << "Creating a file with " << _num_rec 00196 << " records of size " << _rec_size << endl; 00197 W_DO(ssm->begin_xct()); 00198 00199 // Create the file. Stuff its fid in the persistent file_info 00200 W_DO(ssm->create_file(_vid, info.fid, smlevel_3::t_regular)); 00201 rid_t rid; 00202 00203 _rec_size -= align(sizeof(int)); 00204 00205 /// each record will have its ordinal number in the header 00206 /// and zeros for data 00207 00208 char* dummy = new char[_rec_size]; 00209 char* dummy2 = new char[_rec_size]; 00210 char* dummy3 = new char[_rec_size]; 00211 char* dummy4 = new char[_rec_size]; 00212 memset(dummy, '\1', _rec_size); // compressible 00213 memset(dummy2, '\2', _rec_size); // not compressible 00214 memset(dummy3, '\3', _rec_size); // not compressible 00215 memset(dummy4, '\4', _rec_size); // not compressible 00216 for(smsize_t i=0; i < _rec_size; i++) { 00217 dummy2[i] = (char)(i%8); 00218 dummy3[i] = (dummy2[i] + 1)%8; 00219 dummy4[i] = (dummy2[i] - 1)%8; 00220 } 00221 00222 vec_t data(dummy, _rec_size); 00223 vec_t data2(dummy2, _rec_size); 00224 vec_t data3(dummy3, _rec_size); 00225 vec_t data4(dummy4, _rec_size); 00226 00227 for(int j=0; j < _num_rec; j++) 00228 { 00229 { 00230 w_ostrstream o(dummy, _rec_size); 00231 o << "Record number " << j << ends; 00232 w_assert1(o.c_str() == dummy); 00233 } 00234 // header contains record # 00235 int i = j; 00236 const vec_t hdr(&i, sizeof(i)); 00237 W_COERCE(ssm->create_rec(info.fid, hdr, 00238 _rec_size, data, rid)); 00239 cout << "Creating rec " << j << endl; 00240 00241 // Now modify the record a bunch of times 00242 // These should chew up log space pretty fast. 00243 for(int i=0; i < 200; i++) { 00244 W_DO(ssm->update_rec(rid, 0 /* start byte */, data2)); 00245 W_DO(ssm->update_rec(rid, 0 /* start byte */, data3)); 00246 W_DO(ssm->update_rec(rid, 0 /* start byte */, data4)); 00247 } 00248 if (j == 0) { 00249 info.first_rid = rid; 00250 } 00251 } 00252 cout << "Created all. First rid " << info.first_rid << endl; 00253 delete [] dummy; 00254 delete [] dummy2; 00255 delete [] dummy3; 00256 delete [] dummy4; 00257 info.num_rec = _num_rec; 00258 info.rec_size = _rec_size; 00259 00260 // record file info in the root index : this stores some 00261 // attributes of the file in general 00262 stid_t _root_iid; 00263 W_DO(ss_m::vol_root_index(_vid, _root_iid)); 00264 00265 const vec_t key_vec_tmp(file_info_t::key, strlen(file_info_t::key)); 00266 const vec_t info_vec_tmp(&info, sizeof(info)); 00267 W_DO(ss_m::create_assoc(_root_iid, 00268 key_vec_tmp, 00269 info_vec_tmp)); 00270 W_DO(ssm->commit_xct()); 00271 return RCOK; 00272 } 00273 00274 rc_t 00275 smthread_user_t::scan_the_root_index() 00276 { 00277 W_DO(ssm->begin_xct()); 00278 stid_t _root_iid; 00279 W_DO(ss_m::vol_root_index(_vid, _root_iid)); 00280 cout << "Scanning index " << _root_iid << endl; 00281 scan_index_i scan(_root_iid, 00282 scan_index_i::ge, vec_t::neg_inf, 00283 scan_index_i::le, vec_t::pos_inf, false, 00284 ss_m::t_cc_kvl); 00285 bool eof(false); 00286 int i(0); 00287 smsize_t klen(0); 00288 smsize_t elen(0); 00289 #define MAXKEYSIZE 100 00290 char * keybuf[MAXKEYSIZE]; 00291 file_info_t info; 00292 00293 do { 00294 w_rc_t rc = scan.next(eof); 00295 if(rc.is_error()) { 00296 cerr << "Error getting next: " << rc << endl; 00297 retval = rc.err_num(); 00298 return rc; 00299 } 00300 if(eof) break; 00301 00302 // get the key len and element len 00303 W_DO(scan.curr(NULL, klen, NULL, elen)); 00304 // Create vectors for the given lengths. 00305 vec_t key(keybuf, klen); 00306 vec_t elem(&info, elen); 00307 // Get the key and element value 00308 W_DO(scan.curr(&key, klen, &elem, elen)); 00309 00310 cout << "Key " << keybuf << endl; 00311 cout << "Value " 00312 << " { fid " << info.fid 00313 << " first_rid " << info.first_rid 00314 << " #rec " << info.num_rec 00315 << " rec size " << info.rec_size << " }" 00316 << endl; 00317 i++; 00318 } while (!eof); 00319 W_DO(ssm->commit_xct()); 00320 return RCOK; 00321 } 00322 00323 rc_t 00324 smthread_user_t::scan_the_file() 00325 { 00326 cout << "Scanning file " << _fid << endl; 00327 W_DO(ssm->begin_xct()); 00328 00329 scan_file_i scan(_fid); 00330 pin_i* cursor(NULL); 00331 bool eof(false); 00332 int i(0); 00333 00334 do { 00335 w_rc_t rc = scan.next(cursor, 0, eof); 00336 if(rc.is_error()) { 00337 cerr << "Error getting next: " << rc << endl; 00338 retval = rc.err_num(); 00339 return rc; 00340 } 00341 if(eof) break; 00342 00343 cout << "Record " << i << "/" << _num_rec 00344 << " Rid " << cursor->rid() << endl; 00345 vec_t header (cursor->hdr(), cursor->hdr_size()); 00346 int hdrcontents; 00347 header.copy_to(&hdrcontents, sizeof(hdrcontents)); 00348 cout << "Record hdr " << hdrcontents << endl; 00349 00350 const char *body = cursor->body(); 00351 w_assert1(cursor->body_size() == _rec_size); 00352 cout << "Record body " << body << endl; 00353 i++; 00354 } while (!eof); 00355 w_assert1(i == _num_rec); 00356 00357 W_DO(ssm->commit_xct()); 00358 return RCOK; 00359 } 00360 00361 rc_t 00362 smthread_user_t::do_init() 00363 { 00364 { 00365 devid_t devid; 00366 cout << "Formatting device: " << _device_name 00367 << " with a " << _quota << "KB quota ..." << endl; 00368 W_DO(ssm->format_dev(_device_name, _quota, true)); 00369 00370 cout << "Mounting device: " << _device_name << endl; 00371 // mount the new device 00372 u_int vol_cnt; 00373 W_DO(ssm->mount_dev(_device_name, vol_cnt, devid)); 00374 00375 cout << "Mounted device: " << _device_name 00376 << " volume count " << vol_cnt 00377 << " device " << devid 00378 << endl; 00379 00380 // generate a volume ID for the new volume we are about to 00381 // create on the device 00382 cout << "Generating new lvid: " << endl; 00383 W_DO(ssm->generate_new_lvid(_lvid)); 00384 cout << "Generated lvid " << _lvid << endl; 00385 00386 // create the new volume 00387 cout << "Creating a new volume on the device" << endl; 00388 cout << " with a " << _quota << "KB quota ..." << endl; 00389 00390 W_DO(ssm->create_vol(_device_name, _lvid, _quota, false, _vid)); 00391 cout << " with local handle(phys volid) " << _vid << endl; 00392 00393 } 00394 00395 W_DO(create_the_file()); 00396 return RCOK; 00397 } 00398 00399 rc_t 00400 smthread_user_t::no_init() 00401 { 00402 cout << "Using already-existing device: " << _device_name << endl; 00403 // mount already existing device 00404 devid_t devid; 00405 u_int vol_cnt; 00406 w_rc_t rc = ssm->mount_dev(_device_name, vol_cnt, devid); 00407 if (rc.is_error()) { 00408 cerr << "Error: could not mount device: " 00409 << _device_name << endl; 00410 return rc; 00411 } 00412 00413 // find ID of the volume on the device 00414 lvid_t* lvid_list; 00415 u_int lvid_cnt; 00416 W_DO(ssm->list_volumes(_device_name, lvid_list, lvid_cnt)); 00417 if (lvid_cnt == 0) { 00418 cerr << "Error, device has no volumes" << endl; 00419 exit(1); 00420 } 00421 _lvid = lvid_list[0]; 00422 delete [] lvid_list; 00423 00424 W_DO(find_file_info()); 00425 W_DO(scan_the_root_index()); 00426 W_DO(scan_the_file()); 00427 return RCOK; 00428 } 00429 00430 rc_t 00431 smthread_user_t::do_work() 00432 { 00433 if (_initialize_device) W_DO(do_init()); 00434 else W_DO(no_init()); 00435 return RCOK; 00436 } 00437 00438 /**\defgroup EGOPTIONS Example of setting up options. 00439 * This method creates configuration options, starts up 00440 * the storage manager, 00441 */ 00442 static option_t *logdir(NULL); 00443 w_rc_t smthread_user_t::handle_options() 00444 { 00445 option_t* opt_device_name = 0; 00446 option_t* opt_device_quota = 0; 00447 option_t* opt_num_rec = 0; 00448 00449 cout << "Processing configuration options ..." << endl; 00450 00451 // Create an option group for my options. 00452 // I use a 3-level naming scheme: 00453 // executable-name.server.option-name 00454 // Thus, the file will contain lines like this: 00455 // log_exceed.server.device_name : /tmp/example/device 00456 // *.server.device_name : /tmp/example/device 00457 // log_exceed.*.device_name : /tmp/example/device 00458 // 00459 const int option_level_cnt = 3; 00460 00461 _options = new option_group_t (option_level_cnt); 00462 if(!_options) { 00463 cerr << "Out of memory: could not allocate from heap." << 00464 endl; 00465 retval = 1; 00466 return RC(fcINTERNAL); 00467 } 00468 option_group_t &options(*_options); 00469 00470 W_COERCE(options.add_option("device_name", "device/file name", 00471 NULL, "device containg volume holding file to scan", 00472 true, option_t::set_value_charstr, 00473 opt_device_name)); 00474 00475 W_COERCE(options.add_option("device_quota", "# > 1000", 00476 "2000", "quota for device", 00477 false, option_t::set_value_long, 00478 opt_device_quota)); 00479 00480 // Default number of records to create is 1. 00481 W_COERCE(options.add_option("num_rec", "# > 0", 00482 "1", "number of records in file", 00483 true, option_t::set_value_long, 00484 opt_num_rec)); 00485 00486 // Have the SSM add its options to my group. 00487 W_COERCE(ss_m::setup_options(&options)); 00488 00489 cout << "Finding configuration option settings." << endl; 00490 00491 w_rc_t rc = init_config_options(options, "server", _argc, _argv); 00492 if (rc.is_error()) { 00493 usage(options); 00494 retval = 1; 00495 return rc; 00496 } 00497 cout << "Processing command line." << endl; 00498 00499 // Process the command line: looking for the "-h" flag 00500 int option; 00501 while ((option = getopt(_argc, _argv, "hi")) != -1) { 00502 switch (option) { 00503 case 'h' : 00504 usage(options); 00505 break; 00506 00507 default: 00508 usage(options); 00509 retval = 1; 00510 return RC(fcNOTIMPLEMENTED); 00511 break; 00512 } 00513 } 00514 { 00515 cout << "Checking for required options..."; 00516 /* check that all required options have been set */ 00517 w_ostrstream err_stream; 00518 w_rc_t rc = options.check_required(&err_stream); 00519 if (rc.is_error()) { 00520 cerr << "These required options are not set:" << endl; 00521 cerr << err_stream.c_str() << endl; 00522 return rc; 00523 } 00524 cout << "OK " << endl; 00525 } 00526 00527 // Grab the options values for later use by run() 00528 _device_name = opt_device_name->value(); 00529 _quota = strtol(opt_device_quota->value(), 0, 0); 00530 _num_rec = strtol(opt_num_rec->value(), 0, 0); 00531 00532 if(logdir==NULL) { 00533 W_DO(options.lookup("sm_logdir", false, logdir)); 00534 fprintf(stdout, "Found logdir %s\n", logdir->value()); 00535 } 00536 00537 return RCOK; 00538 } 00539 00540 void smthread_user_t::run() 00541 { 00542 w_rc_t rc = handle_options(); 00543 if(rc.is_error()) { 00544 retval = 1; 00545 return; 00546 } 00547 00548 // Now start a storage manager. 00549 cout << "Starting SSM and performing recovery ..." << endl; 00550 ssm = new ss_m(out_of_log_space, get_archived_log_file); 00551 if (!ssm) { 00552 cerr << "Error: Out of memory for ss_m" << endl; 00553 retval = 1; 00554 return; 00555 } 00556 00557 cout << "Getting SSM config info for record size ..." << endl; 00558 00559 sm_config_info_t config_info; 00560 W_COERCE(ss_m::config_info(config_info)); 00561 _rec_size = config_info.max_small_rec; // minus a header 00562 00563 // Subroutine to set up the device and volume and 00564 // create the num_rec records of rec_size. 00565 rc = do_work(); 00566 00567 if (rc.is_error()) { 00568 cerr << "Could not set up device/volume due to: " << endl; 00569 cerr << rc << endl; 00570 { 00571 w_ostrstream o; 00572 static sm_stats_info_t curr; 00573 00574 rc = ssm->gather_stats(curr); 00575 00576 o << curr.sm.abort_xct_cnt<< ends; 00577 fprintf(stdout, "log_exceed stats: abort_xct_cnt %s\n" , o.c_str()); 00578 } 00579 delete ssm; 00580 rc = RCOK; // force deletion of w_error_t info hanging off rc 00581 // otherwise a leak for w_error_t will be reported 00582 retval = 0; 00583 if(rc.is_error()) 00584 W_COERCE(rc); // avoid error not checked. 00585 return; 00586 } 00587 00588 00589 // Clean up and shut down 00590 cout << "\nShutting down SSM ..." << endl; 00591 delete ssm; 00592 00593 cout << "Finished!" << endl; 00594 00595 return; 00596 } 00597 00598 // This was copied from file_scan so it has lots of extra junk 00599 int 00600 main(int argc, char* argv[]) 00601 { 00602 smthread_user_t *smtu = new smthread_user_t(argc, argv); 00603 if (!smtu) 00604 W_FATAL(fcOUTOFMEMORY); 00605 00606 w_rc_t e = smtu->fork(); 00607 if(e.is_error()) { 00608 cerr << "error forking thread: " << e <<endl; 00609 return 1; 00610 } 00611 e = smtu->join(); 00612 if(e.is_error()) { 00613 cerr << "error forking thread: " << e <<endl; 00614 return 1; 00615 } 00616 00617 int rv = smtu->retval; 00618 delete smtu; 00619 00620 return rv; 00621 } 00622 00623 #include <os_interface.h> 00624 00625 void dump() 00626 { 00627 00628 os_dirent_t *dd = NULL; 00629 os_dir_t ldir = os_opendir(logdir->value()); 00630 if(!ldir) { 00631 fprintf(stdout, "Could not open directory %s\n", logdir->value()); 00632 return; 00633 } 00634 fprintf(stdout, "---------------------- %s {\n", logdir->value()); 00635 while ((dd = os_readdir(ldir))) 00636 { 00637 fprintf(stdout, "%s\n", dd->d_name); 00638 } 00639 os_closedir(ldir); 00640 fprintf(stdout, "---------------------- %s }\n", logdir->value()); 00641 } 00642 00643 00644 w_rc_t get_archived_log_file ( 00645 const char *filename, 00646 ss_m::partition_number_t num) 00647 { 00648 fprintf(stdout, 00649 "\n**************************************** RECOVER %s : %d\n", 00650 filename, num 00651 ); 00652 dump(); 00653 00654 w_rc_t rc; 00655 00656 static char O[smlevel_0::max_devname<<1]; 00657 strcat(O, filename); 00658 strcat(O, ".bak"); 00659 00660 static char N[smlevel_0::max_devname<<1]; 00661 strcat(N, filename); 00662 00663 int e = ::rename(O, N); 00664 if(e != 0) 00665 { 00666 fprintf(stdout, "Could not move %s to %s: error : %d %s\n", 00667 O, N, e, strerror(errno)); 00668 rc = RC2(smlevel_0::eOUTOFLOGSPACE, errno); 00669 } 00670 dump(); 00671 fprintf(stdout, "recovered ... OK!\n\n"); 00672 fprintf(stdout, 00673 "This recovery of the log file will enable us to finish the abort.\n"); 00674 fprintf(stdout, 00675 "It will not continue the device/volume set up.\n"); 00676 fprintf(stdout, 00677 "Expect an error message and stack trace about that:\n\n"); 00678 return rc; 00679 } 00680 w_rc_t out_of_log_space ( 00681 xct_i* iter, 00682 xct_t *& xd, 00683 smlevel_0::fileoff_t curr, 00684 smlevel_0::fileoff_t thresh, 00685 const char *filename 00686 ) 00687 { 00688 static int calls=0; 00689 00690 calls++; 00691 00692 w_rc_t rc; 00693 fprintf(stdout, "\n**************************************** %d\n", calls); 00694 dump(); 00695 00696 fprintf(stdout, 00697 "Called out_of_log_space with curr %lld thresh %lld, file %s\n", 00698 (long long) curr, (long long) thresh, filename); 00699 { 00700 w_ostrstream o; 00701 o << xd->tid() << endl; 00702 fprintf(stdout, "called with xct %s\n" , o.c_str()); 00703 } 00704 00705 xd->log_warn_disable(); 00706 iter->never_mind(); // release the mutex 00707 00708 { 00709 w_ostrstream o; 00710 static sm_stats_info_t curr; 00711 00712 W_DO( ssm->gather_stats(curr)); 00713 00714 o << curr.sm.log_bytes_generated << ends; 00715 fprintf(stdout, "stats: log_bytes_generated %s\n" , o.c_str()); 00716 } 00717 xct_t *oldxct(NULL); 00718 lsn_t target; 00719 { 00720 w_ostrstream o; 00721 o << "Active xcts: " << xct_t::num_active_xcts() << " "; 00722 00723 tid_t old = xct_t::oldest_tid(); 00724 o << "Oldest transaction: " << old; 00725 00726 xct_t *x = xct_t::look_up(old); 00727 if(x==NULL) { 00728 fprintf(stdout, "Could not find %s\n", o.c_str()); 00729 W_FATAL(fcINTERNAL); 00730 } 00731 00732 target = x->first_lsn(); 00733 o << " First lsn: " << x->first_lsn(); 00734 o << " Last lsn: " << x->last_lsn(); 00735 00736 fprintf(stdout, "%s\n" , o.c_str()); 00737 00738 oldxct = x; 00739 } 00740 00741 if(calls > 3) { 00742 // See what happens... 00743 static tid_t aborted_tid; 00744 if(aborted_tid == xd->tid()) { 00745 w_ostrstream o; 00746 o << aborted_tid << endl; 00747 fprintf(stdout, 00748 "Multiple calls with same victim! : %s total calls %d\n", 00749 o.c_str(), calls); 00750 W_FATAL(smlevel_0::eINTERNAL); 00751 } 00752 aborted_tid = xd->tid(); 00753 fprintf(stdout, "\n\n******************************** ABORTING\n\n"); 00754 return RC(smlevel_0::eUSERABORT); // sm will abort this guy 00755 } 00756 00757 fprintf(stdout, "\n\n******************************** ARCHIVING \n\n"); 00758 fprintf(stdout, "Move aside log file log.%d to log.%d.bak\n", 00759 target.file(), target.file()); 00760 static char O[smlevel_0::max_devname<<1]; 00761 strcat(O, filename); 00762 static char N[smlevel_0::max_devname<<1]; 00763 strcat(N, filename); 00764 strcat(N, ".bak"); 00765 00766 int e = ::rename(O, N); 00767 if(e != 0) { 00768 fprintf(stdout, "Could not move %s to %s: error : %d %s\n", 00769 O, N, e, strerror(errno)); 00770 if(errno == ENOENT) { 00771 fprintf(stdout, "Ignored error.\n\n"); 00772 return RCOK; // just to ignore these. 00773 } 00774 fprintf(stdout, "Returning eOUTOFLOGSPACE.\n\n"); 00775 rc = RC2(smlevel_0::eOUTOFLOGSPACE, errno); 00776 } else { 00777 dump(); 00778 fprintf(stdout, "archived ... OK\n\n"); 00779 W_COERCE(ss_m::log_file_was_archived(filename)); 00780 } 00781 return rc; 00782 }