w_rc_t sthread_t::cold_startup() { _class_list = new sthread_list_t(W_LIST_ARG(sthread_t, _class_link), &_class_list_lock); if (_class_list == 0) W_FATAL(fcOUTOFMEMORY); // initialize the global RNG struct timeval now; gettimeofday(&now, NULL); // Set the seed for the clib random-number generator, which // we use to seed the per-thread RNG ::srand(now.tv_usec); /* * Boot the main thread onto the current (system) stack. */ sthread_main_t *main = new sthread_main_t; if (!main) W_FATAL(fcOUTOFMEMORY); me_lval() = _main_thread = main; W_COERCE( main->fork() ); if (me() != main) W_FATAL(stINTERNAL); #if defined(PURIFY) /* The main thread is different from all other threads. */ purify_name_thread(me()->name()); #endif return RCOK; }
sthread_t::sthread_t(priority_t pr, const char *nm, unsigned stack_size) : sthread_named_base_t(nm), user(0), id(_next_id++), // make it match the gdb threads #. Origin 1 _start_terminate_lock(new pthread_mutex_t), _start_cond(new pthread_cond_t), _sleeping(false), _forked(false), _terminated(false), _unblock_flag(false), _core(0), _status(t_virgin), _priority(pr), _rce(stOK) { if(!_start_terminate_lock || !_start_cond ) W_FATAL(fcOUTOFMEMORY); DO_PTHREAD(pthread_cond_init(_start_cond, NULL)); DO_PTHREAD(pthread_mutex_init(_start_terminate_lock, NULL)); _core = new sthread_core_t; if (!_core) W_FATAL(fcOUTOFMEMORY); _core->sthread = (void *)this; // not necessary, but might // be useful for debugging /* * Set a valid priority level */ if (_priority > max_priority) _priority = max_priority; else if (_priority <= min_priority) _priority = min_priority; /* * Initialize the core. */ DO_PTHREAD(pthread_mutex_init(&_wait_lock, NULL)); DO_PTHREAD(pthread_cond_init(&_wait_cond, NULL)); /* * stash the procedure (sthread_t::_start) * and arg (this) * in the core structure, along with * status info. * and if this is not the _main_thread (running in * the system thread, i.e., in an already-running pthread) * then create a pthread for it and give it a starting function // TODO: should probably merge sthread_core_pthread.cpp in here */ if (sthread_core_init(_core, __start, this, stack_size) == -1) { cerr << "sthread_t: cannot initialize thread core" << endl; W_FATAL(stINTERNAL); } }
void smthread_t::_initialize_fingerprint() { // We can see if we might be getting false positives here. // If we make the finger print maps unique, we can eliminate that // possibility. #define DEBUG_FINGERPRINTS 0 #if DEBUG_FINGERPRINTS int tries=0; const int trylimit = 50; bool bad=true; while ( (bad = _try_initialize_fingerprint()) ) { _uninitialize_fingerprint(); if(++tries > trylimit) { fprintf(stderr, "Could not make non-overlapping fingerprint after %d tries; %d out of %d bits are inuse\n", tries, all_fingerprints.num_bits_set(), all_fingerprints.num_bits()); // note: there's a race here but if servers are // creating a pool of threads at start-up, this // is still useful info: if(all_fingerprints.is_full()) { fprintf(stderr, "collective thread map is full: increase #bits an recompile.\n"); } W_FATAL(smlevel_0::eTHREADMAPFULL); } } #else (void) _try_initialize_fingerprint(); #endif }
/********************************************************************* * * scan_index_i::finish() * * Terminate the scan. * *********************************************************************/ void scan_index_i::finish() { _eof = true; switch (ntype) { case t_btree: case t_uni_btree: case t_mrbtree: case t_uni_mrbtree: case t_mrbtree_l: case t_uni_mrbtree_l: case t_mrbtree_p: case t_uni_mrbtree_p: if (_btcursor) { delete _btcursor; _btcursor = 0; } break; case t_bad_ndx_t: // error must have occured during init break; default: W_FATAL(eINTERNAL); } }
void ErrLog::_openlogfile( const char *fn ) { const char *filename=fn; if(strcmp(filename, "-")==0) { // std::cerr << "log to stderr" << std::endl; _destination = log_to_stderr; _file = stderr; return; } if(filename) { _destination = log_to_unix_file; if(strncmp(filename, "unix:", 5) == 0) { filename += 5; } else if (strncmp(filename, "shore:", 6) == 0) { filename += 6; } _file = fopen(filename, "a+"); if(_file == NULL) { w_rc_t e = RC(fcOS); std::cerr << "Cannot fopen Unix file " << filename << std::endl; std::cerr << e << std::endl; W_COERCE(e); } } else { std::cerr << "Unknown logging destination." << std::endl; W_FATAL(fcINTERNAL); } }
int main(int argc, char **argv) { int i; int threads; if (parse_args(argc, argv) == -1) return 1; if (mix_it_up) threads = NumFloatThreads + NumIntThreads; else threads = NumFloatThreads > NumIntThreads ? NumFloatThreads : NumIntThreads; ack = new int[threads]; if (!ack) W_FATAL(fcOUTOFMEMORY); worker = new sthread_t *[threads]; if (!worker) W_FATAL(fcOUTOFMEMORY); for (i=0; i<NumIntThreads; ++i) { ack[i] = 0; worker[i] = new int_thread_t(i); w_assert1(worker[i]); W_COERCE( worker[i]->fork() ); } if (!mix_it_up) harvest(NumIntThreads); int base = mix_it_up ? NumIntThreads : 0; for(i=base ; i < base + NumFloatThreads; ++i){ ack[i] = 0; worker[i] = new float_thread_t(i); w_assert1(worker[i]); W_COERCE( worker[i]->fork() ); } harvest(mix_it_up ? threads : NumFloatThreads); delete [] worker; delete [] ack; return 0; }
NORET w_bitmap_t::w_bitmap_t(uint4_t size) : sz(size), mem_alloc(true) { int n = bytesForBits(size); ptr = new uint1_t[n] ; if (!ptr) W_FATAL(fcOUTOFMEMORY) ; }
void normal() { int i; int n; stime_test_t *raw; cout << "============ NORMAL ==================" << endl; raw = new stime_test_t[100]; if (!raw) W_FATAL(fcOUTOFMEMORY); n = 0; /* normal form w/ tod == 0 */ new (raw + n++) stime_test_t(0, 8); new (raw + n++) stime_test_t(0, -8); new (raw + n++) stime_test_t(0, hires + 8); new (raw + n++) stime_test_t(0, -hires - 9); /* normal form w/ non-zero tod */ new (raw + n++) stime_test_t(tod, 8); new (raw + n++) stime_test_t(tod, hires + 8); new (raw + n++) stime_test_t(-tod, -8); new (raw + n++) stime_test_t(-tod, -hires - 8); /* sign correction w/out normal */ new (raw + n++) stime_test_t(tod, 9); new (raw + n++) stime_test_t(tod, -9); new (raw + n++) stime_test_t(-tod, -9); new (raw + n++) stime_test_t(-tod, 9); /* sign correction w/ normal */ new (raw + n++) stime_test_t(tod, hires + 7); new (raw + n++) stime_test_t(tod, -hires - 7); new (raw + n++) stime_test_t(-tod, -hires - 7); new (raw + n++) stime_test_t(-tod, hires + 7); for (i = 0; i < n; i++) { stime_test_t _norm, norm; _norm = norm = raw[i]; _norm._normalize(); norm.normalize(); W_FORM(cout)("[%d] == ", i); cout << raw[i]; cout << " to " << _norm; if (norm != _norm) cout << " AND " << norm << " XXX"; cout << endl; } delete [] raw; }
void arithmetic() { int i; int n; stime_pair *raw; cout << "============ ARITHMETIC ==================" << endl; raw = new stime_pair[100]; if (!raw) W_FATAL(fcOUTOFMEMORY); n = 0; raw[n].l = stime_test_t(0, 8); raw[n++].r = stime_test_t(0, 5); raw[n].l = stime_test_t(1, hires-7); raw[n++].r = stime_test_t(1, 8); raw[n].l = stime_test_t(1, hires-7); raw[n++].r = stime_test_t(0, 8); raw[n].l = stime_test_t(1, 8); raw[n++].r = stime_test_t(-2, -9); cout << "================== add / subtract =============" << endl; for (i = 0; i < n; i++) { W_FORM(cout)("[%d] => ", i); cout << raw[i].l << " op "; cout << raw[i].r << ": "; cout << " +: " << (stime_test_t)(raw[i].l + raw[i].r); cout << ", +': " << (stime_test_t)(raw[i].r + raw[i].l); cout << ", -: " << (stime_test_t)(raw[i].l - raw[i].r); cout << ", -': " << (stime_test_t)(raw[i].r - raw[i].l); cout << endl; } cout << "================== scaling ==============" << endl; for (i = 0; i < n; i++) { W_FORM(cout)("[%d] => ", i); cout << raw[i].l; cout << " * " << (stime_test_t)(raw[i].l * 2); cout << " *' " << (stime_test_t)(raw[i].l * 2.0); cout << " / " << (stime_test_t)(raw[i].l / 2); cout << " /' " << (stime_test_t)(raw[i].l / 2.0); cout << endl; } delete [] raw; }
/********************************************************************* * * chkpt_m::spawn_chkpt_thread() * * Fork the checkpoint thread. * *********************************************************************/ void chkpt_m::spawn_chkpt_thread() { w_assert1(_chkpt_thread == 0); if (smlevel_0::log) { /* Create thread (1) to take checkpoints */ _chkpt_thread = new chkpt_thread_t; if (! _chkpt_thread) W_FATAL(eOUTOFMEMORY); W_COERCE(_chkpt_thread->fork()); } }
shpid_t lg_tag_chunks_h::_pid(uint4_t pid_num) const { FUNC(lg_tag_chunks_h::_pid); for (int i = 0; i < _cref.chunk_cnt; i++) { if (_cref.chunks[i].npages > pid_num) { return _cref.chunks[i].pid(pid_num); } pid_num -= _cref.chunks[i].npages; } W_FATAL(smlevel_0::eINTERNAL); return 0; // keep compiler quiet }
void ErrLog::_init2() { ErrLogInfo *ei; if((ei = _tab.search(this->_ident)) == 0) { ei = new ErrLogInfo(this); _tab.put_in_order(ei); // not really ordered } else { std::cerr << "An ErrLog called " << _ident << " already exists." << std::endl; W_FATAL(fcINTERNAL); } }
rc_t lid_m::generate_new_volid(lvid_t& lvid) { FUNC(lid_m::_generate_new_volid); /* * For now the logical volume ID will consists of * the machine network address and the current time-of-day. * * Since the time of day resolution is in seconds, * we protect this function with a mutex to guarantee we * don't generate duplicates. */ static long last_time = 0; const int max_name = 100; char name[max_name+1]; // Mutex only for generating new volume ids. static queue_based_block_lock_t lidmgnrt_mutex; CRITICAL_SECTION(cs, lidmgnrt_mutex); #ifdef HAVE_UTSNAME struct utsname uts; if (uname(&uts) == -1) return RC(eOS); strncpy(name, uts.nodename, max_name); #else if (gethostname(name, max_name)) return RC(eOS); #endif struct hostent* hostinfo = gethostbyname(name); if (!hostinfo) W_FATAL(eINTERNAL); memcpy(&lvid.high, hostinfo->h_addr, sizeof(lvid.high)); DBG( << "lvid " << lvid ); /* XXXX generating ids fast enough can create a id time sequence that grows way faster than real time! This could be a problem! Better time resolution than seconds does exist, might be worth using it. */ stime_t curr_time = stime_t::now(); if (curr_time.secs() > last_time) last_time = curr_time.secs(); else last_time++; lvid.low = last_time; return RCOK; }
void doErrorTests() { if (TestAssert) { OUT << endl << "** Generating an assertion failure." << endl; FLUSHOUT; w_assert1(false); } if (TestFatal) { OUT << endl << "** Generating a fatal error." << endl; FLUSHOUT; W_FATAL(fcINTERNAL); } }
/********************************************************************* * * logrec_t::type_str() * * Return a string describing the type of the log record. * *********************************************************************/ const char* logrec_t::get_type_str(kind_t type) { switch (type) { # include "logstr_gen.cpp" default: return 0; } /* * Not reached. */ W_FATAL(eINTERNAL); return 0; }
void smthread_t::attach_xct(xct_t* x) { // can't attach more than one xct to a thread // if called from sm, caller should have checked for this already, // but if called from vas directly, we need to check. if(tcb().xct != NULL) { W_FATAL(smlevel_0::eTWOTRANS); } tcb().xct = x; x->attach_thread(); // descends to xct_impl::attach_thread() // which grabs the 1thread mutex, calls new_xct, releases the mutex. }
void bf_prefetch_thread_t::new_state(int i, prefetch_event_t e) { FUNC(bf_prefetch_thread_t::new_state); // ASSUMES CALLER HAS THE MUTEX prefetch_status_t nw; prefetch_status_t old; bf_prefetch_thread_t::frame_info &inf = _info[i]; old = inf._status; if( (nw = _table[old][e]) == pf_fatal) { std::cerr << "Bad transition for state " << int(old) << " and event " << int(e) <<std::endl; W_FATAL(fcINTERNAL); } DBGTHRD(<< " change : _table[" << int(old) << "," << int(e) << "] ->" << int(nw)); inf._status = nw; if(old != nw) { switch(nw) { case pf_failure: w_assert3(_fix_error.is_error()); _fix_error_i = i; break; case pf_grabbed: w_assert3(_n == 2); DBGTHRD(<<"BUMPING INDEX from " << _f << " to " << (1-_f) ); _f = 1-_f; break; case pf_init: if(old != pf_failure) { inf._page.unfix(); } break; case pf_available: // Must unfix because the fetching thread // cannot do so. inf._page.unfix(); break; default: break; } } }
/* check all threads */ void sthread_t::check_all_stacks(const char *file, int line) { w_list_i<sthread_t, queue_based_lock_t> i(*_class_list); unsigned corrupt = 0; while (i.next()) { if (! i.curr()->isStackOK(file, line)) corrupt++; } if (corrupt > 0) { cerr << "sthread_t::check_all: " << corrupt << " thread stacks, dieing" << endl; W_FATAL(fcINTERNAL); } }
w_rc_t sthread_t::set_priority(priority_t priority) { CRITICAL_SECTION(cs, _wait_lock); _priority = priority; // in this statement, <= is used to keep gcc -Wall quiet if (_priority <= min_priority) _priority = min_priority; if (_priority > max_priority) _priority = max_priority; if (_status == t_ready) { cerr << "sthread_t::set_priority() :- " << "cannot change priority of ready thread" << endl; W_FATAL(stINTERNAL); } return RCOK; }
void smthread_t::detach_xct(xct_t* x) { // Had better have a thread from which to detach. // if called from sm, caller should have checked for this already, // but if called from vas directly, we need to check. if(tcb().xct == NULL) { W_FATAL(smlevel_0::eNOTRANS); } DBGTHRD(<<"detach: "); // descends to xct_impl::detach_thread() // which grabs the 1thread mutex, calls no_xct, releases the mutex. x->detach_thread(); tcb().xct = NULL; }
int main(int argc, char* argv[]) { smthread_main_t *smtu = new smthread_main_t(argc, argv); if (!smtu) W_FATAL(fcOUTOFMEMORY); w_rc_t e = smtu->fork(); if(e.is_error()) { cerr << "error forking thread: " << e <<endl; return 1; } e = smtu->join(); if(e.is_error()) { cerr << "error forking thread: " << e <<endl; return 1; } int rv = smtu->retval; delete smtu; return rv; }
/********************************************************************* * * chkpt_m::take() * * Take a checkpoint. A Checkpoint consists of: * 1. Checkpoint Begin Log (chkpt_begin) * 2. Checkpoint Device Table Log(s) (chkpt_dev_tab) * -- all mounted devices * 3. Checkpoint Buffer Table Log(s) (chkpt_bf_tab) * -- dirty page entries in bf and their recovery lsn * 4. Checkpoint Transaction Table Log(s) (chkpt_xct_tab) * -- active transactions and their first lsn * 5. Checkpoint Prepared Transactions (optional) * -- prepared transactions and their locks * (using the same log records that prepare does) * 6. Checkpoint End Log (chkpt_end) * *********************************************************************/ void chkpt_m::take() { FUNC(chkpt_m::take); if (! log) { /* * recovery facilities disabled ... do nothing */ return; } INC_TSTAT(log_chkpt_cnt); /* * Allocate a buffer for storing log records */ w_auto_delete_t<logrec_t> logrec(new logrec_t); /* * checkpoints are fuzzy * but must be serialized wrt each other. * * Acquire the mutex to serialize prepares and * checkpoints. * * NB: EVERYTHING BETWEEN HERE AND RELEASING THE MUTEX * MUST BE W_COERCE (not W_DO). */ chkpt_serial_m::chkpt_acquire(); retry: /* * FRJ: We must somehow guarantee that the log always has space to * accept checkpoints. We impose two constraints to this end: * * 1. We cap the total space checkpoints are allowed to consume in * any one log partition. This is a good idea anyway because * checkpoint size is linear in the number of dirty buffer pool * pages -- ~2MB per GB of dirty data -- and yet the utility of * checkpoints drops off quickly as the dirty page count * increases -- log analysis and recovery must start at the lsn * of the oldest dirty page regardless of how recent the * checkpoint was. * * 2. No checkpoint may depend on more than /max_openlog-1/ log * partitions. In other words, every checkpoint completion must * leave at least one log partition available. * * We use these two constraints, together with log reservations, * to guarantee the ability to reclaim log space if the log * becomes full. The log maintains, on our behalf, a reservation * big enough for two maximally-sized checkpoints (ie the dirty * page table lists every page in the buffer pool). Every time we * reclaim a log segment this reservation is topped up atomically. */ #define LOG_INSERT(constructor_call, rlsn) \ do { \ new (logrec) constructor_call; \ W_COERCE( log->insert(*logrec, rlsn) ); \ if(!log->consume_chkpt_reservation(logrec->length())) { \ W_FATAL(eOUTOFLOGSPACE); \ } \ } while(0) /* if current partition is max_openlog then the oldest lsn we can tolerate is 2.0. We must flush all pages dirtied before that time and must wait until all transactions with an earlier start_lsn have ended (at worst they will abort if the log fills up before they can commit). TODO: use smlevel_0::log_warn_callback to notify the VAS in case old transactions are't currently active for some reason. Also, remember the current checkpoint count so we can see whether we get raced... */ // #warning "TODO use log_warn_callback in case old transactions aren't logging right now" long curr_pnum = log->curr_lsn().file(); long too_old_pnum = std::max(0l, curr_pnum - max_openlog+1); if(!log->verify_chkpt_reservation()) { /* Yikes! The log can't guarantee that we'll be able to complete any checkpoint after this one, so we must reclaim space even if the log doesn't seem to be full. */ long too_old_pnum = log->global_min_lsn().file(); if(too_old_pnum == curr_pnum) { // how/why did they reserve so much log space??? W_FATAL(eOUTOFLOGSPACE); } } /* We cannot proceed if any transaction has a too-low start_lsn; wait for them to complete before continuing. WARNING: we have to wake any old transactions which are waiting on locks, or we risk deadlocks where the lock holder waits on a full log while the old transaction waits on the lock. */ lsn_t oldest_valid_lsn = log_m::first_lsn(too_old_pnum+1); old_xct_tracker tracker; { xct_i it(true); // do acquire the xlist_mutex... while(xct_t* xd=it.next()) { lsn_t const &flsn = xd->first_lsn(); if(flsn.valid() && flsn < oldest_valid_lsn) { // poison the transaction and add it to the list... xd->force_nonblocking(); tracker.track(xd); } } } /* release the chkpt_serial to do expensive stuff We'll record the current checkpoint count so we can detect whether we get raced during the gap. */ long chkpt_stamp = _chkpt_count; chkpt_serial_m::chkpt_release(); // clear out all too-old pages W_COERCE(bf->force_until_lsn(oldest_valid_lsn, false)); /* hopefully the page cleaning took long enough that the old transactions all ended... */ if(!tracker.finished()) tracker.wait_for_all(); // raced? chkpt_serial_m::chkpt_acquire(); if(_chkpt_count != chkpt_stamp) goto retry; /* * Finally, we're ready to start the actual checkpoint! * * Write a Checkpoint Begin Log and record its lsn in master */ lsn_t master; LOG_INSERT(chkpt_begin_log(io->GetLastMountLSN()), &master); /* * Checkpoint the buffer pool dirty page table, and record * minimum of the recovery lsn of all dirty pages. * * We could do this (very slow) operation before grabbing the * checkpoint mutex because all pages can do is get younger by * being flushed; no page can become older than the min_rec_lsn * we record here ... however, we have to serialize checkpoints * because, although they are fuzzy, they cannot intermingle. * One must complete before another starts. Recovery relies * on it. Either everyone uses wakeup_and_take or they (dismount, * mount, etc) wait on this. * * The srv_log does wakeup_and_take() whenever a new partition is * opened, and it might be that a checkpoint is spanning a * partition. */ lsn_t min_rec_lsn = lsn_t::max; { int bfsz = bf->npages(); const int chunk = chkpt_bf_tab_t::max; w_auto_delete_array_t<lpid_t> pid(new lpid_t[chunk]); w_auto_delete_array_t<lsn_t> rec_lsn(new lsn_t[chunk]); w_assert1(pid && rec_lsn); int total_count = 0; for (int i = 0; i < bfsz; ) { /* * Loop over all buffer pages */ int count = chunk; // Have the minimum rec_lsn of the bunch // returned iff it's less than the value passed in W_COERCE( bf->get_rec_lsn(i, count, pid, rec_lsn, min_rec_lsn) ); if (count) { total_count+= count; /* * Write a Buffer Table Log */ LOG_INSERT(chkpt_bf_tab_log(count, pid, rec_lsn), 0); } } //fprintf(stderr, "Checkpoint found %d dirty pages\n", total_count); } /* * Checkpoint the dev mount table */ { /* * Log the mount table in "max loggable size" chunks. */ // XXX casts due to enums const int chunk = (int)max_vols > (int)chkpt_dev_tab_t::max ? (int)chkpt_dev_tab_t::max : (int)max_vols; int dev_cnt = io->num_vols(); int i; char **devs; devs = new char *[chunk]; if (!devs) W_FATAL(fcOUTOFMEMORY); for (i = 0; i < chunk; i++) { devs[i] = new char[max_devname+1]; if (!devs[i]) W_FATAL(fcOUTOFMEMORY); } vid_t *vids; vids = new vid_t[chunk]; if (!vids) W_FATAL(fcOUTOFMEMORY); for (i = 0; i < dev_cnt; i += chunk) { int ret; W_COERCE( io->get_vols(i, MIN(dev_cnt - i, chunk), devs, vids, ret)); if (ret) { /* * Write a Checkpoint Device Table Log */ // XXX The bogus 'const char **' cast is for visual c++ LOG_INSERT(chkpt_dev_tab_log(ret, (const char **) devs, vids), 0); } } delete [] vids; for (i = 0; i < chunk; i++) delete [] devs[i]; delete [] devs; } /* * Checkpoint the transaction table, and record * minimum of first_lsn of all transactions. */ lsn_t min_xct_lsn = lsn_t::max; { const int chunk = chkpt_xct_tab_t::max; tid_t youngest = xct_t::youngest_tid(); w_auto_delete_array_t<tid_t> tid(new tid_t[chunk]); w_auto_delete_array_t<xct_state_t> state(new xct_state_t[chunk]); w_auto_delete_array_t<lsn_t> last_lsn(new lsn_t[chunk]); w_auto_delete_array_t<lsn_t> undo_nxt(new lsn_t[chunk]); /* Keep the transaction list static while we write the state of prepared transactions. Without the lock the list could change underneath this checkpoint. Note that we are using the iterator without locking because we own the lock. FRJ: even though xct_i now locks in a fully safe way, we want to hold the mutex longer than it's in scope so we continue using manual locking. */ xct_i x(true); // true -> acquire the mutex const xct_t* xd = 0; do { int i = 0; while (i < chunk && (xd = x.next())) { /* * Loop over all transactions and record only * xcts that dirtied something. * Skip those that have ended but not yet * been destroyed. */ if( xd->state() == xct_t::xct_ended) { continue; } if (xd->first_lsn().valid()) { tid[i] = xd->tid(); state[i] = xd->state(); // // NOTE: aborting xcts are installed as active - // they will be aborted on restart if not ended // by the time we restart. if (state[i] == xct_t::xct_aborting) state[i] = xct_t::xct_active; // if (state[i] == xct_t::xct_prepared) { DBG(<< tid[i] <<" is prepared -- logging as active"); state[i] = xct_t::xct_active; } // ^^^^^^^^^^^^^^^^^^^^^^^^^^^ // don't worry - it // will be prepared in the next section. // this just makes recovery debug-checking // a little easier ///////////////////////////////////////// last_lsn[i] = xd->last_lsn(); undo_nxt[i] = xd->undo_nxt(); if (min_xct_lsn > xd->first_lsn()) min_xct_lsn = xd->first_lsn(); i++; } } /* // We *always* have to write this record, because we have // to record the youngest xct!!!! NEH // if (i) */ { /* * Write a Transaction Table Log */ LOG_INSERT(chkpt_xct_tab_log(youngest, i, tid, state, last_lsn, undo_nxt), 0); } } while (xd);
/********************************************************************* * * scan_index_i::_fetch(key, klen, el, elen, skip) * * Fetch current entry into "key" and "el". If "skip" is true, * advance the scan to the next qualifying entry. * *********************************************************************/ rc_t scan_index_i::_fetch( vec_t* key, smsize_t* klen, vec_t* el, smsize_t* elen, bool skip) { // Check if error condition occured. if (_error_occurred.is_error()) { if(_error_occurred.err_num() == eBADCMPOP) { _eof = true; return RCOK; } return w_rc_t(_error_occurred); } SM_PROLOGUE_RC(scan_index_i::_fetch, in_xct, read_only, 0); /* * Check if scan is terminated. */ if (_finished) { return RC(eBADSCAN); } if (_eof) { return RC(eEOF); } w_assert1(xct()->tid() == tid); switch (ntype) { case t_btree: case t_uni_btree: case t_mrbtree: case t_uni_mrbtree: case t_mrbtree_l: case t_uni_mrbtree_l: case t_mrbtree_p: case t_uni_mrbtree_p: if (skip) { /* * Advance cursor. */ do { DBG(<<""); W_DO( bt->fetch(*_btcursor, _bIgnoreLatches) ); if(_btcursor->eof()) break; } while (_skip_nulls && (_btcursor->klen() == 0)); } break; case t_bad_ndx_t: default: W_FATAL(eINTERNAL); } /* * Copy result to user buffer. */ if (_btcursor->eof()) { DBG(<<"eof"); _eof = true; } else {
TEST (ThreadTest1, All) { int i; if (NumThreads) { ack = new int[NumThreads]; if (!ack) W_FATAL(fcOUTOFMEMORY); worker = new worker_thread_t *[NumThreads]; if (!worker) W_FATAL(fcOUTOFMEMORY); /* print some stuff */ for(i=0; i<NumThreads; ++i) { OUT << "creating i= " << i << endl; FLUSHOUT; ack[i] = 0; worker[i] = new worker_thread_t(i); EXPECT_TRUE(worker[i] != NULL); EXPECT_FALSE(worker[i]->fork().is_error()); OUT << "forked i= " << i << endl; FLUSHOUT; } if (DumpThreads) { OUT << ""; sthread_t::dumpall("dump", _out); FLUSHOUT; } ::usleep(2); for(i=0; i<NumThreads; ++i) { OUT << "joining i= " << i << endl; FLUSHOUT; EXPECT_FALSE( worker[i]->join().is_error() ); EXPECT_TRUE(ack[i] != 0); if (DumpThreads) { OUT << "Thread Done:" << endl << *worker[i] << endl; FLUSHOUT; } OUT << "deleting thread i= " << i << endl; FLUSHOUT; delete worker[i]; worker[i] = 0; } delete [] worker; delete [] ack; } ::usleep(2); if (PongTimes || PongGames) playPong(); ::usleep(2); if (SleepTime) { OUT << "SleepTime " << SleepTime << endl; FLUSHOUT; timer_thread_t* timer_thread = new timer_thread_t; EXPECT_TRUE(timer_thread != NULL); EXPECT_FALSE( timer_thread->fork().is_error() ); OUT << "Timer thread forked " << endl; FLUSHOUT; EXPECT_FALSE( timer_thread->join().is_error() ); OUT << "Timer thread joined " << endl; FLUSHOUT; if (DumpThreads) { OUT << "Timer Thread Done:" << endl << *timer_thread << endl; FLUSHOUT; } delete timer_thread; } if (StackOverflow) { overflow_thread_t *overflow = new overflow_thread_t; EXPECT_TRUE(overflow != NULL); OUT << "forking overflow_thread_t " << endl; FLUSHOUT; EXPECT_FALSE(overflow->fork().is_error()); EXPECT_FALSE(overflow->join().is_error()); delete overflow; } if (TestAssert || TestFatal) { if (TestErrorInThread) { error_thread_t *error = new error_thread_t; EXPECT_TRUE (error != NULL); OUT << "forking error_thread_t " << endl; FLUSHOUT; EXPECT_FALSE(error->fork().is_error()); EXPECT_FALSE(error->join().is_error()); delete error; } else { OUT << "Errors testing in main thread" << endl; FLUSHOUT; doErrorTests(); } } if (verbose) { sthread_t::dump_stats(cout); } }
/********************************************************************* * * scan_index_i::_init(cond, b1, c2, b2) * * Initialize a scan. Called by all constructors. * * Of which there is only 1, and it uses mode=SH * *********************************************************************/ void scan_index_i::_init( cmp_t cond, const cvec_t& bound, cmp_t c2, const cvec_t& b2, lock_mode_t mode, const bool bIgnoreLatches) { _finished = false; /* * Determine index and kvl lock modes. */ lock_mode_t index_lock_mode; concurrency_t key_lock_level; // _cc was passed in on constructor // Disallow certain kinds of scans on certain // kinds of indexes: // switch(_cc) { case t_cc_none: index_lock_mode = lock_m::parent_mode[mode]; // IS if mode == SH key_lock_level = t_cc_none; break; case t_cc_im: case t_cc_kvl: index_lock_mode = lock_m::parent_mode[mode]; // IS if mode==SH key_lock_level = _cc; break; case t_cc_modkvl: index_lock_mode = lock_m::parent_mode[mode]; // IS if mode==SH // GROT: force the checks below to // check scan conditions key_lock_level = t_cc_none; break; case t_cc_file: index_lock_mode = mode; key_lock_level = t_cc_none; break; case t_cc_append: default: _error_occurred = RC(eBADLOCKMODE); return; break; } /* * Save tid */ tid = xct()->tid(); /* * Access directory entry */ sdesc_t* sd = 0; _error_occurred = dir->access(_stid, sd, index_lock_mode); if (_error_occurred.is_error()) { return; } if (sd->sinfo().stype != t_index) { _error_occurred = RC(eBADSTORETYPE); return; } if((concurrency_t)sd->sinfo().cc != key_lock_level) { switch((concurrency_t)sd->sinfo().cc) { case t_cc_none: // allow anything break; case t_cc_modkvl: // certain checks are made in fetch_init if(_cc == t_cc_none || _cc == t_cc_file) { key_lock_level = t_cc_none; } else { key_lock_level = (concurrency_t)sd->sinfo().cc; } break; case t_cc_im: case t_cc_kvl: // allow file if(_cc == t_cc_file) { key_lock_level = t_cc_file; break; } key_lock_level = (concurrency_t)sd->sinfo().cc; break; default: _error_occurred = RC(eBADCCLEVEL); return; } } /* * Initialize the fetch */ switch (ntype = (ndx_t) sd->sinfo().ntype) { case t_bad_ndx_t: _error_occurred = RC(eBADNDXTYPE); return; case t_btree: case t_uni_btree: { _btcursor = new bt_cursor_t(!_skip_nulls); if (! _btcursor) { _error_occurred = RC(eOUTOFMEMORY); return; } bool inclusive = (cond == eq || cond == ge || cond == le); cvec_t* elem = 0; if(_btcursor->is_backward()) { elem = &(inclusive ? cvec_t::pos_inf : cvec_t::neg_inf); } else { elem = &(inclusive ? cvec_t::neg_inf : cvec_t::pos_inf); } _error_occurred = bt->fetch_init(*_btcursor, sd->root(), sd->sinfo().nkc, sd->sinfo().kc, ntype == t_uni_btree, key_lock_level, bound, *elem, cond, c2, b2, mode); if (_error_occurred.is_error()) { return; } /* if(_btcursor->is_backward()) { // Not fully supported _error_occurred = RC(eNOTIMPLEMENTED); return; } */ } break; case t_mrbtree: case t_uni_mrbtree: case t_mrbtree_l: case t_uni_mrbtree_l: case t_mrbtree_p: case t_uni_mrbtree_p: { _btcursor = new bt_cursor_t(!_skip_nulls); if (! _btcursor) { _error_occurred = RC(eOUTOFMEMORY); return; } bool inclusive = (cond == eq || cond == ge || cond == le); cvec_t* elem = 0; if(_btcursor->is_backward()) { elem = &(inclusive ? cvec_t::pos_inf : cvec_t::neg_inf); } else { elem = &(inclusive ? cvec_t::neg_inf : cvec_t::pos_inf); } // traverse all the subtrees that covers the region [bound,b2] std::vector<lpid_t> roots; cvec_t* bound_key; cvec_t* b2_key; _error_occurred = bt->_scramble_key(bound_key, bound, sd->sinfo().nkc, sd->sinfo().kc); char* bound_sc = (char*) malloc((*bound_key).size()); (*bound_key).copy_to(bound_sc, (*bound_key).size()); cvec_t b1(bound_sc, (*bound_key).size()); _error_occurred = bt->_scramble_key(b2_key, b2, sd->sinfo().nkc, sd->sinfo().kc); if(&bound == &vec_t::neg_inf && &b2 == &vec_t::pos_inf) { _error_occurred = sd->partitions().getAllPartitions(roots); } else { _error_occurred = sd->partitions().getPartitions(b1, *b2_key, roots); } _error_occurred = bt->mr_fetch_init(*_btcursor, roots, sd->sinfo().nkc, sd->sinfo().kc, ntype == t_uni_btree, key_lock_level, b1, *elem, cond, c2, *b2_key, mode, bIgnoreLatches); free(bound_sc); if (_error_occurred.is_error()) { return; } /* if(_btcursor->is_backward()) { // Not fully supported _error_occurred = RC(eNOTIMPLEMENTED); return; } */ } break; default: W_FATAL(eINTERNAL); } }
void chkpt_t::deserialize_binary(ifstream& ifs) { if(!ifs.is_open()) { cerr << "Could not open input stream for chkpt file" << endl;; W_FATAL(fcINTERNAL); } ifs.read((char*)&highest_tid, sizeof(tid_t)); size_t buf_tab_size; ifs.read((char*)&buf_tab_size, sizeof(size_t)); for(uint i=0; i<buf_tab_size; i++) { PageID pid; ifs.read((char*)&pid, sizeof(PageID)); buf_tab_entry_t entry; ifs.read((char*)&entry, sizeof(buf_tab_entry_t)); DBGOUT1(<<"pid[]="<<pid<< " , " << "rec_lsn[]="<<entry.rec_lsn<< " , " << "page_lsn[]="<<entry.page_lsn); // buf_tab[pid] = entry; mark_page_dirty(pid, entry.page_lsn, entry.rec_lsn); } size_t xct_tab_size; ifs.read((char*)&xct_tab_size, sizeof(size_t)); for(uint i=0; i<xct_tab_size; i++) { tid_t tid; ifs.read((char*)&tid, sizeof(tid_t)); xct_tab_entry_t entry; ifs.read((char*)&entry.state, sizeof(smlevel_0::xct_state_t)); ifs.read((char*)&entry.last_lsn, sizeof(lsn_t)); ifs.read((char*)&entry.first_lsn, sizeof(lsn_t)); DBGOUT1(<<"tid[]="<<tid<<" , " << "state[]="<<entry.state<< " , " << "last_lsn[]="<<entry.last_lsn<<" , " << "first_lsn[]="<<entry.first_lsn); if (entry.state != smlevel_0::xct_ended) { mark_xct_active(tid, entry.first_lsn, entry.last_lsn); if (is_xct_active(tid)) { size_t lock_tab_size; ifs.read((char*)&lock_tab_size, sizeof(size_t)); for(uint j=0; j<lock_tab_size; j++) { lock_info_t lock_entry; ifs.read((char*)&lock_entry, sizeof(lock_info_t)); // entry.locks.push_back(lock_entry); add_lock(tid, lock_entry.lock_mode, lock_entry.lock_hash); DBGOUT1(<< " lock_mode[]="<<lock_entry.lock_mode << " , lock_hash[]="<<lock_entry.lock_hash); } } // xct_tab[tid] = entry; } }
main(int argc, char **argv) { int numBits = 71; int numBytes; int i; int errors = 0; int iterations = 0; bool random_tests = false; bool stateless_tests = false; int c; while ((c = getopt(argc, argv, "n:ri:")) != EOF) { switch (c) { case 'n': /* number of bits */ numBits = atoi(optarg); break; case 'r': /* tests using random bit numbers; otherwise tests test all valid bit numbers in order */ random_tests = true; break; case 'i': /* iterations for each test */ iterations = atoi(optarg); break; default: errors++; break; } } if (errors) { W_FORM(cerr)("usage: %s [-n bits] [-r] [-i iterations]\n", argv[0]); return 1; } if (!iterations) iterations = random_tests ? 10000 : numBits; // tests must leave no state if probes are random, or will // repeat through the sample space stateless_tests = (random_tests || iterations > numBits); numBytes = (numBits - 1) / 8 + 1; u_char *map = new u_char[numBytes]; if (!map) W_FATAL(fcOUTOFMEMORY); W_FORM(cout)("test bitmap of %d bits, stored in %d bytes (%d bits).\n", numBits, numBytes, numBytes*8); for (i = 0; i < numBytes; i++) map[i] = rand(); cout << "Clear Map: "; errors = 0; bm_zero(map, numBits); for (i = 0; i < numBits; i++) { if (bm_is_set(map, i)) { cout << i << " "; errors++; break; } } cout << (errors ? "failed" : "passed") << endl << flush; cout << "Set Map: "; errors = 0; bm_fill(map, numBits); for (i = 0; i < numBits; i++) { if ( ! bm_is_set(map, i)) { cout << i << " "; errors++; break; } } cout << (errors ? "failed" : "passed") << endl << flush; cout << "Set: "; errors = 0; bm_zero(map, numBits); for (i = 0; i < iterations; i++) { int bit = (random_tests ? rand() : i) % numBits; bm_set(map, bit); if ( ! bm_is_set(map, bit) ) { cout << bit << " "; errors++; break; } } cout << (errors ? "failed" : "passed") << endl << flush; cout << "Clear: "; errors = 0; bm_fill(map, numBits); for (i = 0; i < iterations; i++) { int bit = (random_tests ? rand() : i) % numBits; bm_clr(map, bit); if (bm_is_set(map, bit)) { cout << bit << " "; errors++; break; } } cout << (errors ? "failed" : "passed") << endl << flush; cout << "First Set: "; errors = 0; bm_zero(map, numBits); for (i = 0; i < iterations; i++) { int bit = (random_tests ? rand() : i) % numBits; bm_set(map, bit); if (bm_first_set(map, numBits, 0) != bit) { cout << bit << " "; errors++; break; } if (bm_first_set(map, numBits, bit) != bit) { cout << bit << " "; errors++; break; } bm_clr(map, bit); } cout << (errors ? "failed" : "passed") << endl << flush; cout << "First Clear: "; errors = 0; bm_fill(map, numBits); for (i = 0; i < iterations; i++) { int bit = (random_tests ? rand() : i) % numBits; bm_clr(map, bit); if (bm_first_clr(map, numBits, 0) != bit) { cout << bit << " "; errors++; break; } if (bm_first_clr(map, numBits, bit) != bit) { cout << bit << " "; errors++; break; } bm_set(map, bit); } cout << (errors ? "failed" : "passed") << endl << flush; cout << "Last Set: "; errors = 0; bm_zero(map, numBits); for (i = 0; i < iterations; i++) { int bit = (random_tests ? rand() : i) % numBits; bm_set(map, bit); if (bm_last_set(map, numBits, numBits-1) != bit) { cout << bit << " "; errors++; break; } if (bm_last_set(map, numBits, bit) != bit) { cout << bit << " "; errors++; break; } if (stateless_tests) bm_clr(map, bit); } cout << (errors ? "failed" : "passed") << endl << flush; cout << "Last Clear: "; errors = 0; bm_fill(map, numBits); for (i = 0; i < iterations; i++) { int bit = (random_tests ? rand() : i) % numBits; bm_clr(map, bit); if (bm_last_clr(map, numBits, numBits-1) != bit) { cout << bit << " "; errors++; break; } if (bm_last_clr(map, numBits, bit) != bit) { cout << bit << " "; errors++; break; } if (stateless_tests) bm_set(map, bit); } cout << (errors ? "failed" : "passed") << endl << flush; cout << "Num Set: "; errors = 0; bm_zero(map, numBits); if (bm_num_set(map, numBits) != 0) { cout << "all "; errors++; } for (i = 0; i < numBits; i++) { bm_set(map, i); if (bm_num_set(map, numBits) != i+1) { cout << i << " "; errors++; break; } } cout << (errors ? "failed" : "passed") << endl << flush; cout << "Num Clear: "; errors = 0; bm_fill(map, numBits); if (bm_num_clr(map, numBits) != 0) { cout << "all "; errors++; } for (i = 0; i < numBits; i++) { bm_clr(map, i); if (bm_num_clr(map, numBits) != i+1) { cout << i << " "; errors++; break; } } cout << (errors ? "failed" : "passed") << endl << flush; delete [] map; cout << flush; }
bool lock_m::get_parent(const lockid_t& c, lockid_t& p) { switch (c.lspace()) { case lockid_t::t_vol: // no parent case lockid_t::t_extent: // no parent p.zero(); // sets type to t_bad break; case lockid_t::t_store: // parent of store is volume new (&p) lockid_t(c.vid()); break; case lockid_t::t_page: { // parent of page is store stid_t s; c.extract_stid(s); new (&p) lockid_t(s); } break; case lockid_t::t_kvl: { // parent of kvl is store? stid_t s; c.extract_stid(s); new (&p) lockid_t(s); } break; case lockid_t::t_record: { // parent of record is page lpid_t pg; c.extract_lpid(pg); new (&p) lockid_t(pg); } break; case lockid_t::t_user1: // no parent p.zero(); break; case lockid_t::t_user2: { lockid_t::user1_t u; c.extract_user1(u); new (&p) lockid_t(u); } break; case lockid_t::t_user3: { lockid_t::user2_t u; c.extract_user2(u); new (&p) lockid_t(u); } break; case lockid_t::t_user4: { lockid_t::user3_t u; c.extract_user3(u); new (&p) lockid_t(u); } break; default: W_FATAL(eINTERNAL); } DBGTHRD(<< "child:" << c << " parent: " << p ); #ifdef W_TRACE bool b = p.lspace() != lockid_t::t_bad; DBGTHRD(<< "get_parent returns " << b << " for parent type " << int(p.lspace()) ); #endif return p.lspace() != lockid_t::t_bad; }
w_rc_t out_of_log_space ( xct_i* iter, xct_t *& xd, smlevel_0::fileoff_t curr, smlevel_0::fileoff_t thresh, const char *filename ) { static int calls=0; calls++; w_rc_t rc; fprintf(stdout, "\n**************************************** %d\n", calls); dump(); fprintf(stdout, "Called out_of_log_space with curr %lld thresh %lld, file %s\n", (long long) curr, (long long) thresh, filename); { w_ostrstream o; o << xd->tid() << endl; fprintf(stdout, "called with xct %s\n" , o.c_str()); } xd->log_warn_disable(); iter->never_mind(); // release the mutex { w_ostrstream o; static sm_stats_info_t curr; W_DO( ssm->gather_stats(curr)); o << curr.sm.log_bytes_generated << ends; fprintf(stdout, "stats: log_bytes_generated %s\n" , o.c_str()); } lsn_t target; { w_ostrstream o; o << "Active xcts: " << xct_t::num_active_xcts() << " "; tid_t old = xct_t::oldest_tid(); o << "Oldest transaction: " << old; xct_t *x = xct_t::look_up(old); if(x==NULL) { fprintf(stdout, "Could not find %s\n", o.c_str()); W_FATAL(fcINTERNAL); } target = x->first_lsn(); o << " First lsn: " << x->first_lsn(); o << " Last lsn: " << x->last_lsn(); fprintf(stdout, "%s\n" , o.c_str()); } if(calls > 3) { // See what happens... static tid_t aborted_tid; if(aborted_tid == xd->tid()) { w_ostrstream o; o << aborted_tid << endl; fprintf(stdout, "Multiple calls with same victim! : %s total calls %d\n", o.c_str(), calls); W_FATAL(smlevel_0::eINTERNAL); } aborted_tid = xd->tid(); fprintf(stdout, "\n\n******************************** ABORTING\n\n"); return RC(smlevel_0::eUSERABORT); // sm will abort this guy } fprintf(stdout, "\n\n******************************** ARCHIVING \n\n"); fprintf(stdout, "Move aside log file log.%d to log.%d.bak\n", target.file(), target.file()); static char O[smlevel_0::max_devname<<1]; strcat(O, filename); static char N[smlevel_0::max_devname<<1]; strcat(N, filename); strcat(N, ".bak"); int e = ::rename(O, N); if(e != 0) { fprintf(stdout, "Could not move %s to %s: error : %d %s\n", O, N, e, strerror(errno)); if(errno == ENOENT) { fprintf(stdout, "Ignored error.\n\n"); return RCOK; // just to ignore these. } fprintf(stdout, "Returning eOUTOFLOGSPACE.\n\n"); rc = RC2(smlevel_0::eOUTOFLOGSPACE, errno); } else { dump(); fprintf(stdout, "archived ... OK\n\n"); W_COERCE(ss_m::log_file_was_archived(filename)); } return rc; }
istream & w_base_t::_scan_uint8( istream& i, w_base_t::uint8_t &u8, bool chew_white, // true if coming from istream operator bool is_signed, // if true, we have to return an error for overflow bool& range_err // set to true if range error occurred ) { w_base_t::uint8_t thresh=0, thresh2=0 /* thresh2, thresh3, thresh4 for decimal only */, thresh3=0, thresh4=0; w_base_t::uint8_t value = 0; bool negate = false; int e=0; int base=0; bool skip_white = true; states s = start; streampos tell_start = i.tellg(); int chewamt = chew_white? 1 : 0; XTABLE *table=0; range_err = false; { // Get the base from the stream ios_fmtflags old = i.flags(); skip_white = ((old & ios::skipws) != 0); switch(old & ios::basefield) { case 0: base = 0; table = &table_unknown; break; case ios::hex: base = 4; // shift by this table = &table_base16; thresh = is_signed? thresh_hex_signed : thresh_hex_unsigned; break; case ios::oct: base = 3; // shift by this table = &table_base8; thresh = is_signed? thresh_oct_signed : thresh_oct_unsigned; break; case ios::dec: base = 10; // multiply by this table = &table_base10; thresh = is_signed? thresh_dec_signed : thresh_dec_unsigned; thresh2 = is_signed? thresh2_dec_signed : thresh2_dec_unsigned; thresh3 = is_signed? (negate? 8: 7) : 5; thresh4 = is_signed? thresh_hex_signed : thresh_hex_unsigned; break; default: W_FATAL(fcINTERNAL); break; } } int ich; char ch; while (s < end) { ch = 0; // if (i) { ich = i.get(); if (ich != EOF) { ch = char(ich); /* By using isspace() we get locale-dependent behavior */ if(isspace(ch)) { e = white; } else { e = equiv[unsigned(ch)]; } } else e = eofile; // } else { // e = eofile; // } /* transition table */ s = (*table)[e][s]; switch(s) { case start: /* Have seen leading white space */ if(!skip_white) { s = end; } tell_start += chewamt; break; case sgned: if(ch == '-') { negate = true; if(thresh3!=0) thresh3 = is_signed? (negate? 8: 7) : 5; } break; case leadz: /* Have seen 1 or more leading zeroes * if base is 0 (unstated), 0 or 0x will * determine the base. */ break; case new_hex: /* State means we've seen [0][a-f] or 0[xX] */ if(base && (base != 4)) { /* consider this the end of the string */ IOS_BACK(i, ch); s = end; break; } w_assert9(base == 0 || base == 4); if((base == 0) && (e != exx)) { /* consider this the end of the string */ IOS_BACK(i, ch); s = end; break; } /* at this point, in the 0[xX] case, * we WILL make a conversion, * if nothing else, it will be to 0. In event * of error (the char after the [Xx] is not * a legit hex digit) we have to be able to * seek back to where the [Xx] was, rather than * leave the endptr at the offending digit. */ base = 4; // 2 ** base, i.e., shift amt if(e != exx) { IOS_BACK(i, ch); } else { /* XXX used to be tellg()-1, but no streampos arith allowed that way. */ tell_start = i.tellg(); tell_start -= 1; // for possible error-handling } thresh = is_signed? thresh_hex_signed : thresh_hex_unsigned; break; case new_oct: /* State means we've seen 0 followed by [1-7] */ if(base==0 || base == 3) { /* treat as oct # */ base = 3; // shift amt thresh = is_signed? thresh_oct_signed : thresh_oct_unsigned; } else if(base == 10) { s = new_dec; thresh = is_signed? thresh_dec_signed : thresh_dec_unsigned; thresh2= is_signed?thresh2_dec_signed : thresh2_dec_unsigned; thresh3 = is_signed? (negate? 8: 7) : 5; thresh4 = is_signed? thresh_hex_signed : thresh_hex_unsigned; } else { w_assert9(base == 4); s = new_hex; thresh = is_signed? thresh_hex_signed : thresh_hex_unsigned; } IOS_BACK(i, ch); break; case new_dec: /* State means we've seen [1-9] in start/sgned state * or 0 followed by [8-9] */ if(e == eight || e == nine) { if(base && base != 10) { /* consider this the end of the string */ IOS_BACK(i, ch); s = end; break; } } if(base==0 || base == 10) { /* treat as dec # */ base = 10; // multiply amt thresh = is_signed? thresh_dec_signed : thresh_dec_unsigned; thresh2= is_signed?thresh2_dec_signed : thresh2_dec_unsigned; thresh3 = is_signed? (negate? 8: 7) : 5; thresh4 = is_signed? thresh_hex_signed : thresh_hex_unsigned; } else if(base == 3) { s = new_oct; thresh = is_signed? thresh_oct_signed : thresh_oct_unsigned; } else { w_assert9(base == 4); thresh = is_signed? thresh_hex_signed : thresh_hex_unsigned; s = new_hex; } IOS_BACK(i, ch); break; case is_hex: w_assert9(base == 4); /* drop down */ case is_oct: if(value & thresh) { range_err = true; // keep parsing // s = end; break; } /* shift */ value <<= base; value += int(e); break; case is_dec: w_assert9(base == 10); if(value & thresh4) { if(value > thresh2) { /* will overflow on multiply */ range_err = true; // keep parsing // s = end; break; } value *= base; if((value - thresh2) + unsigned(e) > thresh3) { /* overflow adding in e */ range_err = true; // keep parsing // s = end; break; } } else { /* multiply */ value *= base; } value += unsigned(e); break; case error: IOS_FAIL(i); i.seekg(tell_start); s = end; break; case no_hex: i.seekg(tell_start); s = end; break; case end: IOS_BACK(i, ch); break; case no_state: W_FATAL(fcINTERNAL); break; } } if(range_err) { // don't seek to start u8 = negate ? ( is_signed? w_base_t::int8_min : w_base_t::uint8_max) : ( is_signed? w_base_t::int8_max : w_base_t::uint8_max); IOS_FAIL(i); } else { u8 = negate ? (0 - value) : value; } return i; }