/* * This file is part of rasdaman community. * * Rasdaman community is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Rasdaman community is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with rasdaman community. If not, see . * * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann / rasdaman GmbH. * * For more information please see * or contact Peter Baumann via . / /** * SOURCE: transaction.cc * * MODULE: rasodmg * CLASS: r_Transaction * * COMMENTS: * None */ static const char rcsid[] = "@(#)rasodmg, r_Transaction: $Id: transaction.cc,v 1.38 2005/09/03 20:39:35 rasdev Exp $"; #ifdef __VISUALC__ #ifndef __EXECUTABLE__ #define __EXECUTABLE__ #define TRANSACTION_NOT_SET #endif #endif #include "rasodmg/transaction.hh" #include "rasodmg/database.hh" #include "raslib/rmdebug.hh" #include "raslib/scalar.hh" #include "clientcomm/clientcomm.hh" #ifdef __VISUALC__ #ifdef TRANSACTION_NOT_SET #undef __EXECUTABLE__ #endif template class r_Set< r_Ref >; #endif #include // Initially there is no transaction active. r_Transaction* r_Transaction::actual_transaction = 0; r_Transaction::r_Transaction() : ta_state( inactive ), ta_mode( read_write ) { } r_Transaction::~r_Transaction() { if( ta_state == active ) abort(); } void r_Transaction::begin( r_Transaction::r_TAMode mode ) throw( r_Error ) { // check if no other transaction is running if( ta_state != inactive || actual_transaction ) { r_Error err = r_Error( r_Error::r_Error_TransactionOpen ); throw err; } // check if a database is opened if( r_Database::actual_database == 0 ) { r_Error err = r_Error( r_Error::r_Error_DatabaseClosed ); throw err; } ta_state = active; // if a database is opened, a communication object is existing //r_Database::actual_database->communication->openTA( mode == read_only ? 1 : 0 ); r_Database::actual_database->getComm()->openTA( mode == read_only ? 1 : 0 ); actual_transaction = this; ta_mode = mode; } void r_Transaction::commit() throw( r_Error ) { if( ta_state != active ) { throw( new r_Error( r_Error::r_Error_TransactionNotOpen ) ); } else { RMInit::logOut << std::endl << "Commit Log:" << std::endl; // // Commit list of r_Object references. // r_Iterator< r_Ref > iter = object_list.create_iterator(); for( iter.reset(); iter.not_done(); iter++ ) { if( (*iter)->get_oid().is_valid() ) { RMInit::logOut << " Object " << (*iter)->get_oid() << " " << std::flush; switch( (*iter)->get_status() ) { case r_Object::deleted: RMInit::logOut << "state DELETED, deleting ... " << std::flush; (*iter)->r_Object::delete_obj_from_db(); RMInit::logOut << "OK" << std::endl; break; case r_Object::created: RMInit::logOut << "state CREATED, writing ... " << std::flush; (*iter)->insert_obj_into_db(); RMInit::logOut << "OK" << std::endl; break; case r_Object::modified: RMInit::logOut << "state MODIFIED, modifying ... " << std::endl; (*iter)->update_obj_in_db(); break; case r_Object::read: RMInit::logOut << "state READ, OK" << std::endl; break; case r_Object::transient: RMInit::logOut << "state TRANSIENT, OK" << std::endl; break; default: RMInit::logOut << "state UNKNOWN" << std::endl; break; } } else RMInit::logOut << " Object with no oid, state TRANSIENT query result" << std::endl; } // Don't do the r_deactivate() in the first loop because if a collection is not // before its elements in the list, it tries to save non existing objects. for( iter.reset(); iter.not_done(); iter++ ) { if( !(*iter)->test_status( r_Object::deleted ) ) (*iter)->r_deactivate(); (*iter)->r_Object::r_deactivate(); free( (*iter).get_memory_ptr() ); } object_list.remove_all(); // // Commit list of non-r_Object references. // r_Iterator< GenRefElement* > iter2 = non_object_list.create_iterator(); for( iter2.reset(); iter2.not_done(); iter2++ ) { RMInit::logOut << " Value " << std::flush; switch( (*iter2)->type ) { case POINT: RMInit::logOut << "transient Point DELETED" << std::endl; delete ((r_Point*)(*iter2)->ref); break; case SINTERVAL: RMInit::logOut << "transient Sinterval DELETED" << std::endl; delete ((r_Sinterval*)(*iter2)->ref); break; case MINTERVAL: RMInit::logOut << "transient Minterval DELETED" << std::endl; delete ((r_Minterval*)(*iter2)->ref); break; case OID: RMInit::logOut << "transient OId DELETED" << std::endl; delete ((r_OId*)(*iter2)->ref); break; default: RMInit::logOut << "transient Scalar DELETED" << std::endl; delete ((r_Scalar*)(*iter2)->ref); break; } delete *iter2; } non_object_list.remove_all(); // // commit transaction on the server // // r_Database::actual_database->communication->commitTA(); r_Database::actual_database->getComm()->commitTA(); ta_state = inactive; actual_transaction = 0; } } void r_Transaction::abort() { if( ta_state != active ) { throw( r_Error( r_Error::r_Error_TransactionNotOpen ) ); } else { RMInit::logOut << std::endl << "Abort Log:" << std::endl; // // Abort list of r_Object references. // r_Iterator< r_Ref > iter = object_list.create_iterator(); for( iter.reset(); iter.not_done(); iter++ ) { RMInit::logOut << " Object DELETED" << std::endl; if( !(*iter)->test_status( r_Object::deleted ) ) (*iter)->r_deactivate(); (*iter)->r_Object::r_deactivate(); free( (*iter).get_memory_ptr() ); } object_list.remove_all(); // // Abort list of non-r_Object references. // r_Iterator< GenRefElement* > iter2 = non_object_list.create_iterator(); for( iter2.reset(); iter2.not_done(); iter2++ ) { switch( (*iter2)->type ) { case POINT: RMInit::logOut << " Transient Point DELETED" << std::endl; delete ((r_Point*)(*iter2)->ref); break; case SINTERVAL: RMInit::logOut << " Transient Sinterval DELETED" << std::endl; delete ((r_Sinterval*)(*iter2)->ref); break; case MINTERVAL: RMInit::logOut << " Transient Minterval DELETED" << std::endl; delete ((r_Minterval*)(*iter2)->ref); break; case OID: RMInit::logOut << " Transient OId DELETED" << std::endl; delete ((r_OId*)(*iter2)->ref); break; default: RMInit::logOut << " Transient Scalar DELETED" << std::endl; delete ((r_Scalar*)(*iter2)->ref); break; } delete *iter2; } non_object_list.remove_all(); // // Abort transaction on the server. // if (r_Database::actual_database) // r_Database::actual_database->communication->abortTA(); r_Database::actual_database->getComm()->abortTA(); else RMInit::logOut << " Database was already closed. Please abort every transaction before closing the database. Please also check for any try/catches with a close database but without transaction abort." << std::endl; ta_state = inactive; actual_transaction = 0; } } r_Ref_Any r_Transaction::load_object( const r_OId& oid ) { // check, if object is already loaded unsigned int found = 0; r_Iterator< r_Ref > iter = object_list.create_iterator(); iter.reset(); while( iter.not_done() && !found ) { found = ( (*iter)->get_oid() == oid ); if( !found ) iter++; } if( found ) { // return reference of loaded object RMDBGONCE(4, RMDebug::module_rasodmg, "r_Transaction", "load_object( oid ) - object already loaded") return *iter; } else { // load object and return reference RMDBGONCE(4, RMDebug::module_rasodmg, "r_Transaction", "load_object( oid ) - load object") return r_Database::actual_database->lookup_object( oid ); } } void r_Transaction::add_object_list( const r_Ref &obj ) { object_list.insert_element( obj ); } void r_Transaction::add_object_list( GenRefType type, void* ref ) { GenRefElement* element = new GenRefElement; element->type = type; element->ref = ref; non_object_list.insert_element( element ); }