00001 #include "CondCore/ORA/interface/Exception.h"
00002 #include "DatabaseContainer.h"
00003 #include "DatabaseSession.h"
00004 #include "ContainerSchema.h"
00005 #include "IRelationalStreamer.h"
00006 #include "RelationalBuffer.h"
00007 #include "RelationalOperation.h"
00008 #include "DataElement.h"
00009 #include "RelationalDeleter.h"
00010 #include "RelationalStreamerFactory.h"
00011 #include "IDatabaseSchema.h"
00012 #include "ClassUtils.h"
00013 #include "MappingRules.h"
00014
00015 #include "CoralBase/Attribute.h"
00016
00017 namespace ora {
00018
00019 class WriteBuffer {
00020 public:
00021 explicit WriteBuffer( ContainerSchema& contSchema ):
00022 m_buffer(),
00023 m_operationBuffer( contSchema.storageSchema() ),
00024 m_topLevelElement(),
00025 m_writer(),
00026 m_topLevelInsert( 0 ){
00027
00028 MappingElement& topLevelMapping = contSchema.mapping( true ).topElement();
00029 m_topLevelInsert = &m_operationBuffer.newInsert( topLevelMapping.tableName() );
00030 m_topLevelInsert->addId( topLevelMapping.columnNames()[ 0 ] );
00031 const Reflex::Type& type = contSchema.type();
00032 MappingElement::iterator iMap = topLevelMapping.find( type.Name(Reflex::SCOPED) );
00033
00034 if( iMap == topLevelMapping.end()){
00035 throwException("Could not find a mapping element for class \""+
00036 type.Name(Reflex::SCOPED)+"\"",
00037 "WriteBuffer::WriteBuffer");
00038 }
00039 MappingElement& mapping = iMap->second;
00040 RelationalStreamerFactory streamerFactory( contSchema );
00041 m_writer.reset( streamerFactory.newWriter( type, mapping ) );
00042 m_writer->build( m_topLevelElement, *m_topLevelInsert, m_operationBuffer );
00043 }
00044
00045
00046 ~WriteBuffer(){
00047 }
00048
00049 void registerForWrite( int oid, const void* data ){
00050 m_buffer.push_back( std::make_pair(oid, data ) );
00051 }
00052
00053 size_t flush(){
00054 size_t nobj = 0;
00055 for( std::vector<std::pair<int, const void*> >::const_iterator iW = m_buffer.begin();
00056 iW != m_buffer.end(); ++iW ){
00057 write( iW->first, iW->second );
00058 if( m_operationBuffer.flush() ) nobj++;
00059 }
00060 m_buffer.clear();
00061 return nobj;
00062 }
00063
00064 private:
00065 void write( int oid, const void* data ){
00066 coral::AttributeList& dataBuff = m_topLevelInsert->data();
00067 dataBuff.begin()->data<int>() = oid;
00068 m_writer->write( oid, data );
00069 }
00070
00071 private:
00072 std::vector<std::pair<int, const void*> > m_buffer;
00073 RelationalBuffer m_operationBuffer;
00074 DataElement m_topLevelElement;
00075 std::auto_ptr<IRelationalWriter> m_writer;
00076 InsertOperation* m_topLevelInsert;
00077 };
00078
00079 class UpdateBuffer {
00080 public:
00081 explicit UpdateBuffer( ContainerSchema& contSchema ):
00082 m_buffer(),
00083 m_operationBuffer( contSchema.storageSchema() ),
00084 m_topLevelElement(),
00085 m_depDeleter(),
00086 m_updater(),
00087 m_topLevelUpdate( 0 ){
00088
00089 std::vector<MappingElement> dependentMappings;
00090 contSchema.mappingForDependentClasses( dependentMappings );
00091 m_depDeleter.reset( new RelationalDeleter( dependentMappings ) );
00092 m_depDeleter->build( m_operationBuffer );
00093 dependentMappings.clear();
00094
00095 MappingElement& topLevelMapping = contSchema.mapping( true ).topElement();
00096 m_topLevelUpdate = &m_operationBuffer.newUpdate( topLevelMapping.tableName(), true );
00097 m_topLevelUpdate->addId( topLevelMapping.columnNames()[ 0 ] );
00098 m_topLevelUpdate->addWhereId( topLevelMapping.columnNames()[ 0 ] );
00099 const Reflex::Type& type = contSchema.type();
00100 MappingElement::iterator iMap = topLevelMapping.find( type.Name(Reflex::SCOPED) );
00101
00102 if( iMap == topLevelMapping.end()){
00103 throwException("Could not find a mapping element for class \""+
00104 type.Name(Reflex::SCOPED)+"\"",
00105 "UpdateBuffer::UpdateBuffer");
00106 }
00107 MappingElement& mapping = iMap->second;
00108 RelationalStreamerFactory streamerFactory( contSchema );
00109 m_updater.reset( streamerFactory.newUpdater( type, mapping ));
00110 m_updater->build( m_topLevelElement, *m_topLevelUpdate, m_operationBuffer );
00111 }
00112
00113 ~UpdateBuffer(){
00114 }
00115
00116
00117 void registerForUpdate( int oid, const void* data ){
00118 m_buffer.push_back( std::make_pair( oid, data ));
00119 }
00120
00121
00122 size_t flush(){
00123 size_t nobj = 0;
00124 for( std::vector<std::pair<int, const void*> >::const_iterator iU = m_buffer.begin();
00125 iU != m_buffer.end(); ++iU ){
00126 update( iU->first, iU->second );
00127 if( m_operationBuffer.flush()) nobj++;
00128 }
00129 m_buffer.clear();
00130 return nobj;
00131 }
00132
00133
00134 private:
00135 void update( int oid, const void* data ){
00136
00137 m_depDeleter->erase( oid );
00138 coral::AttributeList& dataBuff = m_topLevelUpdate->data();
00139 dataBuff.begin()->data<int>() = oid;
00140 coral::AttributeList& whereDataBuff = m_topLevelUpdate->whereData();
00141 whereDataBuff.begin()->data<int>() = oid;
00142 m_updater->update( oid, data );
00143 }
00144
00145
00146 private:
00147 std::vector<std::pair<int, const void*> > m_buffer;
00148 RelationalBuffer m_operationBuffer;
00149 DataElement m_topLevelElement;
00150 std::auto_ptr<RelationalDeleter> m_depDeleter;
00151 std::auto_ptr<IRelationalUpdater> m_updater;
00152 UpdateOperation* m_topLevelUpdate;
00153 };
00154
00155 class ReadBuffer {
00156 public:
00157 explicit ReadBuffer( ContainerSchema& contSchema ):
00158 m_topLevelElement(),
00159 m_type( contSchema.type() ),
00160 m_reader(),
00161 m_topLevelQuery( contSchema.mapping().topElement().tableName(), contSchema.storageSchema() ){
00162
00163 MappingElement& topLevelMapping = contSchema.mapping().topElement();
00164 m_topLevelQuery.addWhereId( topLevelMapping.columnNames()[ 0 ] );
00165 MappingElement::iterator iMap = topLevelMapping.find( m_type.Name(Reflex::SCOPED) );
00166
00167 if( iMap == topLevelMapping.end()){
00168 throwException("Could not find a mapping element for class \""+
00169 m_type.Name(Reflex::SCOPED)+"\"",
00170 "ReadBuffer::ReadBuffer");
00171 }
00172 MappingElement& mapping = iMap->second;
00173 RelationalStreamerFactory streamerFactory( contSchema );
00174 m_reader.reset( streamerFactory.newReader( m_type, mapping )) ;
00175 m_reader->build( m_topLevelElement , m_topLevelQuery );
00176 }
00177
00178 ~ReadBuffer(){
00179 }
00180
00181 void* read( int oid ){
00182 coral::AttributeList& dataBuff = m_topLevelQuery.whereData();
00183 dataBuff.begin()->data<int>() = oid;
00184 m_topLevelQuery.execute();
00185 m_reader->select( oid );
00186 void* destination = 0;
00187 if( m_topLevelQuery.nextCursorRow() ){
00188 destination = ClassUtils::constructObject( m_type );
00189 m_reader->read( destination );
00190 }
00191 m_reader->clear();
00192 m_topLevelQuery.clear();
00193 return destination;
00194 }
00195
00196 const Reflex::Type& type(){
00197 return m_type;
00198 }
00199
00200 private:
00201 DataElement m_topLevelElement;
00202 const Reflex::Type& m_type;
00203 std::auto_ptr<IRelationalReader> m_reader;
00204 SelectOperation m_topLevelQuery;
00205 };
00206
00207 class DeleteBuffer {
00208 public:
00209 explicit DeleteBuffer( ContainerSchema& contSchema ):
00210 m_buffer(),
00211 m_operationBuffer( contSchema.storageSchema() ),
00212 m_mainDeleter(),
00213 m_depDeleter(){
00214 m_mainDeleter.reset( new RelationalDeleter( contSchema.mapping().topElement() ));
00215 m_mainDeleter->build( m_operationBuffer );
00216
00217 std::vector<MappingElement> dependentMappings;
00218 contSchema.mappingForDependentClasses( dependentMappings );
00219 m_depDeleter.reset( new RelationalDeleter( dependentMappings ) );
00220 m_depDeleter->build( m_operationBuffer );
00221 dependentMappings.clear();
00222 }
00223
00224 ~DeleteBuffer(){
00225 }
00226
00227
00228 void registerForDelete( int oid ){
00229 m_buffer.push_back( oid );
00230 }
00231
00232 size_t flush(){
00233 size_t nobj = 0;
00234 for( std::vector<int>::const_iterator iD = m_buffer.begin();
00235 iD != m_buffer.end(); ++iD ){
00236 m_depDeleter->erase( *iD );
00237 m_mainDeleter->erase( *iD );
00238 if( m_operationBuffer.flush() ) nobj++;
00239 }
00240 m_buffer.clear();
00241 return nobj;
00242 }
00243
00244 private:
00245 std::vector<int> m_buffer;
00246 RelationalBuffer m_operationBuffer;
00247 std::auto_ptr<RelationalDeleter> m_mainDeleter;
00248 std::auto_ptr<RelationalDeleter> m_depDeleter;
00249 };
00250
00251 }
00252
00253 ora::IteratorBuffer::IteratorBuffer( ContainerSchema& schema,
00254 ReadBuffer& buffer ):
00255 m_query( schema.mapping().topElement().tableName(), schema.storageSchema() ),
00256 m_itemId( -1 ),
00257 m_readBuffer( buffer ){
00258 const std::string& idCol = schema.mapping().topElement().columnNames()[0];
00259 m_query.addId( idCol );
00260 m_query.addOrderId( idCol );
00261 }
00262
00263 ora::IteratorBuffer::~IteratorBuffer(){
00264 }
00265
00266 void ora::IteratorBuffer::reset(){
00267 m_query.execute();
00268 }
00269
00270 bool ora::IteratorBuffer::next(){
00271 bool prevValid = (m_itemId != -1);
00272 bool currValid = false;
00273 m_itemId = -1;
00274 if( m_query.nextCursorRow() ){
00275 coral::AttributeList& row = m_query.data();
00276 m_itemId = row.begin()->data<int>();
00277 currValid = true;
00278 }
00279
00280 if( !currValid && prevValid ) m_query.clear();
00281 return currValid;
00282 }
00283
00284 void* ora::IteratorBuffer::getItem(){
00285 void* ret = 0;
00286 if( m_itemId != -1 ){
00287 ret = m_readBuffer.read( m_itemId );
00288 }
00289 return ret;
00290 }
00291
00292 void* ora::IteratorBuffer::getItemAsType( const Reflex::Type& asType ){
00293 if( !ClassUtils::isType( type(), asType ) ){
00294 throwException("Provided output object type \""+asType.Name(Reflex::SCOPED)+"\" does not match with the container type \""+
00295 type().Name(Reflex::SCOPED)+"\"","IteratorBuffer::getItemAsType");
00296 }
00297 return getItem();
00298 }
00299
00300 int ora::IteratorBuffer::itemId(){
00301 return m_itemId;
00302 }
00303
00304 const Reflex::Type& ora::IteratorBuffer::type(){
00305 return m_readBuffer.type();
00306 }
00307
00308 ora::DatabaseContainer::DatabaseContainer( int contId,
00309 const std::string& containerName,
00310 const std::string& className,
00311 unsigned int containerSize,
00312 DatabaseSession& session ):
00313 m_schema( new ContainerSchema(contId, containerName, className, session) ),
00314 m_writeBuffer(),
00315 m_updateBuffer(),
00316 m_readBuffer(),
00317 m_deleteBuffer(),
00318 m_iteratorBuffer(),
00319 m_size( containerSize ),
00320 m_containerUpdateTable( session.containerUpdateTable() ){
00321 }
00322
00323 ora::DatabaseContainer::DatabaseContainer( int contId,
00324 const std::string& containerName,
00325 const Reflex::Type& containerType,
00326 DatabaseSession& session ):
00327 m_schema( new ContainerSchema(contId, containerName, containerType, session) ),
00328 m_writeBuffer(),
00329 m_updateBuffer(),
00330 m_readBuffer(),
00331 m_deleteBuffer(),
00332 m_iteratorBuffer(),
00333 m_size(0),
00334 m_containerUpdateTable( session.containerUpdateTable() ){
00335 }
00336
00337 ora::DatabaseContainer::~DatabaseContainer(){
00338 m_iteratorBuffer.clear();
00339 }
00340
00341 int ora::DatabaseContainer::id(){
00342 return m_schema->containerId();
00343 }
00344
00345 const std::string& ora::DatabaseContainer::name(){
00346 return m_schema->containerName();
00347 }
00348
00349 const std::string& ora::DatabaseContainer::className(){
00350 return m_schema->className();
00351 }
00352
00353 const Reflex::Type& ora::DatabaseContainer::type(){
00354 return m_schema->type();
00355 }
00356
00357 const std::string& ora::DatabaseContainer::mappingVersion(){
00358 return m_schema->mappingVersion();
00359 }
00360
00361 size_t ora::DatabaseContainer::size(){
00362 return m_size;
00363 }
00364
00365 ora::Handle<ora::IteratorBuffer> ora::DatabaseContainer::iteratorBuffer(){
00366 if(!m_readBuffer.get()){
00367 m_readBuffer.reset( new ReadBuffer( *m_schema ) );
00368 }
00369 if( !m_iteratorBuffer ){
00370 m_iteratorBuffer.reset( new IteratorBuffer(*m_schema, *m_readBuffer ) );
00371 m_iteratorBuffer->reset();
00372 }
00373 return m_iteratorBuffer;
00374 }
00375
00376 void ora::DatabaseContainer::create(){
00377 m_schema->create();
00378 }
00379
00380 void ora::DatabaseContainer::drop(){
00381 m_schema->drop();
00382 }
00383
00384 void ora::DatabaseContainer::extendSchema( const Reflex::Type& dependentType ){
00385 m_schema->extendIfRequired( dependentType );
00386 }
00387
00388 void* ora::DatabaseContainer::fetchItem(int itemId){
00389
00390 if(!m_readBuffer.get()){
00391 m_readBuffer.reset( new ReadBuffer( *m_schema ) );
00392 }
00393 return m_readBuffer->read( itemId );
00394 }
00395
00396 void* ora::DatabaseContainer::fetchItemAsType(int itemId,
00397 const Reflex::Type& asType){
00398 if(!m_readBuffer.get()){
00399 m_readBuffer.reset( new ReadBuffer( *m_schema ) );
00400 }
00401 if( !ClassUtils::isType( type(), asType ) ){
00402 throwException("Provided output object type \""+asType.Name(Reflex::SCOPED)+"\" does not match with the container type \""+
00403 type().Name(Reflex::SCOPED)+"\"","DatabaseContainer::fetchItemAsType");
00404 }
00405 return m_readBuffer->read( itemId );
00406 }
00407
00408 int ora::DatabaseContainer::insertItem( const void* data,
00409 const Reflex::Type& dataType ){
00410 if(!m_writeBuffer.get()){
00411 m_writeBuffer.reset( new WriteBuffer( *m_schema ) );
00412 }
00413 Reflex::Type inputResType = ClassUtils::resolvedType( dataType );
00414 Reflex::Type contType = ClassUtils::resolvedType(m_schema->type());
00415 if( inputResType.Name()!= contType.Name() && !inputResType.HasBase( contType ) ){
00416 throwException( "Provided input object type=\""+inputResType.Name()+
00417 "\" does not match with the container type=\""+contType.Name()+"\"",
00418 "DatabaseContainer::insertItem" );
00419 }
00420
00421 int newId = m_schema->containerSequences().getNextId( MappingRules::sequenceNameForContainer( m_schema->containerName()) );
00422 m_writeBuffer->registerForWrite( newId, data );
00423 return newId;
00424 }
00425
00426 void ora::DatabaseContainer::updateItem( int itemId,
00427 const void* data,
00428 const Reflex::Type& dataType ){
00429 if(!m_updateBuffer.get()){
00430 m_updateBuffer.reset( new UpdateBuffer( *m_schema ) );
00431 }
00432 Reflex::Type inputResType = ClassUtils::resolvedType( dataType );
00433 Reflex::Type contType = ClassUtils::resolvedType(m_schema->type());
00434 if( inputResType.Name()!= contType.Name() && !inputResType.HasBase( contType ) ){
00435 throwException( "Provided input object type=\""+inputResType.Name()+"\" does not match with the container type=\""+
00436 contType.Name()+"\".",
00437 "DatabaseContainer::updateItem" );
00438 }
00439
00440 m_updateBuffer->registerForUpdate( itemId, data );
00441 }
00442
00443 void ora::DatabaseContainer::erase( int itemId ){
00444 if(!m_deleteBuffer.get()){
00445 m_deleteBuffer.reset( new DeleteBuffer( *m_schema ) );
00446 }
00447 m_deleteBuffer->registerForDelete( itemId );
00448 }
00449
00450 void ora::DatabaseContainer::flush(){
00451 size_t prevSize = m_size;
00452 if(m_writeBuffer.get()) m_size += m_writeBuffer->flush();
00453 if(m_updateBuffer.get()) m_updateBuffer->flush();
00454 if(m_deleteBuffer.get()) m_size -= m_deleteBuffer->flush();
00455 m_schema->containerSequences().sinchronizeAll();
00456 if( prevSize != m_size ){
00457 m_containerUpdateTable.takeNote( id(), m_size );
00458 }
00459 }
00460
00461 void ora::DatabaseContainer::setItemName( const std::string& name,
00462 int itemId ){
00463 m_schema->dbSession().setObjectName( name, m_schema->containerId(), itemId );
00464 }
00465
00466 bool ora::DatabaseContainer::getNames( std::vector<std::string>& destination ){
00467 return m_schema->dbSession().getNamesForContainer( m_schema->containerId(), destination );
00468 }
00469
00470