Bdb packages | Design docs | Source docs | Guidelines | Recent releases

Search | Site Map .

Main Page   Modules   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

/BdbBitMap/BdbBMIndexQueryAPI.cc

Go to the documentation of this file.
00001 // ------------------------------------------------------------------------------
00002 // File:
00003 //      BdbBMIndexQueryAPI.cc
00004 //
00005 // Description:
00006 //      Transient abstract class implmeenting an API to the BitMap index structure.
00007 //      The API is used to access events using index structure. The access 
00008 //      is read-only via (subset of) SQL query.
00009 //
00010 // Environment:
00011 //      Software developed for the BaBar Detector at the SLAC B-Factory
00012 //
00013 // Author List:
00014 //      Jacek Becla, Igor Gaponenko           Original Authors
00015 //
00016 // Copyright Information:
00017 //      Copyright (C) 1997-98      Stanford Linear Accelerator Center
00018 //
00019 // ------------------------------------------------------------------------------
00020 
00021 // -------------------------
00022 // -- This Class's Header --
00023 // -------------------------
00024 
00025 #ifndef BDBBMINDEXQUERYAPI_HH
00026 #include "BdbBitMap/BdbBMIndexQueryAPI.hh"
00027 #endif
00028 
00029 // ---------------------------------
00030 // -- Collaborating Class Headers --
00031 // ---------------------------------
00032 
00033 #include "BdbApplication/BdbApplication.hh"
00034 
00035 #include "BdbAccess/BdbDbTreeSingleton.hh"
00036 
00037 #include "BdbClustering/BdbEvsHdrClusteringHint.hh"
00038 #include "BdbClustering/BdbSimpleClusteringHint.hh"
00039 
00040 #include "BdbTrees/BdbDbRegistrator.hh"
00041 
00042 #include "AbsEvent/AbsEvent.hh"
00043 
00044 #include "BdbEvent/BdbEvent.hh"
00045 
00046 #include "BdbEventStore/BdbCollection.hh"
00047 #include "BdbEventStore/BdbEventStore.hh"
00048 #include "BdbEventStore/BdbTreeNodeCollectionIterator.hh"
00049 #include "BdbEventStore/BdbEventStoreIterator.hh"
00050 #include "BdbEventStore/BdbTreeCollection.hh"
00051 #include "BdbEventStore/BdbVectorCollection.hh"
00052 
00053 #include "BdbIndexing/BdbIndexingErrors.hh"
00054 #include "BdbIndexing/BdbAbsIndexAPI.hh"
00055 #include "BdbIndexing/BdbQuery.hh"
00056 #include "BdbIndexing/BdbQueryDescr.hh"
00057 #include "BdbIndexing/BdbQueryEstimation.hh"
00058 
00059 #include "BdbBitMap/BdbBMDimension.hh"
00060 #include "BdbBitMap/BdbBMBin.hh"
00061 
00062 // -----------------------
00063 // -- Local definitions --
00064 // -----------------------
00065 
00066 static const d_ULong BITS_31_30 = 0x80000000 | 0x40000000 ;
00067 static const d_ULong BITS_31    = 0x80000000 ;
00068 static const d_ULong BITS_30    = 0x40000000 ;
00069 static const d_ULong BITS_29_00 = 0x3FFFFFFF ;
00070 
00071 // ----------------------
00072 // -- Static functions --
00073 // ----------------------
00074 
00075 inline d_Boolean IS_COMPRESSED(d_ULong value)
00076 {
00077     return BITS_31 == ( BITS_31 & value ) ;
00078 }
00079 
00080 inline d_Boolean IS_EMPTY(d_ULong value)
00081 {
00082     return ! ( BITS_29_00 & value ) ;
00083 }
00084 
00085 /**  
00086  **  Constructor. Used for accessing existing index structure.
00087  **  Requires a read transaction.
00088  **/
00089 
00090 BdbBMIndexQueryAPI::BdbBMIndexQueryAPI() :
00091 BdbAbsIndexQueryAPI("IndexRegistry",
00092                                         "BitMapIndexStructure")
00093 {}
00094 
00095 /**  
00096  **  Destructor
00097  **/
00098 
00099 BdbBMIndexQueryAPI::~BdbBMIndexQueryAPI()
00100 {}
00101 
00102 /**
00103  **  Report error condition
00104  **/
00105 
00106 void
00107 BdbBMIndexQueryAPI::error(const char* message) const
00108 {
00109     cout << "BdbBitMap[Events]::error " << message << "." << endl ;
00110 }
00111 
00112 /**
00113  **  Get a persistent reference to the implementation-specific
00114  **  index structure.
00115  **/
00116 
00117 BdbStatus
00118 BdbBMIndexQueryAPI::lookupIndexStructure(BdbHandle(BdbContObj)& contH,
00119                                          BdbRef(BdbAbsIndexStructure)& indexRef)
00120 {
00121         BdbStatus status ;
00122     BdbRef(BdbBMIndexStructure) bmRef ;
00123 
00124   // Look up an object by its name in the namespace
00125   // container.
00126 
00127     status = bmRef.lookupObj(contH, getIndexStructureName(), BdbcRead) ;
00128     if( BdbcSuccess != status ) {
00129         error(" locate index structure") ;
00130         return status ;
00131     }
00132 
00133   // Load some essential information on the database:
00134   //
00135   //  - the compression flag (used by vector operations)
00136   //  - the number of events (used by vector operation NOT for
00137   //    the correct vector allignment).
00138 
00139     _compressed = bmRef->isCompressed() ;
00140     _events     = bmRef->getNumEvents() ;
00141 
00142     // Initialize the number of events
00143 
00144   // Return a reference to the structure.
00145 
00146     indexRef = bmRef ;
00147 
00148     return BdbcSuccess ;
00149 }
00150 
00151 
00152 // ----------------------------------------------------------------------
00153 // -- Execute "trial" query request. Return result of query estimation --
00154 // -- into supplied object.                                            --
00155 // ----------------------------------------------------------------------
00156 
00157 
00158 BdbStatus
00159 BdbBMIndexQueryAPI::estimate(BdbQueryDescr& descr,
00160                              BdbQueryEstimation& estimation)
00161 {
00162     BdbStatus status ;
00163 
00164   // Build the mask (vector) of selected events based on
00165   // given query description.
00166 
00167     ooVArray(d_ULong) result ;
00168 
00169     status = select(result, descr) ;
00170     if ( BdbcSuccess != status ) {
00171         return status ;
00172     }
00173 
00174   // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  - - - - - - - - - - - -
00175   //  Make some estimations on the query results.
00176   //
00177   //  <IMPLEMENTED> (1) In case of the totatl number of the selected events this
00178   //                    require to count "1" in both compressed and non-compressed
00179   //                    vectors.
00180   //  <NOT APPLIED> (2) In case of number of "physical" DBs we have to use the
00181   //  <NOT APPLIED> (3) There are no ideas what to do with the number of tapes, since we
00182   //                    don't know for the moment how the files are located on HPSS.
00183   // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  - - - - - - - - - - - -
00184 
00185     BdbRef(BdbBMIndexStructure) indexRef = getBMIndexRef() ;
00186 
00187     estimation.setTotalNumEvents(indexRef->getNumEvents()) ;
00188     estimation.setNumEvents(estimateNumEvents(result)) ;
00189 
00190     return BdbcSuccess ;
00191 }
00192 
00193 
00194 // -----------------------------------------------------------------------
00195 // -- FRONT-END: Place results into specified by name events collection --
00196 // -----------------------------------------------------------------------
00197 
00198 
00199 BdbStatus
00200 BdbBMIndexQueryAPI::execute(BdbQueryDescr& descr,
00201                             BdbQueryEstimation& estimation,
00202                             const char* collection)
00203 {
00204     BdbStatus status ;
00205 
00206   // - - - - - - - - - - - - - - - - - - - - -
00207   // Initialize context: clustering hints, etc
00208   // - - - - - - - - - - - - - - - - - - - - -
00209   
00210     BdbEventStore* theStore = BdbEventStore::instance( ) ;
00211 
00212     BdbDbRegistrator registrator ;
00213     BdbDbTreeSingleton::instance()->setRegistrator(&registrator) ;
00214 
00215     BdbAbstractClusteringHint* theTreHint ;
00216     BdbAbstractClusteringHint* theVecHint ;
00217 
00218     theStore->configureClustering() ;
00219 
00220     if ( theStore->useFullClustering()) {
00221         theTreHint = new BdbEvsClusteringHint(*theStore) ;
00222         theVecHint = new BdbEvsClusteringHint(*theStore) ;
00223     } else {
00224         theTreHint = new BdbSimpleClusteringHint(*theStore) ;
00225         theVecHint = new BdbSimpleClusteringHint(*theStore) ;
00226     }
00227     theTreHint->setComponent("col") ;
00228     theVecHint->setComponent("col") ;
00229 
00230     theStore->configureClustering(theTreHint, theVecHint) ;
00231 
00232   // - - - - - - - - - - - - - - - - - - - - - - - -
00233   // Try to locate collection.  It should not exists
00234   // - - - - - - - - - - - - - - - - - - - - - - - -
00235 
00236     BdbCollection<BdbEvent> aCollection;
00237         
00238     status = theStore->collection( aCollection, collection );
00239     if ( BdbcSuccess == status ) {
00240         error("Can not execute the query. Specified output collection already exists.") ;
00241         return BdbcError ;
00242     }
00243     
00244   // - - - - - - - - - - -
00245   // Create new collection
00246   // - - - - - - - - - - -
00247 
00248     status = theStore->treeCollection(aCollection, collection);
00249     if ( BdbcSuccess != status ) {
00250         error("Can not execute the query. Failed to create specified output collection.") ;
00251         return status ;
00252     }
00253     aCollection.createDescription(aCollection.name()) ;
00254 
00255   // - - - - - - - - - - - - - - - - - - - - - - - - - - -
00256   // Go ahead and perform a real query. Place results into
00257   // specified collection.
00258   // - - - - - - - - - - - - - - - - - - - - - - - - - - -
00259 
00260     return ( status = execute(descr, estimation, aCollection)) ;
00261 }
00262 
00263 
00264 // ----------------------------------------------------------------------------
00265 // -- FRONT-END: Place results into specified by reference events collection --
00266 // ----------------------------------------------------------------------------
00267 
00268 
00269 BdbStatus
00270 BdbBMIndexQueryAPI::execute(BdbQueryDescr& descr,
00271                             BdbQueryEstimation& estimation,
00272                             BdbCollection<BdbEvent>& outputCollection)
00273 {
00274     BdbStatus status ;
00275 
00276   // - - - - - - - - - - - - - - - - - - - - - - - - - -
00277   // Build the mask (vector) of selected events based on
00278   // given query description.
00279   // - - - - - - - - - - - - - - - - - - - - - - - - - -
00280 
00281     ooVArray(d_ULong) result ;
00282 
00283     status = select(result, descr) ;
00284     if ( BdbcSuccess != status ) {
00285         return status ;
00286     }
00287     
00288   // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00289   //  Make some estimations on the query results.
00290   //
00291   //    <IMPLEMENTED> (1) In case of the totatl number of the selected events this
00292   //                      require to count "1" in both compressed and non-compressed
00293   //                      vectors.
00294   //    <NOT APPLIED> (2) In case of number of "physical" DBs we have to use the
00295   //    <NOT APPLIED> (3) There are no ideas what to do with the number of tapes, since
00296   //                      we don't know for the moment how the files are located on HPSS
00297   // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00298 
00299     BdbRef(BdbBMIndexStructure) indexRef = getBMIndexRef() ;
00300 
00301     estimation.setTotalNumEvents(indexRef->getNumEvents()) ;
00302     estimation.setNumEvents(estimateNumEvents(result)) ;
00303 
00304   // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00305   // Locate the name of the original events collection
00306   //
00307   // NOTE: The current implementation allows to execute queries
00308   //       if the index was built from a real events collection
00309   //       rather then from just a plain text file.
00310   // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00311 
00312     const char* target = indexRef->getTarget() ;
00313 
00314     if ( strncmp(target, "COLLECTION:", strlen("COLLECTION:"))) {
00315         error("Can not execute query. The index was not built from an event collection.") ;
00316         return BdbcError ;
00317     }
00318 
00319     int   inputCollectionNameLength = strlen(target) - strlen("COLLECTION:") ;
00320     char* inputCollectionName = new char[inputCollectionNameLength + 1] ;
00321     
00322     strcpy(inputCollectionName, &target[strlen(target) - inputCollectionNameLength]) ;
00323 
00324   // - - - - - - - - - - - - - - - - - - - - - - - - -
00325   // Open input collection and set up events iterator
00326   // - - - - - - - - - - - - - - - - - - - - - - - - -
00327   
00328     BdbEventStore* theStore = BdbEventStore::instance( ) ;
00329   
00330     BdbCollection<BdbEvent> inputCollection;
00331         
00332     status = theStore->collection( inputCollection, inputCollectionName );
00333     if ( BdbcSuccess != status ) {
00334         error("Can not execute the query. Original events collection does not exists.") ;        
00335         return status ;
00336     }
00337     BdbCollectionIterator<BdbEvent> inputCollectionItr(inputCollection) ;
00338 
00339   // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00340   // Now we will translate the selected events (defined by their relative
00341   // position in the bit string) into real references.
00342   // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00343    
00344     BdbHandle(BdbEvent) theEvent ;
00345     
00346     d_ULong nElems = result.size() ;
00347     d_ULong eventNumber = 0 ;
00348 
00349     d_ULong i ;
00350     d_ULong j ;
00351 
00352     for ( i = 0 ; i < nElems ; i++ ) {
00353 
00354         d_ULong value = result[i] ;
00355 
00356         if ( IS_COMPRESSED(value)) {
00357             if ( value & BITS_30 ) {
00358 
00359               // Take into account all "1"-s.
00360 
00361                 d_ULong elements = BITS_29_00 & value ;
00362 
00363                 for ( j = 0 ; j < elements ; j++ ) {
00364 
00365                     status = inputCollectionItr.next(theEvent) ;
00366                     if ( BdbcSuccess != status ) {
00367 
00368                         error("1: Unable to proceed with query execution.") ;
00369                         error("2: Failed to fetch next event reference from original collection.") ;
00370                         error("3: This might be because the index does not match the original collection.") ;
00371 
00372                         return status ;
00373                     }
00374 
00375                     status = outputCollection.add(theEvent) ;
00376                     if ( BdbcSuccess != status ) {
00377                         error("1: Unable to proceed with query execution.") ;
00378                         error("2: Failed to add next event reference to the output collection.") ;
00379                             
00380                         return status ;
00381                     }
00382                     eventNumber++ ;
00383                 }
00384             } else {
00385 
00386               // Skip "0"-es.
00387               
00388                 d_ULong eventsToSkeep = BITS_29_00 & value ;
00389                 
00390                 for ( j = 0 ; j < eventsToSkeep ; j++ ) {
00391 
00392                     status = inputCollectionItr.next(theEvent) ;
00393                     if ( BdbcSuccess != status ) {
00394 
00395                         error("1: Unable to proceed with query execution.") ;
00396                         error("2: Failed to fetch next event reference from original collection.") ;
00397                         error("3: This might be because the index does not match the original collection.") ;
00398 
00399                         return status ;
00400                     }
00401                 }
00402                 
00403                 eventNumber += eventsToSkeep ;
00404             }
00405         } else {
00406 
00407           // Go along the bits and find all "1"-s.
00408 
00409             for ( j = 0 ; j < 30 ; j++ ) {
00410                 if (( 1 << j ) & ( BITS_29_00 & value )) {
00411 
00412                     status = inputCollectionItr.next(theEvent) ;
00413                     if ( BdbcSuccess != status ) {
00414 
00415                         error("1: Unable to proceed with query execution.") ;
00416                         error("2: Failed to fetch next event reference from original collection.") ;
00417                         error("3: This might be because the index does not match the original collection.") ;
00418 
00419                         return status ;
00420                     }
00421 
00422                     status = outputCollection.add(theEvent) ;
00423                     if ( BdbcSuccess != status ) {
00424                         error("1: Unable to proceed with query execution.") ;
00425                         error("2: Failed to add next event reference to the output collection.") ;
00426                             
00427                         return status ;
00428                     }
00429                 }
00430                 eventNumber++ ;
00431             }
00432         }
00433     }
00434 
00435   // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00436   // Copy collection description (TAGs profile) from the original
00437   // colection to the output one.
00438   // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
00439 
00440     BdbHandle(HepExplorableDescr) expDescr ;
00441     
00442     status = inputCollection.description(expDescr) ;
00443     if ( BdbcSuccess != status ) {
00444         error("Unable to get a description for input collection") ;
00445         return status ;
00446     }
00447     
00448     status = outputCollection.setDescription(expDescr) ;
00449     if ( BdbcSuccess != status ) {
00450         error("Unable to set a description for output collection") ;
00451         return status ;
00452     }
00453 
00454     return BdbcSuccess ;
00455 }
00456 
00457 
00458 // ------------------------------------------------------------
00459 // -- Test method. It brakes through the regular interface   --
00460 // -- allowing to obtain the bit-map implementation specific --
00461 // -- results of the query execution.                        --
00462 // ------------------------------------------------------------
00463 
00464 
00465 BdbStatus
00466 BdbBMIndexQueryAPI::execute(const BdbQueryDescr& descr,
00467                             BdbQueryEstimation& estimation,
00468                             ooVArray(d_ULong)& result)
00469 {
00470     BdbStatus status ;
00471 
00472   // Build the mask (vector) of selected events based on
00473   // given query description.
00474 
00475     status = select(result, descr) ;
00476     if ( BdbcSuccess != status ) {
00477         return status ;
00478     }
00479 
00480   // Make some estimations on the query results.
00481   //
00482   // <IMPLEMENTED> (1) In case of the totatl number of the selected events this
00483   //                   require to count "1" in both compressed and non-compressed
00484   //                   vectors.
00485   // <NOT APPLIED> (2) In case of number of "physical" DBs we have to use the
00486   // <NOT APPLIED> (3) There are no ideas what to do with the number of tapes, since we
00487   //                   don't know for the moment how the files are located on HPSS.
00488 
00489     estimation.setNumEvents(estimateNumEvents(result)) ;
00490 
00491     return BdbcSuccess ;
00492 }
00493 
00494 /**-----------------------------------------------------------
00495  ** This helper functions perform an actual processing of the
00496  ** given request. On return it fills up a bit vector
00497  ** with the compression information on the selected events.
00498  **-----------------------------------------------------------
00499  **/
00500 
00501 BdbStatus
00502 BdbBMIndexQueryAPI::select(ooVArray(d_ULong)& result, const BdbQueryDescr& descr)
00503 {
00504 
00505   // Check if the given structure is initialized.
00506 
00507     if ( ! descr.isInitialized()) {
00508         error("- the wrong structure has been passed for selection.") ;
00509         return BdbcError ;
00510     }
00511 
00512   // Start from the root node in the tree.
00513 
00514     return nextNode(result, descr.getHead()) ;
00515 }
00516 
00517 BdbStatus
00518 BdbBMIndexQueryAPI::nextNode(ooVArray(d_ULong)& result, const BdbQueryNode* node)
00519 {
00520     BdbStatus status ;
00521     ooVArray(d_ULong) left ;
00522     ooVArray(d_ULong) right ;
00523 
00524   // Check zero reference to the node was passed.
00525   // This should be treated as a error.
00526 
00527     if ( node == (BdbQueryNode*) 0 ) {
00528         error("- inconsistent query description. Unexpected NULL pointer.") ;
00529         return BdbcError ;
00530     }
00531 
00532   // Process this node.
00533 
00534     if ( node->isLogical()) {
00535 
00536         switch ( node->getLogicalOperation()) {
00537 
00538         case BdbQueryNode::LOP_NOT :
00539 
00540             status = nextNode(left, node->getLeft()) ;
00541             if ( BdbcSuccess != status ) {
00542                 return status ;
00543             }
00544 
00545             status = NOT(result, left) ;
00546             if ( BdbcSuccess != status ) {
00547                 return status ;
00548             }
00549 
00550             break ;
00551 
00552         case BdbQueryNode::LOP_AND :
00553 
00554             status = nextNode(left, node->getLeft()) ;
00555             if ( BdbcSuccess != status ) {
00556                 return status ;
00557             }
00558             status = nextNode(right, node->getRight()) ;
00559             if ( BdbcSuccess != status ) {
00560                 return status ;
00561             }
00562 
00563             status = AND(result, left, right) ;
00564             if ( BdbcSuccess != status ) {
00565                 return status ;
00566             }
00567 
00568             break ;
00569 
00570         case BdbQueryNode::LOP_OR :
00571 
00572             status = nextNode(left, node->getLeft()) ;
00573             if ( BdbcSuccess != status ) {
00574                 return status ;
00575             }
00576             status = nextNode(right, node->getRight()) ;
00577             if ( BdbcSuccess != status ) {
00578                 return status ;
00579             }
00580 
00581             status = OR(result, left, right) ;
00582             if ( BdbcSuccess != status ) {
00583                 return status ;
00584             }
00585 
00586             break ;
00587         }
00588     } else {
00589 
00590         status = endNode(result, node) ;
00591         if ( BdbcSuccess != status ) {
00592             return status ;
00593         }
00594     }
00595 
00596     return BdbcSuccess ;
00597 }
00598 
00599 BdbStatus
00600 BdbBMIndexQueryAPI::endNode(ooVArray(d_ULong)& result, const BdbQueryNode* node)
00601 {
00602     BdbStatus status ;
00603     d_ULong i ;
00604 
00605   // Take the specified range and calculate the bins
00606   // that must be OR-ed.
00607 
00608     const char* dimName = node->getName() ;
00609 
00610   // STEP I: Pre-load the following information:
00611   //
00612   //  - the reference to the persistent index structure
00613   //  - reference to the persistent dimension
00614   //  - the number of events in the database
00615   //  - the number of bins
00616   //  - an array of references to the persistent bins
00617 
00618     d_ULong nEvents ;
00619     d_ULong nBins ;
00620 
00621     BdbRef(BdbBMIndexStructure) indexRef ;
00622     BdbRef(BdbBMDimension)      dimRef ;
00623     ooVArray(BdbRef(BdbBMBin))  binRef ;
00624 
00625     indexRef = getBMIndexRef() ;
00626 
00627     status = indexRef->getDimension(dimName, dimRef) ;
00628     if ( BdbcSuccess != status ) {
00629         cout << "BdbBMIndexQuery::endNode() - unknown attribute name: "
00630              << dimName << endl ;
00631         return status ;
00632     }
00633 
00634     nEvents = indexRef->getNumEvents() ;
00635     nBins   = dimRef->getNumBins() ;
00636 
00637     status = binRef.resize(nBins) ;
00638     if ( BdbcSuccess != status ) {
00639         cout << "BdbBMIndexQuery::endNode() - failed to resize ooVArray." << endl ;
00640         return status ;
00641     }
00642 
00643     for ( i = 0 ; i < nBins ; i++ ) {
00644 
00645         status = dimRef->getBin(i, binRef[i]) ;
00646         if ( BdbcSuccess != status ) {
00647           cout << "BdbBMIndexQuery::endNode() - failed to load persistent BdbBMBin object." << endl ;
00648           return status ;
00649         }
00650     }
00651 
00652   // STEP II: Find out a range of bins to be OR-ed together
00653   //          in order to meet the selection criteria.
00654 
00655     d_ULong from ;     // The bin number to start WITH.
00656     d_ULong to ;       // The bin number to finish BEFORE.
00657 
00658     d_Float minVal ;   // Minumum range of the query.
00659     d_Float maxVal ;   // Maxumum range of the query.
00660 
00661     minVal = node->getMinVal() ;
00662     maxVal = node->getMaxVal() ;
00663 
00664     if ( ! node->isMinDefined()) {
00665         from = 0 ;
00666     } else {
00667 
00668         while ( true ) {
00669 
00670             if ( minVal <  dimRef->getMinValue()) {
00671                 from = 0 ;
00672                 break ; // Less then dimension's minimum.
00673             }
00674 
00675             if ( minVal >= dimRef->getMaxValue()) {
00676                 from = nBins -1 ;
00677                 break ; // More or equal then dimension's maximum.
00678             }
00679 
00680             d_Boolean from_is_found = false ;
00681 
00682             for ( i = 0 ; i < nBins ; i++ ) {
00683 
00684                 if (( minVal >= binRef[i]->getMinValue()) &&
00685                     ( minVal <  binRef[i]->getMaxValue())) {
00686 
00687                     from = i ;
00688 
00689                     from_is_found = true ;
00690 
00691                     break ;
00692                 }
00693             }
00694 
00695             if ( ! from_is_found ) {
00696                 cout << "BdbBMIndexQuery::endNode() - internal bug #1." << endl ;
00697                 return BdbcError ;
00698             }
00699 
00700             break ;     // Within dimension.
00701         }
00702     }
00703 
00704     if ( ! node->isMaxDefined()) {
00705         to = nBins  ;
00706     } else {
00707 
00708         while ( true ) {
00709 
00710             if ( maxVal <  dimRef->getMinValue()) {
00711                 to = 1 ;
00712                 break ; // Less then dimension's minimum.
00713             }
00714 
00715             if ( maxVal >= dimRef->getMaxValue()) {
00716                 to = nBins ;
00717                 break ; // More or equal then dimension's maximum.
00718             }
00719 
00720             d_Boolean to_is_found = false ;
00721 
00722             for ( i = 0 ; i < nBins ; i++ ) {
00723 
00724                 if (( maxVal >= binRef[i]->getMinValue()) &&
00725                     ( maxVal <  binRef[i]->getMaxValue())) {
00726 
00727                     to = i + 1 ;
00728 
00729                     to_is_found = true ;
00730 
00731                     break ;
00732                 }
00733             }
00734 
00735             if ( ! to_is_found ) {
00736                 cout << "BdbBMIndexQuery::endNode() - internal bug #2." << endl ;
00737                 return BdbcError ;
00738             }
00739 
00740             break ;     // Within dimension.
00741         }
00742     }
00743 
00744     if ( from >= to ) {
00745         cout << "BdbBMIndexQuery::endNode() - wrong range for attribute: "
00746              << dimName << endl ;
00747         return BdbcError ;
00748     }
00749 
00750   // STEP III: The final action is to go through the selected
00751   //           bit strings and to "OR" them together.
00752 
00753     ooVArray(d_ULong) tmp ;
00754 
00755     status = ZERO(tmp, nEvents) ;
00756     if ( BdbcSuccess != status ) {
00757         cout << "BdbBMIndexQuery::endNode() - error to create temporary bit vector." << endl ;
00758         return status ;
00759     }
00760 
00761     for ( i = from ; i < to ; i++ ) {
00762 
00763         result.resize(0) ;  // If we don't do it, the vector length
00764                             // will increase after each OR.
00765 
00766         status = OR(result, tmp, binRef[i]->getBits()) ;
00767         if ( BdbcSuccess != status ) {
00768           cout << "BdbBMIndexQuery::endNode() - operation OR failed for bit vectors." << endl ;
00769           return status ;
00770         }
00771         tmp = result ;  // Save the result for the next operation.
00772     }
00773 
00774     return BdbcSuccess ;
00775 }
00776 
00777 /**-------------------------------------------------------------------
00778  **  Bit strings operations. Are used by the query estimator
00779  **  and executor.
00780  **  All the operations are based on existing arrays.
00781  **  The output of the vectors is compressed or not depending
00782  ** on the state of the persistent index structure.
00783  **
00784  ** NOTE: (1) The max number of elements (either compressed or not)
00785  **           is limited by 30 bits, or 10^30.
00786  **           This is general limitation of all the vector algorithms.
00787  **
00788  **       (2) The implementation of the OR, AND operations for the
00789  **           compressed vetors is not so efficient as it could be.
00790  **           The situation will be improved in further versions.
00791  **-------------------------------------------------------------------
00792  **/
00793 
00794 BdbStatus
00795 BdbBMIndexQueryAPI::NOT(ooVArray(d_ULong)& out,
00796                         const ooVArray(d_ULong)& in)
00797 {
00798     BdbStatus status ;
00799     d_ULong i ;
00800     d_ULong nBits ;
00801 
00802   // (Re-)allocate output vector of the same
00803   // size as the input one.
00804 
00805     nBits = in.size() ;
00806 
00807     status = out.resize(nBits) ;
00808     if ( BdbcSuccess != status ) {
00809         error("- vector resize.") ;
00810         return status ;
00811     }
00812 
00813   // Perform NOT for each element depending
00814   // on the compressing method.
00815 
00816   // DEBUG:    cout << endl ;
00817   // DEBUG:    cout << "BdbBMIndexQueryAPI::NOT num30 " << nBits << endl ;
00818 
00819     if ( isCompressed()) {
00820 
00821         for ( i = 0 ; i < nBits ; i++ ) {
00822 
00823             d_ULong value  = in[i] ;
00824 
00825             if ( IS_COMPRESSED(value)) {
00826 
00827                 out[i] = BITS_31 | ( BITS_30 & ( ~value )) | ( BITS_29_00 & value ) ;
00828 
00829             } else {
00830 
00831                 out[i] = BITS_29_00 & ( ~value ) ;
00832 
00833             }
00834 
00835             d_ULong value1 = value ;
00836             d_ULong value2 = out[i] ;
00837 
00838   // DEBUG:            cout << endl ;
00839   // DEBUG:            cout << "                       value1: (31) (30) (29..0) = "
00840   // DEBUG:                 << ( BITS_31 == ( BITS_31 & value1 )) << " "
00841   // DEBUG:                 << ( BITS_30 == ( BITS_30 & value1 )) << " "
00842   // DEBUG:                 << ( BITS_29_00 & value1 ) << endl
00843   // DEBUG:                 << "                       value2: (31) (30) (29..0) = "
00844   // DEBUG:                 << ( BITS_31 == ( BITS_31 & value2 )) << " "
00845   // DEBUG:                 << ( BITS_30 == ( BITS_30 & value2 )) << " "
00846   // DEBUG:                 << ( BITS_29_00 & value2 ) << endl ;
00847 
00848         }
00849 
00850     } else {
00851 
00852       // The most significant two (31,30) bits
00853       // are zero-ed.
00854 
00855         for ( i = 0 ; i < nBits ; i++ ) {
00856             out[i] = BITS_29_00 & ( ~in[i] ) ;
00857         }
00858     }
00859 
00860   // Make a "last word alignment correction", by suppressing all meaningles
00861   // fantom "1" in the last word.
00862   // As it's might be seen from the code below, this kind of correction
00863   // is only done, when the last word is uncompressed and contains
00864   // less then 30 meaningfull bits.
00865   //
00866   // NOTE: The correction mechanism is based on an idea of a "magic
00867   //       quantum" of 30 events.
00868 
00869     d_ULong rem30 = getNumEvents() % 30 ;
00870 
00871     if ( rem30 && nBits ) {
00872 
00873       // DEBUG:     cout << endl ;
00874       // DEBUG:     cout << "BdbBMIndexQueryAPI::NOT rem30 " << rem30 << endl ;
00875 
00876         if ( ! IS_COMPRESSED(out[nBits-1])) {
00877 
00878           // Make a proper mask in order to enable the meaningfull
00879           // bits only.
00880 
00881             d_ULong bits29_00 = 0 ;
00882 
00883             for ( i = 0 ; i < rem30 ; i++ ) {
00884                 bits29_00 = ( 1 << i ) | bits29_00 ;
00885             }
00886 
00887             d_ULong value1 = out[nBits-1] ;
00888 
00889             out[nBits-1] = bits29_00 & out[nBits-1] ;
00890 
00891             d_ULong value2 = out[nBits-1];
00892 
00893           // DEBUG:            cout << endl ;
00894           // DEBUG:            cout << "                       value1: (31) (30) (29..0) = "
00895           // DEBUG:                 << ( BITS_31 == ( BITS_31 & value1 )) << " "
00896           // DEBUG:                 << ( BITS_30 == ( BITS_30 & value1 )) << " "
00897           // DEBUG:                 << ( BITS_29_00 & value1 ) << endl
00898           // DEBUG:                 << "                       value2: (31) (30) (29..0) = "
00899           // DEBUG:                 << ( BITS_31 == ( BITS_31 & value2 )) << " "
00900           // DEBUG:                 << ( BITS_30 == ( BITS_30 & value2 )) << " "
00901           // DEBUG:                 << ( BITS_29_00 & value2 ) << endl ;
00902 
00903         }
00904     }
00905 
00906     return BdbcSuccess ;
00907 }
00908 
00909 BdbStatus
00910 BdbBMIndexQueryAPI::AND(ooVArray(d_ULong)& out,
00911                         const ooVArray(d_ULong)& in1,
00912                         const ooVArray(d_ULong)& in2)
00913 {
00914     BdbStatus status ;
00915     d_ULong i ;
00916     d_ULong size1 = in1.size() ;
00917     d_ULong size2 = in2.size() ;
00918 
00919   // Perform AND depending
00920   // on the compressing method.
00921 
00922     if ( isCompressed()) {
00923 
00924         CompressionContext context(out) ;
00925 
00926         d_ULong num30 = getNumEvents() / 30 ;
00927         d_ULong rem30 = getNumEvents() % 30 ;
00928 
00929         d_ULong next1 = 0 ;
00930         d_ULong next2 = 0 ;
00931 
00932       // First we perform operation on "full" 30-bits words.
00933 
00934         d_ULong value1 ;
00935         d_ULong value2 ;
00936 
00937         d_ULong p1 ;
00938         d_ULong p2 ;
00939 
00940         d_Boolean empty1 = true ;
00941         d_Boolean empty2 = true ;
00942 
00943         for ( i = 0 ; i < num30 ; i++ ) {
00944 
00945           // Load the next (compressed/un-compressed) words
00946           // if nessesary.
00947           // Advance the "next" indexes as well.
00948           //
00949           // NOTE: indirect checking for the vectors consistency
00950           //       is done before to load next portion of data.
00951 
00952             if ( empty1 ) {
00953 
00954                 if ( next1 >= size1 ) {
00955                     error("- input vectors are inconsistent.") ;
00956                     return BdbcError ;
00957                 }
00958 
00959                 value1 = in1[next1++] ;
00960             }
00961 
00962             if ( empty2 ) {
00963 
00964                 if ( next2 >= size1 ) {
00965                     error("- input vectors are inconsistent.") ;
00966                     return BdbcError ;
00967                 }
00968 
00969                 value2 = in2[next2++] ;
00970             }
00971 
00972           // Get next portion of 30 bits depending
00973           // on whether the input word is compressed or not.
00974           // Update "empty" flag if desired.
00975 
00976             if ( IS_COMPRESSED(value1)) {
00977 
00978                 p1 = GET_30(value1) ;
00979                 empty1 = IS_EMPTY(value1) ;
00980 
00981             } else {
00982 
00983                 p1 = value1 ;
00984                 empty1 = true ;
00985 
00986             }
00987 
00988             if ( IS_COMPRESSED(value2)) {
00989 
00990                 p2 = GET_30(value2) ;
00991                 empty2 = IS_EMPTY(value2) ;
00992 
00993             } else {
00994 
00995                 p2 = value2 ;
00996                 empty2 = true ;
00997 
00998             }
00999 
01000           // Perform the operation on the values.
01001           // Save the results in the output vector.
01002 
01003             status = context.compress(p1 & p2, 0) ;
01004             if ( BdbcSuccess != status ) {
01005                 return status ;
01006             }
01007 
01008         }
01009 
01010       // Then we perform operation on the last word having less
01011       // then 30 usefull bits if desired, of course.
01012       // Save results in output vector.
01013 
01014         if ( rem30 ) {
01015 
01016           // Check if both vectors have the same length.
01017 
01018             if (( next1 >= size1 ) || ( next2 >= size2 )) {
01019                 error("- input vectors are inconsistent.") ;
01020                 return BdbcError ;
01021             }
01022 
01023             status = context.compress(in1[next1] & in2[next2], rem30) ;
01024             if ( BdbcSuccess != status ) {
01025                 return status ;
01026             }
01027         }
01028 
01029       // Synchronize the context.
01030 
01031         status = context.synchronize() ;
01032         if ( BdbcSuccess != status ) {
01033             return status ;
01034         }
01035 
01036     } else {
01037 
01038       // Check if both vectors have the same length.
01039 
01040         if ( size1 != size2 ) {
01041             error("- vectors have different length.") ;
01042             return BdbcError ;
01043         }
01044 
01045       // (Re-)allocate output vector of the same
01046       // size as the input ones.
01047 
01048          status = out.resize(size1) ;
01049         if ( BdbcSuccess != status ) {
01050             error("- vector resize.") ;
01051             return status ;
01052         }
01053 
01054         for ( i = 0 ; i < size1 ; i++ ) {
01055             out[i] = in1[i] & in2[i] ;
01056         }
01057     }
01058 
01059     return BdbcSuccess ;
01060 }
01061 
01062 BdbStatus
01063 BdbBMIndexQueryAPI::OR(ooVArray(d_ULong)& out,
01064                        const ooVArray(d_ULong)& in1,
01065                        const ooVArray(d_ULong)& in2)
01066 {
01067     BdbStatus status ;
01068     d_ULong i ;
01069     d_ULong size1 = in1.size() ;
01070     d_ULong size2 = in2.size() ;
01071 
01072   // Perform OR depending
01073   // on the compressing method.
01074 
01075     if ( isCompressed()) {
01076 
01077         CompressionContext context(out) ;
01078 
01079         d_ULong num30 = getNumEvents() / 30 ;
01080         d_ULong rem30 = getNumEvents() % 30 ;
01081 
01082       // DEBUG:        cout << "BdbBMIndexQueryAPI::OR" << endl
01083       // DEBUG:             << "    num30 = " << num30  << endl
01084       // DEBUG:             << "    rem30 = " << rem30  << endl
01085       // DEBUG:             << "    size1 = " << size1  << endl
01086       // DEBUG:             << "    size2 = " << size2  << endl ;
01087 
01088         d_ULong next1 = 0 ;
01089         d_ULong next2 = 0 ;
01090 
01091       // First we perform operation on "full" 30-bits words.
01092 
01093         d_ULong value1 ;
01094         d_ULong value2 ;
01095 
01096         d_ULong p1 ;
01097         d_ULong p2 ;
01098 
01099         d_Boolean empty1 = true ;
01100         d_Boolean empty2 = true ;
01101 
01102         for ( i = 0 ; i < num30 ; i++ ) {
01103 
01104           // Load the next (compressed/un-compressed) words
01105           // if nessesary.
01106           // Advance the "next" indexes as well.
01107           //
01108           // NOTE: indirect checking for the vectors consistency
01109           //       is done before to load next portion of data.
01110 
01111             if ( empty1 ) {
01112 
01113                 if ( next1 >= size1 ) {
01114                     error("- input vectors are inconsistent.") ;
01115 
01116                     cout << "BdbBMIndexQueryAPI::OR" << endl
01117                          << "    i     = " << i      << endl
01118                          << "    next1 = " << next1  << endl ;
01119 
01120                     return BdbcError ;
01121                 }
01122 
01123                 value1 = in1[next1++] ;
01124             }
01125 
01126             if ( empty2 ) {
01127 
01128                 if ( next2 >= size2 ) {
01129                     error("- input vectors are inconsistent.") ;
01130 
01131                     cout << "BdbBMIndexQueryAPI::OR" << endl
01132                          << "    i     = " << i      << endl
01133                          << "    next2 = " << next2  << endl ;
01134 
01135                     return BdbcError ;
01136                 }
01137 
01138                 value2 = in2[next2++] ;
01139             }
01140 
01141           // DEBUG:            cout << endl ;
01142           // DEBUG:            cout << "BdbBMIndexQueryAPI::OR num30" << endl
01143           // DEBUG:                 << "                       value1: (31) (30) (29..0) = "
01144           // DEBUG:                 << ( BITS_31 == ( BITS_31 & value1 )) << " "
01145           // DEBUG:                 << ( BITS_30 == ( BITS_30 & value1 )) << " "
01146           // DEBUG:                 << ( BITS_29_00 & value1 ) << endl
01147           // DEBUG:                 << "                       value2: (31) (30) (29..0) = "
01148           // DEBUG:                 << ( BITS_31 == ( BITS_31 & value2 )) << " "
01149           // DEBUG:                 << ( BITS_30 == ( BITS_30 & value2 )) << " "
01150           // DEBUG:                 << ( BITS_29_00 & value2 ) << endl ;
01151 
01152           // Get next portion of 30 bits depending
01153           // on whether the input word is compressed or not.
01154           // Update "empty" flag if desired.
01155 
01156             if ( IS_COMPRESSED(value1)) {
01157 
01158                 p1 = GET_30(value1) ;
01159                 empty1 = IS_EMPTY(value1) ;
01160 
01161             } else {
01162 
01163                 p1 = value1 ;
01164                 empty1 = true ;
01165 
01166             }
01167 
01168             if ( IS_COMPRESSED(value2)) {
01169 
01170                 p2 = GET_30(value2) ;
01171                 empty2 = IS_EMPTY(value2) ;
01172 
01173             } else {
01174 
01175                 p2 = value2 ;
01176                 empty2 = true ;
01177 
01178             }
01179 
01180           // DEBUG:            cout << endl
01181           // DEBUG:                 << "                       value1: (31) (30) (29..0) = "
01182           // DEBUG:                 << ( BITS_31 == ( BITS_31 & value1 )) << " "
01183           // DEBUG:                 << ( BITS_30 == ( BITS_30 & value1 )) << " "
01184           // DEBUG:                 << ( BITS_29_00 & value1 ) << endl
01185           // DEBUG:                 << "                       value2: (31) (30) (29..0) = "
01186           // DEBUG:                 << ( BITS_31 == ( BITS_31 & value2 )) << " "
01187           // DEBUG:                 << ( BITS_30 == ( BITS_30 & value2 )) << " "
01188           // DEBUG:                 << ( BITS_29_00 & value2 ) << endl ;
01189 
01190           // Perform the operation on the values.
01191           // Save the results in the output vector.
01192 
01193             status = context.compress(p1 | p2, 0) ;
01194             if ( BdbcSuccess != status ) {
01195                 return status ;
01196             }
01197 
01198         }
01199 
01200       // Then we perform operation on the last word having less
01201       // then 30 usefull bits if desired, of course.
01202       // Save results in output vector.
01203 
01204         if ( rem30 ) {
01205 
01206           // Check if both vectors have the same length.
01207 
01208             if (( next1 >= size1 ) || ( next2 >= size2 )) {
01209                 error("- input vectors are inconsistent.") ;
01210                 return BdbcError ;
01211             }
01212 
01213           // DEBUG:            d_ULong value1 = in1[next1] ;
01214           // DEBUG:            d_ULong value2 = in2[next2] ;
01215           // DEBUG:
01216           // DEBUG:            cout << endl ;
01217           // DEBUG:            cout << "BdbBMIndexQueryAPI::OR rem30" << endl
01218           // DEBUG:                 << "                       value1: (31) (30) (29..0) = "
01219           // DEBUG:                 << ( BITS_31 == ( BITS_31 & value1 )) << " "
01220           // DEBUG:                 << ( BITS_30 == ( BITS_30 & value1 )) << " "
01221           // DEBUG:                 << ( BITS_29_00 & value1 ) << endl
01222           // DEBUG:                 << "                       value2: (31) (30) (29..0) = "
01223           // DEBUG:                 << ( BITS_31 == ( BITS_31 & value2 )) << " "
01224           // DEBUG:                 << ( BITS_30 == ( BITS_30 & value2 )) << " "
01225           // DEBUG:                 << ( BITS_29_00 & value2 ) << endl ;
01226 
01227             status = context.compress(in1[next1] | in2[next2], rem30) ;
01228             if ( BdbcSuccess != status ) {
01229                 return status ;
01230             }
01231         }
01232 
01233       // Synchronize the context.
01234 
01235         status = context.synchronize() ;
01236         if ( BdbcSuccess != status ) {
01237             return status ;
01238         }
01239 
01240     } else {
01241 
01242       // Check if both vectors have the same length.
01243 
01244         if ( size1 != size2 ) {
01245             error("- vectors have different length.") ;
01246             return BdbcError ;
01247         }
01248 
01249       // (Re-)allocate output vector of the same
01250       // size as the input ones.
01251 
01252         status = out.resize(size1) ;
01253         if ( BdbcSuccess != status ) {
01254             error("- vector resize.") ;
01255             return status ;
01256         }
01257 
01258         for ( i = 0 ; i < size1 ; i++ ) {
01259             out[i] = in1[i] | in2[i] ;
01260         }
01261     }
01262 
01263     return BdbcSuccess ;
01264 }
01265 
01266 BdbStatus
01267 BdbBMIndexQueryAPI::ONE(ooVArray(d_ULong)& out,
01268     d_ULong elements)
01269 {
01270     return ONE_OR_ZERO(out, elements, 1) ;
01271 }
01272 
01273 BdbStatus
01274 BdbBMIndexQueryAPI::ZERO(ooVArray(d_ULong)& out,
01275     d_ULong elements)
01276 {
01277     return ONE_OR_ZERO(out, elements, 0) ;
01278 }
01279 
01280 BdbStatus
01281 BdbBMIndexQueryAPI::ONE_OR_ZERO(ooVArray(d_ULong)& out,
01282                                 d_ULong elements,
01283                                 d_ULong bit)
01284 {
01285     BdbStatus status ;
01286     d_ULong i ;
01287     d_ULong vectorSize ;
01288     d_ULong num30 = (BITS_29_00 & elements) / 30 ;  // Use 30 bits only.
01289     d_ULong rem30 = (BITS_29_00 & elements) % 30 ;  // Use 30 bits only.
01290 
01291   // Create a bit vector with all the elements set either to "1" or to "0",
01292   // depending on the value of specified parameter.
01293   // The vector is created either compressed or not depending
01294   // on the status of the open database.
01295 
01296     if ( isCompressed()) {
01297 
01298       // COMPRESSED vectors.
01299 
01300         vectorSize = 1 ;
01301         if ( rem30 ) {
01302             vectorSize++ ;
01303         }
01304 
01305         status = out.resize(vectorSize) ;
01306         if ( BdbcSuccess != status ) {
01307             error("- vector resize.") ;
01308             return status ;
01309         }
01310 
01311       // Compress the first word of the vector.
01312 
01313         out[0] = ( BITS_31 | ( bit << 30 )) | ( 30 * num30 ) ;
01314 
01315       // Fill the second word of the vector by raw bit string if desired.
01316 
01317         if ( rem30 ) {
01318 
01319             out[1] = 0 ;
01320 
01321             for ( i = 0 ; i < rem30 ; i++ ) {
01322                 out[1] = out[1] | ( bit << i ) ;
01323             }
01324         }
01325 
01326     } else {
01327 
01328       // NON-COMPRESSED vectors.
01329 
01330         vectorSize = num30 ;
01331         if ( rem30 ) {
01332             vectorSize++ ;
01333         }
01334 
01335         status = out.resize(vectorSize) ;
01336         if ( BdbcSuccess != status ) {
01337             error("- vector resize.") ;
01338             return status ;
01339         }
01340 
01341       // Fill the first complete words of the vector by
01342       // raw bit strings.
01343 
01344         for ( d_ULong j = 0 ; j < vectorSize - 1 ; j++ ) {
01345 
01346             out[j] = 0 ;
01347 
01348             for ( i = 0 ; i < 30 ; i++ ) {
01349                 out[j] = out[j] | ( bit << i ) ;
01350             }
01351 
01352         }
01353 
01354       // Fill the last word of the vector by raw bit string if desired.
01355 
01356         if ( rem30 ) {
01357 
01358             out[vectorSize-1] = 0 ;
01359 
01360             for ( i = 0 ; i < rem30 ; i++ ) {
01361                 out[vectorSize-1] = out[vectorSize-1] | ( bit << i ) ;
01362             }
01363         }
01364     }
01365 
01366     return BdbcSuccess ;
01367 }
01368 
01369 d_ULong
01370 BdbBMIndexQueryAPI::GET_30(d_ULong& value)
01371 {
01372 
01373   // Decrement input value by 30.
01374 
01375     value = ( BITS_31_30 & value ) | (( BITS_29_00 & value ) - 30 ) ;
01376 
01377   // Return the mask of "30-th" depending on the compressing
01378   // contents: "1" or "0".
01379 
01380     if ( BITS_30 == ( BITS_30 & value ))
01381         return BITS_29_00 ;
01382     else
01383         return 0 ;
01384 }
01385 
01386 
01387 /** ----------------------------------------------------------
01388  ** The following helper functions gather the query estimation
01389  ** statistics based on already done events pre-selections.
01390  ** ----------------------------------------------------------
01391  **/
01392 
01393 d_ULong
01394 BdbBMIndexQueryAPI::estimateNumEvents(const ooVArray(d_ULong)& in)
01395 {
01396     d_ULong events = 0 ;
01397     d_ULong vectorSize = in.size() ;
01398 
01399   // DEBUG:    cout << endl ;
01400   // DEBUG:    cout << "BdbBMIndexQueryAPI::estimateNumEvents vectorSize = " << vectorSize << endl ;
01401   // DEBUG:
01402   // DEBUG:    cout << "1: events = " << events << endl ;
01403 
01404     for ( d_ULong i = 0 ; i < vectorSize ; i++ ) {
01405 
01406         d_ULong value = in[i] ;
01407 
01408 
01409       // DEBUG:        cout << endl ;
01410       // DEBUG:        cout << "                       value:  (31) (30) (29..0) = "
01411       // DEBUG:             << ( BITS_31 == ( BITS_31 & value )) << " "
01412       // DEBUG:             << ( BITS_30 == ( BITS_30 & value )) << " "
01413       // DEBUG:             << ( BITS_29_00 & value ) << endl ;
01414 
01415       // For compressed words, we take into account only those
01416       // words where the "1"-s were compressed.
01417       //
01418       // Otherwise we count each bit in a word. In this case
01419       // a small optimization is done in order to skip the completelly
01420       // "empty" (= 0) words.
01421 
01422         d_ULong mask = ( BITS_31_30 & value ) ;
01423 
01424         switch ( mask ) {
01425 
01426         case BITS_31_30:
01427 
01428             events = events + ( BITS_29_00 & value ) ;
01429 
01430           // DEBUG:            cout << "2: events = " << events << endl ;
01431 
01432             break ;
01433 
01434         case BITS_31:
01435         case BITS_30:
01436 
01437           // DEBUG:            cout << "x: value      = " << value << endl ;
01438           // DEBUG:            cout << "   mask       = " << mask  << endl ;
01439           // DEBUG:            cout << "   BITS_31_30 = " << BITS_31_30  << endl ;
01440 
01441             break ;
01442 
01443         default:
01444 
01445             if ( value ) {
01446                 for ( d_ULong j = 0 ; j < 30 ; j++ ) {
01447                     if ( value & ( 1 << j )) {
01448                         events++ ;
01449                     }
01450                 }
01451             }
01452 
01453           // DEBUG:            cout << "3: events = " << events << endl ;
01454 
01455             break ;
01456         }
01457     }
01458 
01459   // DEBUG:    cout << "4: events = " << events << endl ;
01460 
01461     return events ;
01462 }
01463 
01464 /**--------------------------
01465  **  Transaction management
01466  **--------------------------
01467  **/
01468 
01469 void
01470 BdbBMIndexQueryAPI::startUpdate( const char* theTag )
01471 {
01472     BdbApplication* theApp = BdbApplication::instance( );
01473     theApp->startUpdate( "Indexing", theTag );
01474 }
01475 
01476 void
01477 BdbBMIndexQueryAPI::startRead( const char* theTag )
01478 {
01479     BdbApplication* theApp = BdbApplication::instance( );
01480     theApp->startRead( "Indexing", theTag );
01481 }
01482 
01483 void
01484 BdbBMIndexQueryAPI::abort( )
01485 {
01486     BdbApplication* theApp = BdbApplication::instance( );
01487     theApp->abort( "Indexing" );
01488 }
01489 
01490 void
01491 BdbBMIndexQueryAPI::commit( )
01492 {
01493     BdbApplication* theApp = BdbApplication::instance( );
01494     theApp->commit( "Indexing" );
01495 }
01496 
01497 /** -----------------------------------------------------------
01498  **  Implementation for the nested class of CompressionContext
01499  ** -----------------------------------------------------------
01500  **/
01501 
01502 BdbBMIndexQueryAPI::CompressionContext::CompressionContext(ooVArray(d_ULong)& out) :
01503 _isCompressing(false),
01504 _out(out)
01505 {
01506 }
01507 
01508 BdbBMIndexQueryAPI::CompressionContext::~CompressionContext()
01509 {
01510     synchronize() ;
01511 }
01512 
01513 BdbStatus
01514 BdbBMIndexQueryAPI::CompressionContext::compress(d_ULong value, d_ULong rem30)
01515 {
01516     BdbStatus status ;
01517 
01518   // Is input value compressed ?
01519 
01520     if ( IS_COMPRESSED(value)) {
01521 
01522         if ( _isCompressing ) {
01523 
01524           // Are we compressing the same ("0" or "1")?
01525 
01526             if (((   _isZero ) && ( ! value ))
01527                                ||
01528                 (( ! _isZero ) && (   value ))) {
01529 
01530               // Yes. We are already compressing the same.
01531               // Here we just update the compression counter.
01532 
01533               _counter += ( BITS_29_00 & value ) ;
01534 
01535             } else {
01536 
01537               // Since we were compressing "something" different,
01538               // first we have to flash it and then start
01539               // compressing new stuff.
01540 
01541                 status = synchronize() ;
01542                 if ( status != BdbcSuccess ) {
01543                     return status ;
01544                 }
01545 
01546                 _isCompressing = true ;
01547                 _isZero        = ( BITS_30 != ( BITS_30 & value )) ;
01548                 _counter       = ( BITS_29_00 & value ) ;
01549 
01550             }
01551 
01552         } else {
01553 
01554           // Start compressing new stuff.
01555 
01556             _isCompressing = true ;
01557             _isZero        = ( BITS_30 != ( BITS_30 & value )) ;
01558             _counter       = ( BITS_29_00 & value ) ;
01559 
01560         }
01561 
01562     } else {
01563 
01564       // Check if it's the last uncompleted word of the bit string,
01565       // having other then 30 "usefull" bits.
01566       // In this case we just flush the existing compression and flush
01567       // this last word as well.
01568       // Otherwise we will try to make a routine compression if possible.
01569 
01570         if ( rem30 ) {
01571 
01572             if ( _isCompressing ) {
01573 
01574                 status = synchronize() ;
01575                 if ( status != BdbcSuccess ) {
01576                     return status ;
01577                 }
01578             }
01579 
01580           // Select meaningfull bits only.
01581 
01582             d_ULong usefull_bits = 0 ;
01583 
01584             for ( d_ULong i = 0 ; i < rem30 ; i++ ) {
01585               usefull_bits = ( 1 << i ) | usefull_bits ;
01586             }
01587 
01588             value = usefull_bits & value ;
01589 
01590           // Then imediatelly flash the new value.
01591 
01592             status = _out.extend(value) ;
01593             if ( status != BdbcSuccess ) {
01594                 return status ;
01595             }
01596 
01597         } else {
01598 
01599           // Possible to compress this word?
01600 
01601             if (( BITS_29_00 == ( BITS_29_00 & value )) || ( ! value )) {
01602 
01603                 if ( _isCompressing ) {
01604 
01605                   // Are we compressing the same ("0" or "1")?
01606 
01607                     if (((   _isZero ) && ( ! value ))
01608                                        ||
01609                         (( ! _isZero ) && (   value ))) {
01610 
01611                       // Yes. We are already compressing the same.
01612                       // Here we just update the compression counter.
01613 
01614                         _counter += 30 ;
01615 
01616                     } else {
01617 
01618                       // Since we were compressing "something" different,
01619                       // first we have to flash it and then start
01620                       // compressing new stuff.
01621 
01622                         status = synchronize() ;
01623                         if ( status != BdbcSuccess ) {
01624                             return status ;
01625                         }
01626 
01627                         _isCompressing = true ;
01628                         _isZero        = ! value ;
01629                         _counter       = 30 ;
01630 
01631                     }
01632                 } else {
01633 
01634                   // Start compressing new stuff.
01635 
01636                     _isCompressing = true ;
01637                     _isZero        = ! value ;
01638                     _counter       = 30 ;
01639 
01640                 }
01641 
01642             } else {
01643 
01644               //  Compressing is not possible.
01645               //  If we are already compressing somthing, we should
01646               //  flash compression buffer before to flush the temporary one.
01647 
01648                 status = synchronize() ;
01649                 if ( status != BdbcSuccess ) {
01650                     return status ;
01651                 }
01652 
01653               // Then imediatelly flash the new value.
01654 
01655                 status = _out.extend(value) ;
01656                 if ( status != BdbcSuccess ) {
01657                     return status ;
01658                 }
01659             }
01660         }
01661     }
01662 
01663   // DEBUG:    cout << "CompressionContext: value       = " << value
01664   //                << "  _counter = " << _counter << endl ;
01665   // DEBUG:    cout << "                    _out.size() =" << (d_ULong) _out.size() << endl ;
01666 
01667     return BdbcSuccess ;
01668 }
01669 
01670 BdbStatus
01671 BdbBMIndexQueryAPI::CompressionContext::synchronize()
01672 {
01673     BdbStatus status ;
01674 
01675   //  If we are already compressing somthing, we should
01676   //  flash compression buffer.
01677 
01678     if ( _isCompressing ) {
01679 
01680         if ( _isZero ) {
01681             _counter = BITS_31    | _counter ;
01682         } else {
01683             _counter = BITS_31_30 | _counter ;
01684         }
01685 
01686         status = _out.extend(_counter) ;
01687         if ( status != BdbcSuccess ) {
01688             return status ;
01689         }
01690 
01691         _isCompressing = false ;
01692     }
01693 
01694     return BdbcSuccess ;
01695 }
01696 
01697 /////////////////
01698 // End Of File //
01699 /////////////////

 


BaBar Public Site | SLAC | News | Links | Who's Who | Contact Us

Page Owner: Jacek Becla
Last Update: October 04, 2002