Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

Recovery.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 //
00020 // Recovery.C
00021 // Last modified on Fri Apr 22 11:33:07 EDT 2005 by ken@xorian.net        
00022 //      modified on Mon Aug  5 17:57:28 EDT 2002 by kcschalk@shr.intel.com
00023 //      modified on Wed Mar 15 17:58:55 PST 2000 by mann
00024 //
00025 // Code to drive recovery from log for repository server
00026 // 
00027 
00028 #include "VestaLog.H"
00029 #include "Recovery.H"
00030 #include <ctype.h>
00031 #include <stdlib.h>
00032 #include <errno.h>
00033 
00034 using std::istream;
00035 
00036 // Methods for RecoveryReader
00037 RecoveryReader::RecoveryReader(VestaLog* vl) throw ()
00038 {
00039     vl_ = vl;
00040     is_ = NULL;
00041 }
00042 
00043 RecoveryReader::RecoveryReader(istream* is) throw ()
00044 {
00045     vl_ = NULL;
00046     is_ = is;
00047 }
00048 
00049 void
00050 RecoveryReader::get(char &c) throw(VestaLog::Eof, VestaLog::Error)
00051 {
00052     if (vl_ != NULL) {
00053         vl_->get(c);
00054     } else {
00055         if (is_->get(c)) return;
00056         if (is_->bad())
00057           throw VestaLog::Error(errno, Text("RecoveryReader::get got \"") +
00058                                 Basics::errno_Text(errno) + "\" on read");
00059         throw VestaLog::Eof();
00060     }
00061 }
00062 
00063 void
00064 RecoveryReader::get(char* p, int n, char term)
00065   throw(VestaLog::Eof, VestaLog::Error)
00066 {
00067     if (vl_ != NULL) {
00068         vl_->get(p, n, term);
00069     } else {
00070         if (is_->get(p, n, term)) return;
00071         if (is_->bad())
00072           throw VestaLog::Error(errno, Text("RecoveryReader::get got \"") +
00073                                 Basics::errno_Text(errno) + "\" on read");
00074         throw VestaLog::Eof();
00075     }
00076 }
00077 
00078 int
00079 RecoveryReader::read(char* p, int n) throw(VestaLog::Error)
00080 {
00081     if (vl_ != NULL) {
00082         return vl_->read(p, n);
00083     } else {
00084         if (is_->read(p, n)) {
00085             return n;
00086         } else if (is_->bad()) {
00087             throw VestaLog::Error(errno, Text("RecoveryReader::read got \"") +
00088                                   Basics::errno_Text(errno) + "\" on read");
00089         } else {
00090             return is_->gcount();
00091         }
00092     }
00093 }
00094 
00095 void
00096 RecoveryReader::readAll(char* p, int n) throw(VestaLog::Eof, VestaLog::Error)
00097 {
00098     if (vl_ != NULL) {
00099         vl_->readAll(p, n);
00100         return;
00101     } else {
00102         if (is_->read(p, n)) {
00103             return;
00104         } else if (is_->bad()) {
00105             throw VestaLog::Error(errno,
00106                                   Text("RecoveryReader::readAll got \"") +
00107                                   Basics::errno_Text(errno) + "\" on read");
00108         } else {
00109             throw VestaLog::Eof();
00110         }
00111     }
00112 }
00113 
00114 bool
00115 RecoveryReader::eof() throw(VestaLog::Error)
00116 {
00117     if (vl_ != NULL) {
00118         return vl_->eof();
00119     } else if (is_->peek() == EOF) {
00120         if (is_->bad()) {
00121             throw VestaLog::Error(errno,
00122                                   Text("RecoveryReader::eof got \"") +
00123                                   Basics::errno_Text(errno) + "\" on peek");
00124         }
00125         return true;
00126     }
00127     return false;
00128 }
00129 
00130 // Helper routines for RecoverFrom.  The c argument is a lookahead
00131 // character, already read from the reader but not yet used.
00132 
00133 void
00134 RecoveryReader::skipWhite(char& c) throw(VestaLog::Eof, VestaLog::Error)
00135 {
00136     while (isspace(c)) {
00137         this->get(c);
00138     }
00139 }       
00140 
00141 void
00142 RecoveryReader::requireChar(char& c, char required)
00143   throw(VestaLog::Eof, VestaLog::Error)
00144 {
00145     this->skipWhite(c);
00146     if (c != required) {
00147         throw VestaLog::Error(0, Text("RecoveryReader::requireChar: ") +
00148                               "expected '" + required + "'; got '" + c + "'");
00149     }
00150     this->get(c);
00151 }       
00152 
00153 void
00154 RecoveryReader::getIdent(char& c, Ident id)
00155   throw(VestaLog::Eof, VestaLog::Error)
00156 {
00157     int guard = sizeof(Ident) - 1;
00158     char* p = &id[0];
00159     this->skipWhite(c);
00160     while (isalnum(c)) {
00161         if (guard-- <= 0) {
00162             id[sizeof(Ident) - 1] = '\0';
00163             throw VestaLog::Error(0, Text("RecoveryReader::getIdent: ") +
00164                                   "ident too long: " + id + "...");
00165         }
00166         *p++ = c;
00167         this->get(c);
00168     }
00169     *p = '\0';
00170 }       
00171 
00172 void
00173 RecoveryReader::getLong(char& c, long& n)
00174   throw(VestaLog::Eof, VestaLog::Error)
00175 {
00176     char digits[256]; // arbitrary limit on number length
00177     char *endptr;
00178     int guard = sizeof(digits) - 1;
00179     char* p = &digits[0];
00180     this->skipWhite(c);
00181     while (isxdigit(c) || c == 'x' || c == 'X' || c == '-' || c == '+') {
00182         if (guard-- <= 0) {
00183             digits[sizeof(Ident) - 1] = '\0';
00184             throw VestaLog::Error(0, Text("RecoveryReader::getLong: ") +
00185                                   "number too long: " + digits + "...");
00186         }
00187         *p++ = c;
00188         this->get(c);
00189     }
00190     *p = '\0';
00191     n = strtol(digits, &endptr, 0);
00192     if (*endptr != '\0') {
00193         n = 0;
00194         throw VestaLog::Error(0, Text("RecoveryReader::getLong: ") +
00195                               "garbled number: " + digits);
00196     }
00197 }
00198 
00199 void
00200 RecoveryReader::getULong(char& c, unsigned long& n)
00201   throw(VestaLog::Eof, VestaLog::Error)
00202 {
00203     char digits[256]; // arbitrary limit on number length
00204     char *endptr;
00205     int guard = sizeof(digits) - 1;
00206     char* p = &digits[0];
00207     this->skipWhite(c);
00208     while (isxdigit(c) || c == 'x' || c == 'X' || c == '-' || c == '+') {
00209         if (guard-- <= 0) {
00210             digits[sizeof(Ident) - 1] = '\0';
00211             throw VestaLog::Error(0, Text("RecoveryReader::getULong: ") +
00212                                   "number too long: " + digits + "...");
00213         }
00214         *p++ = c;
00215         this->get(c);
00216     }
00217     *p = '\0';
00218     n = strtoul(digits, &endptr, 0);
00219     if (*endptr != '\0') {
00220         n = 0;
00221         throw VestaLog::Error(0, Text("RecoveryReader::getULong: ") +
00222                               "garbled number: " + digits);
00223     }
00224 }
00225 
00226 void
00227 RecoveryReader::getLongId(char& c, Byte32& value)
00228   throw(VestaLog::Eof, VestaLog::Error)
00229 {
00230     int i;
00231     char chr[3];
00232     chr[2] = '\000';
00233     this->skipWhite(c);
00234     if (!isxdigit(c)) {
00235         throw VestaLog::Error(0, Text("RecoveryReader::getLongId: ") +
00236                               "bad LongId: " + c + "...");
00237     }
00238     for (i=0; i<32; i++) {
00239         if (!isxdigit(c)) break;
00240         int byte;
00241         chr[0] = c;
00242         this->get(c);
00243         if (isxdigit(c)) {
00244             chr[1] = c;
00245             this->get(c);
00246         } else {
00247             chr[1] = '0';
00248         }
00249         value.byte[i] = strtol(chr, NULL, 16);
00250     }
00251     for (; i<32; i++) {
00252         value.byte[i] = 0;
00253     }
00254 }
00255 
00256 void
00257 RecoveryReader::getQuotedString(char& c, char* buf, int maxLen)
00258   throw(VestaLog::Eof, VestaLog::Error)
00259 {
00260     this->skipWhite(c);
00261     this->requireChar(c, '\"');
00262     char *p = buf;
00263     while (maxLen > 0) {
00264         if (c == '\\') {
00265             this->get(c);
00266             *p++ = c;
00267             maxLen--;
00268             this->get(c);
00269         } else if (c == '\"') {
00270             *p = '\000';
00271             this->get(c);
00272             return;
00273         } else if (c == '\000') {
00274             *p = '\000';
00275             throw
00276               VestaLog::Error(0, Text("RecoveryReader::getQuotedString: ") +
00277                               "illegal null character after: " + buf);
00278         } else {
00279             *p++ = c;
00280             maxLen--;
00281             this->get(c);
00282         }
00283     }
00284     *--p = '\000';  // overwrite last character to null-terminate string
00285     throw VestaLog::Error(0, Text("RecoveryReader::getQuotedString: ") +
00286                           "string too long: " + buf + "...\n");
00287 }
00288 
00289 void
00290 RecoveryReader::getNewQuotedString(char& c, char*& string)
00291   throw(VestaLog::Eof, VestaLog::Error)
00292 {
00293     this->skipWhite(c);
00294     this->requireChar(c, '\"');
00295     int stringLen = 64;
00296     int len = 0;
00297     char* p = string = NEW_PTRFREE_ARRAY(char, stringLen);
00298     for (;;) {
00299         while (len < stringLen) {
00300             if (c == '\\') {
00301                 this->get(c);
00302                 *p++ = c;
00303                 len++;
00304                 this->get(c);
00305             } else if (c == '\"') {
00306                 *p = '\000';
00307                 this->get(c);
00308                 return;
00309             } else if (c == '\000') {
00310                 *p = '\000';
00311                 VestaLog::Error
00312                   f(0, Text("RecoveryReader::getNewQuotedString: ") +
00313                     "illegal null character after: " + string);
00314                 delete [] string;
00315                 throw f;
00316             } else {
00317                 *p++ = c;
00318                 len++;
00319                 this->get(c);
00320             }
00321         }
00322         // realloc, the hard way :-)
00323         int oldLen = stringLen;
00324         char *oldString = string;
00325         stringLen *= 2;
00326         string = NEW_PTRFREE_ARRAY(char, stringLen);
00327         memcpy(string, oldString, oldLen);
00328         delete [] oldString;
00329 
00330         p = &string[len];
00331     }
00332 }
00333 
00334 struct RecoveryDispatch {
00335     RecoveryDispatch* next;
00336     char* id;
00337     RecoveryCallback* rc;
00338 };
00339 
00340 // No locking here because the data is constant after initialization
00341 static RecoveryDispatch* RDHead;
00342 
00343 void
00344 RegisterRecoveryCallback(RecoveryReader::Ident id, RecoveryCallback* rc)
00345   throw ()
00346 {
00347   RecoveryDispatch* rd = NEW(RecoveryDispatch);
00348   rd->next = RDHead;
00349   rd->id = strdup(id);
00350   rd->rc = rc;
00351   RDHead = rd;
00352 }
00353 
00354 // Read records from a RecoveryReader, determine their type, and call
00355 // type-specific code to process them.  This code is used to process
00356 // both checkpoints and logs, because the repository server writes the
00357 // same types of records to both.  (Hence the need for the
00358 // RecoverReader wrapper class.)  Essentially this is a
00359 // recursive-descent parser for log records.  The types are so simple
00360 // that there isn't really any recursion, however.
00361 //
00362 void
00363 RecoverFrom(RecoveryReader* rr) throw(VestaLog::Error)
00364 {
00365     char c;
00366     RecoveryReader::Ident id;
00367 
00368     try {
00369         try {
00370             rr->get(c);         // Prime the pump
00371         } catch (VestaLog::Eof) {
00372             return;             // normal end of log
00373         }
00374         for (;;) {
00375             try {
00376                 rr->skipWhite(c);
00377             } catch (VestaLog::Eof) {
00378                 return;         // normal end of log
00379             }
00380             rr->requireChar(c, '(');
00381             rr->skipWhite(c);
00382             rr->getIdent(c, id);    
00383             
00384             // Dispatch on id
00385             RecoveryDispatch* rd = RDHead;
00386             for (;;) {
00387                 if (rd == NULL) {
00388                     throw VestaLog::Error(0,
00389                       Text("RecoveryReader::recoverFrom: unknown record type ")
00390                       + id);
00391                 }
00392                 if (strcmp(id, rd->id) == 0) {
00393                     rd->rc(rr, c);
00394                     break;
00395                 }
00396                 rd = rd->next;
00397             }
00398             
00399             try {
00400                 rr->requireChar(c, ')');
00401             } catch (VestaLog::Eof) {
00402                 return;         // log ends following the ')'; this is normal
00403             }
00404         }
00405     } catch (VestaLog::Eof) {
00406         throw VestaLog::Error(0,
00407           "RecoveryReader::recoverFrom: unexpected end of file");
00408     }
00409 }

Generated on Mon May 8 00:48:41 2006 for Vesta by  doxygen 1.4.2