[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
How to use the recovery class (class LineDB)
- To: gcdev <gcdev@sseos.lbl.gov>
- Subject: How to use the recovery class (class LineDB)
- From: Henrik Nordberg <hnordberg@lbl.gov>
- Date: Thu, 07 Jan 1999 18:02:27 -0800
- Organization: Lawrence Berkeley Laboratory, Berkeley, California
This email explains how to use the LineDB class for recovery after crashes.
QE is currently using it, so for more info, have a look at the QE code
(qe_i.cpp and estimator_i.cpp).
The usage consists of a few parts:
1. creation
2. recovery
3. logging of state
the two first ones are done once
the third one is done whenever the state of your object(s) change(s)
Here I only show how to use the parts of LineDB that are necessary to do
any recovery at all. There are some other functions that may be useful to
some people:
virtual void replace_line(char* key, char* line);
virtual void remove_line(char* key);
virtual char* get_line(char* key);
virtual char* get_key(char* line);
virtual bool lookup(char* key);
These are documented in linedb.cpp (in CVS/common).
Good luck,
- Henrik
Note: if there is an error anywhere, a char* is thrown. This might not be
the best choice, but that's the way it is for now. (I want to build a good
exception hierarchy in the future (R.S.N.))
// global variable
LineDB *g_db=0; // LineDB object to handle recovery after a QE crash
*******************
in the qe factory (estimator_i.cpp)
in main()
{
// ...
//
// Set up the recovery facility.
//
try
{
if( config["Recover"] )
{
g_db = new LineDB( config["QERecoveryFile"], true);
estimator->recover_state();
}
else
{
//
// even if we don't want to recover previous info
// the next time we might, so we create a recovery
// file, but we don't read the old recovery file
//
g_db = new LineDB( "QERecoveryFile.txt", false);
}
}
catch(char const* s)
{
cerr << "Failed to create recovery object: " << s << endl;
REASON;
return -1;
}
// ...
}
void smEstimator::recover_state()
{
for(LineDB::const_iterator it=g_db->begin(); it!=g_db->end(); ++it)
{
++nToken;
qe* pqe = new qe(0);
pqe->recover_state((*it).second);
m_qe_list.push_back( std::make_pair(pqe->m_token, pqe) );
}
}
********************
in class qe (qe_i.cpp)
//
// log_state() uses class LineDB to maintain recovery information that would
// be used after a crash (not that it will ever be used ;-)
//
void qe::log_state()
{
char s[4096];
char components[4096]="";
for(std::vector<char*>::iterator it=m_components.begin();
it!=m_components.end(); ++it)
{
if( it!=m_components.begin() ) strcat(components,":");
strcat(components,*it);
}
sprintf(s,"%s;%d;%s;%s;%s;",m_token,m_state,m_clause,components,m_uid);
try
{
g_db->add_line(strnewdup(m_token),strnewdup(s));
}
catch(const char* s)
{
cerr << s << endl;
REASON;
}
}
//
// recover_state() might look slightly complicated, this is mainly because
// we are recovering other types than just ordinary char* string,
// such as CORBA::string, int and std::vector<char*>
//
void qe::recover_state(const char* line)
{
if( m_clause ) { delete[] m_clause; m_clause = 0; }
if( m_token ) { delete[] m_token; m_token = 0; }
char* str=strnewdup(line);
char* str_copy=str; // make a copy of str so we can modify str, but still free
memory at the end
char* components=0, *uid=0, *state=0;
//
// get_token() returns 0 if it fails to get a token
// str is modify on each call to point to one character after the
// token it returns. This is to skip the separation character (';' in this
case)
// m_token, state etc. are 0 on entry, which tells get_token() to do the
// memory allocation (using new).
//
if( !get_token( str, m_token, ";") ||
!get_token( str, state, ";") ||
!get_token( str, m_clause, ";") ||
!get_token( str, components, ";") ||
!get_token( str, uid, ";") )
{
cerr << TOKEN << "ERROR: Failed to recover information in \"" << line << "\""
<< endl;
delete[] str_copy;
delete[] state;
delete[] components;
delete[] uid;
return;
}
m_state = (SM_STATE_T)atoi(state);
if( m_uid ) CORBA_string_free(m_uid);
m_uid = CORBA_string_dup(uid);
delete[] state;
delete[] uid;
for(std::vector< char* >::iterator it=m_components.begin();
it!=m_components.end(); ++it)
delete[] *it;
m_components.clear();
char* components_copy=strnewdup(components);
for(char*cmp=0; get_token(components,cmp,":"); ) m_components.push_back( cmp );
if( g_verbose )
cout << TOKEN << ": successfully recovered: clause= " << m_clause <<
", components= " << components_copy << ", uid= " << m_uid << endl;
delete[] str_copy;
delete[] components_copy;
}
_________________________________________
Henrik Nordberg <hnordberg@lbl.gov>
Scientific Data Management Research Group
Lawrence Berkeley National Laboratory