Back to index

lightning-sunbird  0.9+nobinonly
orkinStore.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifndef _MDB_
00039 #include "mdb.h"
00040 #endif
00041 
00042 #ifndef _MORK_
00043 #include "mork.h"
00044 #endif
00045 
00046 #ifndef _MORKNODE_
00047 #include "morkNode.h"
00048 #endif
00049 
00050 #ifndef _MORKHANDLE_
00051 #include "morkHandle.h"
00052 #endif
00053 
00054 #ifndef _MORKSTORE_
00055 #include "morkStore.h"
00056 #endif
00057 
00058 #ifndef _MORKENV_
00059 #include "morkEnv.h"
00060 #endif
00061 
00062 #ifndef _ORKINSTORE_
00063 #include "orkinStore.h"
00064 #endif
00065 
00066 #ifndef _MORKTABLE_
00067 #include "morkTable.h"
00068 #endif
00069 
00070 #ifndef _MORKPORTTABLECURSOR_
00071 #include "morkPortTableCursor.h"
00072 #endif
00073 
00074 #ifndef _ORKINPORTTABLECURSOR_
00075 #include "orkinPortTableCursor.h"
00076 #endif
00077 
00078 #ifndef _MORKROW_
00079 #include "morkRow.h"
00080 #endif
00081 
00082 #ifndef _MORKROWOBJECT_
00083 #include "morkRowObject.h"
00084 #endif
00085 
00086 #ifndef _MORKTHUMB_
00087 #include "morkThumb.h"
00088 #endif
00089 
00090 // #ifndef _MORKFILE_
00091 // #include "morkFile.h"
00092 // #endif
00093 
00094 #ifndef _ORKINTHUMB_
00095 #include "orkinThumb.h"
00096 #endif
00097 
00098 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00099 
00100 /* public virtual*/
00101 orkinStore:: ~orkinStore() // morkHandle destructor does everything
00102 {
00103 }
00104 
00105 /*protected non-poly construction*/
00106 orkinStore::orkinStore(morkEnv* ev, // morkUsage is morkUsage_kPool
00107     morkHandleFace* ioFace,    // must not be nil, cookie for this handle
00108     morkStore* ioObject)  // must not be nil, the object for this handle
00109 : morkHandle(ev, ioFace, ioObject, morkMagic_kStore)
00110 {
00111   // do not modify mNode_Derived; leave it equal to morkDerived_kHandle
00112 }
00113 
00114 
00115 /*static */ orkinStore*
00116 orkinStore::MakeStore(morkEnv* ev, morkStore* ioObject)
00117 {
00118   mork_bool isEnv = ev->IsEnv();
00119   MORK_ASSERT(isEnv);
00120   if ( isEnv )
00121   {
00122     morkHandleFace* face = ev->NewHandle(sizeof(orkinStore));
00123     if ( face )
00124       return new(face) orkinStore(ev, face, ioObject);
00125     else
00126       ev->OutOfMemoryError();
00127   }
00128     
00129   return (orkinStore*) 0;
00130 }
00131 
00132 morkEnv*
00133 orkinStore::CanUseStore(nsIMdbEnv* mev,
00134   mork_bool inMutable, mdb_err* outErr) const
00135 {
00136   morkEnv* outEnv = 0;
00137   morkEnv* ev = morkEnv::FromMdbEnv(mev);
00138   if ( ev )
00139   {
00140     morkStore* self = (morkStore*)
00141       this->GetGoodHandleObject(ev, inMutable, morkMagic_kStore,
00142         /*inClosedOkay*/ morkBool_kFalse);
00143     if ( self )
00144     {
00145       if ( self->IsStore() )
00146         outEnv = ev;
00147       else
00148         self->NonStoreTypeError(ev);
00149     }
00150     *outErr = ev->AsErr();
00151   }
00152   MORK_ASSERT(outEnv);
00153   return outEnv;
00154 }
00155 
00156 // { ===== begin nsIMdbISupports methods =====
00157 
00158 NS_IMPL_QUERY_INTERFACE0(orkinStore)
00159 
00160 /*virtual*/ nsrefcnt
00161 orkinStore::AddRef() // add strong ref with no
00162 {
00163   morkEnv* ev = mHandle_Env;
00164   if ( ev && ev->IsEnv() )
00165     return this->Handle_AddStrongRef(ev->AsMdbEnv());
00166   else
00167     return morkEnv_kNonEnvTypeError;
00168 }
00169 
00170 /*virtual*/ nsrefcnt
00171 orkinStore::Release() // cut strong ref
00172 {
00173   morkEnv* ev = mHandle_Env;
00174   if ( ev && ev->IsEnv() )
00175     return this->Handle_CutStrongRef(ev->AsMdbEnv());
00176   else
00177     return morkEnv_kNonEnvTypeError;
00178 }
00179 // } ===== end nsIMdbISupports methods =====
00180 
00181 // { ===== begin nsIMdbObject methods =====
00182 
00183 // { ----- begin attribute methods -----
00184 /*virtual*/ mdb_err
00185 orkinStore::IsFrozenMdbObject(nsIMdbEnv* mev, mdb_bool* outIsReadonly)
00186 {
00187   return this->Handle_IsFrozenMdbObject(mev, outIsReadonly);
00188 }
00189 // same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port.
00190 // } ----- end attribute methods -----
00191 
00192 // { ----- begin factory methods -----
00193 /*virtual*/ mdb_err
00194 orkinStore::GetMdbFactory(nsIMdbEnv* mev, nsIMdbFactory** acqFactory)
00195 {
00196   return this->Handle_GetMdbFactory(mev, acqFactory);
00197 } 
00198 // } ----- end factory methods -----
00199 
00200 // { ----- begin ref counting for well-behaved cyclic graphs -----
00201 /*virtual*/ mdb_err
00202 orkinStore::GetWeakRefCount(nsIMdbEnv* mev, // weak refs
00203   mdb_count* outCount)
00204 {
00205   return this->Handle_GetWeakRefCount(mev, outCount);
00206 }  
00207 /*virtual*/ mdb_err
00208 orkinStore::GetStrongRefCount(nsIMdbEnv* mev, // strong refs
00209   mdb_count* outCount)
00210 {
00211   return this->Handle_GetStrongRefCount(mev, outCount);
00212 }
00213 
00214 /*virtual*/ mdb_err
00215 orkinStore::AddWeakRef(nsIMdbEnv* mev)
00216 {
00217   return this->Handle_AddWeakRef(mev);
00218 }
00219 /*virtual*/ mdb_err
00220 orkinStore::AddStrongRef(nsIMdbEnv* mev)
00221 {
00222   return this->Handle_AddStrongRef(mev);
00223 }
00224 
00225 /*virtual*/ mdb_err
00226 orkinStore::CutWeakRef(nsIMdbEnv* mev)
00227 {
00228   return this->Handle_CutWeakRef(mev);
00229 }
00230 /*virtual*/ mdb_err
00231 orkinStore::CutStrongRef(nsIMdbEnv* mev)
00232 {
00233   return this->Handle_CutStrongRef(mev);
00234 }
00235 
00236 /*virtual*/ mdb_err
00237 orkinStore::CloseMdbObject(nsIMdbEnv* mev)
00238 {
00239   return this->Handle_CloseMdbObject(mev);
00240 }
00241 
00242 /*virtual*/ mdb_err
00243 orkinStore::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen)
00244 {
00245   return this->Handle_IsOpenMdbObject(mev, outOpen);
00246 }
00247 // } ----- end ref counting -----
00248 
00249 // } ===== end nsIMdbObject methods =====
00250 
00251 // { ===== begin nsIMdbPort methods =====
00252 
00253 // { ----- begin attribute methods -----
00254 /*virtual*/ mdb_err
00255 orkinStore::GetIsPortReadonly(nsIMdbEnv* mev, mdb_bool* outBool)
00256 {
00257   mdb_err outErr = 0;
00258   mdb_bool isReadOnly = morkBool_kFalse;
00259   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00260   if ( ev )
00261   {
00262     ev->StubMethodOnlyError();
00263     outErr = ev->AsErr();
00264   }
00265   if ( outBool )
00266     *outBool = isReadOnly;
00267   return outErr;
00268 }
00269 
00270 /*virtual*/ mdb_err
00271 orkinStore::GetIsStore(nsIMdbEnv* mev, mdb_bool* outBool)
00272 {
00273   MORK_USED_1(mev);
00274  if ( outBool )
00275     *outBool = morkBool_kTrue;
00276   return 0;
00277 }
00278 
00279 /*virtual*/ mdb_err
00280 orkinStore::GetIsStoreAndDirty(nsIMdbEnv* mev, mdb_bool* outBool)
00281 {
00282   mdb_err outErr = 0;
00283   mdb_bool isStoreAndDirty = morkBool_kFalse;
00284   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00285   if ( ev )
00286   {
00287     ev->StubMethodOnlyError();
00288     outErr = ev->AsErr();
00289   }
00290   if ( outBool )
00291     *outBool = isStoreAndDirty;
00292   return outErr;
00293 }
00294 
00295 /*virtual*/ mdb_err
00296 orkinStore::GetUsagePolicy(nsIMdbEnv* mev, 
00297   mdbUsagePolicy* ioUsagePolicy)
00298 {
00299   MORK_USED_1(ioUsagePolicy);
00300   mdb_err outErr = 0;
00301   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00302   if ( ev )
00303   {
00304     ev->StubMethodOnlyError();
00305     outErr = ev->AsErr();
00306   }
00307   return outErr;
00308 }
00309 
00310 /*virtual*/ mdb_err
00311 orkinStore::SetUsagePolicy(nsIMdbEnv* mev, 
00312   const mdbUsagePolicy* inUsagePolicy)
00313 {
00314   MORK_USED_1(inUsagePolicy);
00315   mdb_err outErr = 0;
00316   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00317   if ( ev )
00318   {
00319     // ev->StubMethodOnlyError(); // okay to do nothing?
00320     outErr = ev->AsErr();
00321   }
00322   return outErr;
00323 }
00324 // } ----- end attribute methods -----
00325 
00326 // { ----- begin memory policy methods -----  
00327 /*virtual*/ mdb_err
00328 orkinStore::IdleMemoryPurge( // do memory management already scheduled
00329   nsIMdbEnv* mev, // context
00330   mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed
00331 {
00332   mdb_err outErr = 0;
00333   mdb_size estimatedBytesFreed = 0;
00334   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00335   if ( ev )
00336   {
00337     // ev->StubMethodOnlyError(); // okay to do nothing?
00338     outErr = ev->AsErr();
00339   }
00340   if ( outEstimatedBytesFreed )
00341     *outEstimatedBytesFreed = estimatedBytesFreed;
00342   return outErr;
00343 }
00344 
00345 /*virtual*/ mdb_err
00346 orkinStore::SessionMemoryPurge( // request specific footprint decrease
00347   nsIMdbEnv* mev, // context
00348   mdb_size inDesiredBytesFreed, // approximate number of bytes wanted
00349   mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed
00350 {
00351   MORK_USED_1(inDesiredBytesFreed);
00352   mdb_err outErr = 0;
00353   mdb_size estimate = 0;
00354   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00355   if ( ev )
00356   {
00357     // ev->StubMethodOnlyError(); // okay to do nothing?
00358     outErr = ev->AsErr();
00359   }
00360   if ( outEstimatedBytesFreed )
00361     *outEstimatedBytesFreed = estimate;
00362   return outErr;
00363 }
00364 
00365 /*virtual*/ mdb_err
00366 orkinStore::PanicMemoryPurge( // desperately free all possible memory
00367   nsIMdbEnv* mev, // context
00368   mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed
00369 {
00370   mdb_err outErr = 0;
00371   mdb_size estimate = 0;
00372   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00373   if ( ev )
00374   {
00375     // ev->StubMethodOnlyError(); // okay to do nothing?
00376     outErr = ev->AsErr();
00377   }
00378   if ( outEstimatedBytesFreed )
00379     *outEstimatedBytesFreed = estimate;
00380   return outErr;
00381 }
00382 // } ----- end memory policy methods -----
00383 
00384 // { ----- begin filepath methods -----
00385 /*virtual*/ mdb_err
00386 orkinStore::GetPortFilePath(
00387   nsIMdbEnv* mev, // context
00388   mdbYarn* outFilePath, // name of file holding port content
00389   mdbYarn* outFormatVersion) // file format description
00390 {
00391   mdb_err outErr = 0;
00392   if ( outFormatVersion )
00393     outFormatVersion->mYarn_Fill = 0;
00394   if ( outFilePath )
00395     outFilePath->mYarn_Fill = 0;
00396   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00397   if ( ev )
00398   {
00399     morkStore* store = (morkStore*) mHandle_Object;
00400     nsIMdbFile* file = store->mStore_File;
00401     
00402     if ( file )
00403       file->Path(mev, outFilePath);
00404     else
00405       store->NilStoreFileError(ev);
00406     
00407     outErr = ev->AsErr();
00408   }
00409   return outErr;
00410 }
00411 
00412 /*virtual*/ mdb_err
00413 orkinStore::GetPortFile(
00414   nsIMdbEnv* mev, // context
00415   nsIMdbFile** acqFile) // acquire file used by port or store
00416 {
00417   mdb_err outErr = 0;
00418   if ( acqFile )
00419     *acqFile = 0;
00420 
00421   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00422   if ( ev )
00423   {
00424     morkStore* store = (morkStore*) mHandle_Object;
00425     nsIMdbFile* file = store->mStore_File;
00426     
00427     if ( file )
00428     {
00429       if ( acqFile )
00430       {
00431         file->AddStrongRef(mev);
00432         if ( ev->Good() )
00433           *acqFile = file;
00434       }
00435     }
00436     else
00437       store->NilStoreFileError(ev);
00438       
00439     outErr = ev->AsErr();
00440   }
00441   return outErr;
00442 }
00443 // } ----- end filepath methods -----
00444 
00445 // { ----- begin export methods -----
00446 /*virtual*/ mdb_err
00447 orkinStore::BestExportFormat( // determine preferred export format
00448   nsIMdbEnv* mev, // context
00449   mdbYarn* outFormatVersion) // file format description
00450 {
00451   mdb_err outErr = 0;
00452   if ( outFormatVersion )
00453     outFormatVersion->mYarn_Fill = 0;
00454   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00455   if ( ev )
00456   {
00457     ev->StubMethodOnlyError();
00458     outErr = ev->AsErr();
00459   }
00460   return outErr;
00461 }
00462 
00463 /*virtual*/ mdb_err
00464 orkinStore::CanExportToFormat( // can export content in given specific format?
00465   nsIMdbEnv* mev, // context
00466   const char* inFormatVersion, // file format description
00467   mdb_bool* outCanExport) // whether ExportSource() might succeed
00468 {
00469   MORK_USED_1(inFormatVersion);
00470   mdb_bool canExport = morkBool_kFalse;
00471   mdb_err outErr = 0;
00472   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00473   if ( ev )
00474   {
00475     ev->StubMethodOnlyError();
00476     outErr = ev->AsErr();
00477   }
00478   if ( outCanExport )
00479     *outCanExport = canExport;
00480   return outErr;
00481 }
00482 
00483 /*virtual*/ mdb_err
00484 orkinStore::ExportToFormat( // export content in given specific format
00485   nsIMdbEnv* mev, // context
00486   // const char* inFilePath, // the file to receive exported content
00487   nsIMdbFile* ioFile, // destination abstract file interface
00488   const char* inFormatVersion, // file format description
00489   nsIMdbThumb** acqThumb) // acquire thumb for incremental export
00490 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
00491 // then the export will be finished.
00492 {
00493   mdb_err outErr = 0;
00494   nsIMdbThumb* outThumb = 0;
00495   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00496   if ( ev )
00497   {
00498     if ( ioFile && inFormatVersion && acqThumb )
00499     {
00500       ev->StubMethodOnlyError();
00501     }
00502     else
00503       ev->NilPointerError();
00504     
00505     outErr = ev->AsErr();
00506   }
00507   if ( acqThumb )
00508     *acqThumb = outThumb;
00509   return outErr;
00510 }
00511 
00512 // } ----- end export methods -----
00513 
00514 // { ----- begin token methods -----
00515 /*virtual*/ mdb_err
00516 orkinStore::TokenToString( // return a string name for an integer token
00517   nsIMdbEnv* mev, // context
00518   mdb_token inToken, // token for inTokenName inside this port
00519   mdbYarn* outTokenName) // the type of table to access
00520 {
00521   mdb_err outErr = 0;
00522   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00523   if ( ev )
00524   {
00525     ((morkStore*) mHandle_Object)->TokenToString(ev, inToken, outTokenName);
00526     outErr = ev->AsErr();
00527   }
00528   return outErr;
00529 }
00530 
00531 /*virtual*/ mdb_err
00532 orkinStore::StringToToken( // return an integer token for scope name
00533   nsIMdbEnv* mev, // context
00534   const char* inTokenName, // Latin1 string to tokenize if possible
00535   mdb_token* outToken) // token for inTokenName inside this port
00536   // String token zero is never used and never supported. If the port
00537   // is a mutable store, then StringToToken() to create a new
00538   // association of inTokenName with a new integer token if possible.
00539   // But a readonly port will return zero for an unknown scope name.
00540 {
00541   mdb_err outErr = 0;
00542   mdb_token token = 0;
00543   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00544   if ( ev )
00545   {
00546     token = ((morkStore*) mHandle_Object)->StringToToken(ev, inTokenName);
00547     outErr = ev->AsErr();
00548   }
00549   if ( outToken )
00550     *outToken = token;
00551   return outErr;
00552 }
00553   
00554 
00555 /*virtual*/ mdb_err
00556 orkinStore::QueryToken( // like StringToToken(), but without adding
00557   nsIMdbEnv* mev, // context
00558   const char* inTokenName, // Latin1 string to tokenize if possible
00559   mdb_token* outToken) // token for inTokenName inside this port
00560   // QueryToken() will return a string token if one already exists,
00561   // but unlike StringToToken(), will not assign a new token if not
00562   // already in use.
00563 {
00564   mdb_err outErr = 0;
00565   mdb_token token = 0;
00566   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00567   if ( ev )
00568   {
00569     token = ((morkStore*) mHandle_Object)->QueryToken(ev, inTokenName);
00570     outErr = ev->AsErr();
00571   }
00572   if ( outToken )
00573     *outToken = token;
00574   return outErr;
00575 }
00576 
00577 
00578 // } ----- end token methods -----
00579 
00580 // { ----- begin row methods -----  
00581 /*virtual*/ mdb_err
00582 orkinStore::HasRow( // contains a row with the specified oid?
00583   nsIMdbEnv* mev, // context
00584   const mdbOid* inOid,  // hypothetical row oid
00585   mdb_bool* outHasRow) // whether GetRow() might succeed
00586 {
00587   mdb_err outErr = 0;
00588   mdb_bool hasRow = morkBool_kFalse;
00589   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00590   if ( ev )
00591   {
00592     morkStore* store = (morkStore*) mHandle_Object;
00593     morkRow* row = store->GetRow(ev, inOid);
00594     if ( row )
00595       hasRow = morkBool_kTrue;
00596       
00597     outErr = ev->AsErr();
00598   }
00599   if ( outHasRow )
00600     *outHasRow = hasRow;
00601   return outErr;
00602 }
00603   
00604 /*virtual*/ mdb_err
00605 orkinStore::GetRow( // access one row with specific oid
00606   nsIMdbEnv* mev, // context
00607   const mdbOid* inOid,  // hypothetical row oid
00608   nsIMdbRow** acqRow) // acquire specific row (or null)
00609 {
00610   mdb_err outErr = 0;
00611   nsIMdbRow* outRow = 0;
00612   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00613   if ( ev )
00614   {
00615     morkStore* store = (morkStore*) mHandle_Object;
00616     morkRow* row = store->GetRow(ev, inOid);
00617     if ( row && ev->Good() )
00618       outRow = row->AcquireRowHandle(ev, store);
00619       
00620     outErr = ev->AsErr();
00621   }
00622   if ( acqRow )
00623     *acqRow = outRow;
00624   return outErr;
00625 }
00626 
00627 /*virtual*/ mdb_err
00628 orkinStore::GetRowRefCount( // get number of tables that contain a row 
00629   nsIMdbEnv* mev, // context
00630   const mdbOid* inOid,  // hypothetical row oid
00631   mdb_count* outRefCount) // number of tables containing inRowKey 
00632 {
00633   mdb_err outErr = 0;
00634   mdb_count count = 0;
00635   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00636   if ( ev )
00637   {
00638     morkStore* store = (morkStore*) mHandle_Object;
00639     morkRow* row = store->GetRow(ev, inOid);
00640     if ( row && ev->Good() )
00641       count = row->mRow_GcUses;
00642       
00643     outErr = ev->AsErr();
00644   }
00645   if ( outRefCount )
00646     *outRefCount = count;
00647   return outErr;
00648 }
00649 
00650 /*virtual*/ mdb_err
00651 orkinStore::FindRow(nsIMdbEnv* mev, // search for row with matching cell
00652     mdb_scope inRowScope,   // row scope for row ids
00653     mdb_column inColumn,   // the column to search (and maintain an index)
00654     const mdbYarn* inTargetCellValue, // cell value for which to search
00655     mdbOid* outRowOid, // out row oid on match (or {0,-1} for no match)
00656     nsIMdbRow** acqRow) // acquire matching row (or nil for no match)
00657   // FindRow() searches for one row that has a cell in column inColumn with
00658   // a contained value with the same form (i.e. charset) and is byte-wise
00659   // identical to the blob described by yarn inTargetCellValue.  Both content
00660   // and form of the yarn must be an exact match to find a matching row.
00661   //
00662   // (In other words, both a yarn's blob bytes and form are significant.  The
00663   // form is not expected to vary in columns used for identity anyway.  This
00664   // is intended to make the cost of FindRow() cheaper for MDB implementors,
00665   // since any cell value atomization performed internally must necessarily
00666   // make yarn form significant in order to avoid data loss in atomization.)
00667   //
00668   // FindRow() can lazily create an index on attribute inColumn for all rows
00669   // with that attribute in row space scope inRowScope, so that subsequent
00670   // calls to FindRow() will perform faster.  Such an index might or might
00671   // not be persistent (but this seems desirable if it is cheap to do so).
00672   // Note that lazy index creation in readonly DBs is not very feasible.
00673   //
00674   // This FindRow() interface assumes that attribute inColumn is effectively
00675   // an alternative means of unique identification for a row in a rowspace,
00676   // so correct behavior is only guaranteed when no duplicates for this col
00677   // appear in the given set of rows.  (If more than one row has the same cell
00678   // value in this column, no more than one will be found; and cutting one of
00679   // two duplicate rows can cause the index to assume no other such row lives
00680   // in the row space, so future calls return nil for negative search results
00681   // even though some duplicate row might still live within the rowspace.)
00682   //
00683   // In other words, the FindRow() implementation is allowed to assume simple
00684   // hash tables mapping unqiue column keys to associated row values will be
00685   // sufficient, where any duplication is not recorded because only one copy
00686   // of a given key need be remembered.  Implementors are not required to sort
00687   // all rows by the specified column.
00688 {
00689   mdb_err outErr = 0;
00690   nsIMdbRow* outRow = 0;
00691   mdbOid rowOid;
00692   rowOid.mOid_Scope = 0;
00693   rowOid.mOid_Id = (mdb_id) -1;
00694   
00695   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00696   if ( ev )
00697   {
00698     morkStore* store = (morkStore*) mHandle_Object;
00699     morkRow* row = store->FindRow(ev, inRowScope, inColumn, inTargetCellValue);
00700     if ( row && ev->Good() )
00701     {
00702       outRow = row->AcquireRowHandle(ev, store);
00703       if ( outRow )
00704         rowOid = row->mRow_Oid;
00705     }
00706     outErr = ev->AsErr();
00707   }
00708   if ( acqRow )
00709     *acqRow = outRow;
00710     
00711   return outErr;
00712 }
00713 
00714 // } ----- end row methods -----
00715 
00716 // { ----- begin table methods -----  
00717 /*virtual*/ mdb_err
00718 orkinStore::HasTable( // supports a table with the specified oid?
00719   nsIMdbEnv* mev, // context
00720   const mdbOid* inOid,  // hypothetical table oid
00721   mdb_bool* outHasTable) // whether GetTable() might succeed
00722 {
00723   mdb_err outErr = 0;
00724   mork_bool hasTable = morkBool_kFalse;
00725   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00726   if ( ev )
00727   {
00728     morkTable* table = ((morkStore*) mHandle_Object)->GetTable(ev, inOid);
00729     if ( table )
00730       hasTable = morkBool_kTrue;
00731     
00732     outErr = ev->AsErr();
00733   }
00734   if ( outHasTable )
00735     *outHasTable = hasTable;
00736   return outErr;
00737 }
00738   
00739 /*virtual*/ mdb_err
00740 orkinStore::GetTable( // access one table with specific oid
00741   nsIMdbEnv* mev, // context
00742   const mdbOid* inOid,  // hypothetical table oid
00743   nsIMdbTable** acqTable) // acquire specific table (or null)
00744 {
00745   mdb_err outErr = 0;
00746   nsIMdbTable* outTable = 0;
00747   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00748   if ( ev )
00749   {
00750     morkTable* table =
00751       ((morkStore*) mHandle_Object)->GetTable(ev, inOid);
00752     if ( table && ev->Good() )
00753       outTable = table->AcquireTableHandle(ev);
00754     outErr = ev->AsErr();
00755   }
00756   if ( acqTable )
00757     *acqTable = outTable;
00758   return outErr;
00759 }
00760 
00761 /*virtual*/ mdb_err
00762 orkinStore::HasTableKind( // supports a table of the specified type?
00763   nsIMdbEnv* mev, // context
00764   mdb_scope inRowScope, // rid scope for row ids
00765   mdb_kind inTableKind, // the type of table to access
00766   mdb_count* outTableCount, // current number of such tables
00767   mdb_bool* outSupportsTable) // whether GetTableKind() might succeed
00768 {
00769   mdb_err outErr = 0;
00770   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00771   if ( ev )
00772   {
00773     *outSupportsTable =
00774       ((morkStore*) mHandle_Object)->HasTableKind(ev, inRowScope,
00775         inTableKind, outTableCount);
00776     outErr = ev->AsErr();
00777   }
00778   return outErr;
00779 }
00780       
00781 /*virtual*/ mdb_err
00782 orkinStore::GetTableKind( // access one (random) table of specific type
00783   nsIMdbEnv* mev, // context
00784   mdb_scope inRowScope,      // row scope for row ids
00785   mdb_kind inTableKind,      // the type of table to access
00786   mdb_count* outTableCount, // current number of such tables
00787   mdb_bool* outMustBeUnique, // whether port can hold only one of these
00788   nsIMdbTable** acqTable)      // acquire scoped collection of rows
00789 {
00790   mdb_err outErr = 0;
00791   nsIMdbTable* outTable = 0;
00792   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00793   if ( ev )
00794   {
00795     morkTable* table =
00796       ((morkStore*) mHandle_Object)->GetTableKind(ev, inRowScope,
00797         inTableKind, outTableCount, outMustBeUnique);
00798     if ( table && ev->Good() )
00799       outTable = table->AcquireTableHandle(ev);
00800     outErr = ev->AsErr();
00801   }
00802   if ( acqTable )
00803     *acqTable = outTable;
00804   return outErr;
00805 }
00806   
00807 /*virtual*/ mdb_err
00808 orkinStore::GetPortTableCursor( // get cursor for all tables of specific type
00809   nsIMdbEnv* mev, // context
00810   mdb_scope inRowScope, // row scope for row ids
00811   mdb_kind inTableKind, // the type of table to access
00812   nsIMdbPortTableCursor** acqCursor) // all such tables in the port
00813 {
00814   mdb_err outErr = 0;
00815   nsIMdbPortTableCursor* outCursor = 0;
00816   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00817   if ( ev )
00818   {
00819     morkPortTableCursor* cursor =
00820       ((morkStore*) mHandle_Object)->GetPortTableCursor(ev, inRowScope,
00821         inTableKind);
00822     if ( cursor && ev->Good() )
00823       outCursor = cursor->AcquirePortTableCursorHandle(ev);
00824 
00825     outErr = ev->AsErr();
00826   }
00827   if ( acqCursor )
00828     *acqCursor = outCursor;
00829   return outErr;
00830 }
00831 // } ----- end table methods -----
00832 
00833 // { ----- begin commit methods -----
00834   
00835 /*virtual*/ mdb_err
00836 orkinStore::ShouldCompress( // store wastes at least inPercentWaste?
00837   nsIMdbEnv* mev, // context
00838   mdb_percent inPercentWaste, // 0..100 percent file size waste threshold
00839   mdb_percent* outActualWaste, // 0..100 percent of file actually wasted
00840   mdb_bool* outShould) // true when about inPercentWaste% is wasted
00841 {
00842   mdb_percent actualWaste = 0;
00843   mdb_bool shouldCompress = morkBool_kFalse;
00844   mdb_err outErr = 0;
00845   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00846   if ( ev )
00847   {
00848     actualWaste = ((morkStore*) mHandle_Object)->PercentOfStoreWasted(ev);
00849     if ( inPercentWaste > 100 )
00850       inPercentWaste = 100;
00851     shouldCompress = ( actualWaste >= inPercentWaste );
00852     outErr = ev->AsErr();
00853   }
00854   if ( outActualWaste )
00855     *outActualWaste = actualWaste;
00856   if ( outShould )
00857     *outShould = shouldCompress;
00858   return outErr;
00859 }
00860 
00861 
00862 // } ===== end nsIMdbPort methods =====
00863 
00864 // { ===== begin nsIMdbStore methods =====
00865 
00866 // { ----- begin table methods -----
00867 /*virtual*/ mdb_err
00868 orkinStore::NewTable( // make one new table of specific type
00869   nsIMdbEnv* mev, // context
00870   mdb_scope inRowScope,    // row scope for row ids
00871   mdb_kind inTableKind,    // the type of table to access
00872   mdb_bool inMustBeUnique, // whether store can hold only one of these
00873   const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying 
00874   nsIMdbTable** acqTable)     // acquire scoped collection of rows
00875 {
00876   mdb_err outErr = 0;
00877   nsIMdbTable* outTable = 0;
00878   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00879   if ( ev )
00880   {
00881     morkTable* table =
00882       ((morkStore*) mHandle_Object)->NewTable(ev, inRowScope,
00883         inTableKind, inMustBeUnique, inOptionalMetaRowOid);
00884     if ( table && ev->Good() )
00885       outTable = table->AcquireTableHandle(ev);
00886     outErr = ev->AsErr();
00887   }
00888   if ( acqTable )
00889     *acqTable = outTable;
00890   return outErr;
00891 }
00892 
00893 /*virtual*/ mdb_err
00894 orkinStore::NewTableWithOid( // make one new table of specific type
00895   nsIMdbEnv* mev, // context
00896   const mdbOid* inOid,   // caller assigned oid
00897   mdb_kind inTableKind,    // the type of table to access
00898   mdb_bool inMustBeUnique, // whether store can hold only one of these
00899   const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying 
00900   nsIMdbTable** acqTable)     // acquire scoped collection of rows
00901 {
00902   mdb_err outErr = 0;
00903   nsIMdbTable* outTable = 0;
00904   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00905   if ( ev )
00906   {
00907     morkTable* table = ((morkStore*) mHandle_Object)->OidToTable(ev, inOid,
00908       inOptionalMetaRowOid);
00909     if ( table && ev->Good() )
00910     {
00911       table->mTable_Kind = inTableKind;
00912       if ( inMustBeUnique )
00913         table->SetTableUnique();
00914       outTable = table->AcquireTableHandle(ev);
00915     }
00916     outErr = ev->AsErr();
00917   }
00918   if ( acqTable )
00919     *acqTable = outTable;
00920   return outErr;
00921 }
00922 // } ----- end table methods -----
00923 
00924 // { ----- begin row scope methods -----
00925 /*virtual*/ mdb_err
00926 orkinStore::RowScopeHasAssignedIds(nsIMdbEnv* mev,
00927   mdb_scope inRowScope,   // row scope for row ids
00928   mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
00929   mdb_bool* outStoreAssigned) // nonzero if store db assigned specified
00930 {
00931   MORK_USED_1(inRowScope);
00932   mdb_bool storeAssigned = morkBool_kFalse;
00933   mdb_bool callerAssigned = morkBool_kFalse;
00934   mdb_err outErr = 0;
00935   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00936   if ( ev )
00937   {
00938     ev->StubMethodOnlyError();
00939     outErr = ev->AsErr();
00940   }
00941   if ( outCallerAssigned )
00942     *outCallerAssigned = callerAssigned;
00943   if ( outStoreAssigned )
00944     *outStoreAssigned = storeAssigned;
00945   return outErr;
00946 }
00947 
00948 /*virtual*/ mdb_err
00949 orkinStore::SetCallerAssignedIds(nsIMdbEnv* mev,
00950   mdb_scope inRowScope,   // row scope for row ids
00951   mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
00952   mdb_bool* outStoreAssigned) // nonzero if store db assigned specified
00953 {
00954   MORK_USED_1(inRowScope);
00955   mdb_bool storeAssigned = morkBool_kFalse;
00956   mdb_bool callerAssigned = morkBool_kFalse;
00957   mdb_err outErr = 0;
00958   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00959   if ( ev )
00960   {
00961     ev->StubMethodOnlyError();
00962     outErr = ev->AsErr();
00963   }
00964   if ( outCallerAssigned )
00965     *outCallerAssigned = callerAssigned;
00966   if ( outStoreAssigned )
00967     *outStoreAssigned = storeAssigned;
00968   return outErr;
00969 }
00970 
00971 /*virtual*/ mdb_err
00972 orkinStore::SetStoreAssignedIds(nsIMdbEnv* mev,
00973   mdb_scope inRowScope,   // row scope for row ids
00974   mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
00975   mdb_bool* outStoreAssigned) // nonzero if store db assigned specified
00976 {
00977   MORK_USED_1(inRowScope);
00978   mdb_err outErr = 0;
00979   mdb_bool storeAssigned = morkBool_kFalse;
00980   mdb_bool callerAssigned = morkBool_kFalse;
00981   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
00982   if ( ev )
00983   {
00984     ev->StubMethodOnlyError();
00985     outErr = ev->AsErr();
00986   }
00987   if ( outCallerAssigned )
00988     *outCallerAssigned = callerAssigned;
00989   if ( outStoreAssigned )
00990     *outStoreAssigned = storeAssigned;
00991   return outErr;
00992 }
00993 // } ----- end row scope methods -----
00994 
00995 // { ----- begin row methods -----
00996 /*virtual*/ mdb_err
00997 orkinStore::NewRowWithOid(nsIMdbEnv* mev, // new row w/ caller assigned oid
00998   const mdbOid* inOid,   // caller assigned oid
00999   nsIMdbRow** acqRow) // create new row
01000 {
01001   mdb_err outErr = 0;
01002   nsIMdbRow* outRow = 0;
01003   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01004   if ( ev )
01005   {
01006     morkStore* store = (morkStore*) mHandle_Object;
01007     morkRow* row = store->NewRowWithOid(ev, inOid);
01008     if ( row && ev->Good() )
01009       outRow = row->AcquireRowHandle(ev, store);
01010       
01011     outErr = ev->AsErr();
01012   }
01013   if ( acqRow )
01014     *acqRow = outRow;
01015   return outErr;
01016 }
01017 
01018 /*virtual*/ mdb_err
01019 orkinStore::NewRow(nsIMdbEnv* mev, // new row with db assigned oid
01020   mdb_scope inRowScope,   // row scope for row ids
01021   nsIMdbRow** acqRow) // create new row
01022 // Note this row must be added to some table or cell child before the
01023 // store is closed in order to make this row persist across sesssions.
01024 {
01025   mdb_err outErr = 0;
01026   nsIMdbRow* outRow = 0;
01027   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01028   if ( ev )
01029   {
01030     morkStore* store = (morkStore*) mHandle_Object;
01031     morkRow* row = store->NewRow(ev, inRowScope);
01032     if ( row && ev->Good() )
01033       outRow = row->AcquireRowHandle(ev, store);
01034       
01035     outErr = ev->AsErr();
01036   }
01037   if ( acqRow )
01038     *acqRow = outRow;
01039   return outErr;
01040 }
01041 // } ----- end row methods -----
01042 
01043 // { ----- begin inport/export methods -----
01044 /*virtual*/ mdb_err
01045 orkinStore::ImportContent( // import content from port
01046   nsIMdbEnv* mev, // context
01047   mdb_scope inRowScope, // scope for rows (or zero for all?)
01048   nsIMdbPort* ioPort, // the port with content to add to store
01049   nsIMdbThumb** acqThumb) // acquire thumb for incremental import
01050 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
01051 // then the import will be finished.
01052 {
01053   MORK_USED_2(inRowScope,ioPort);
01054   nsIMdbThumb* outThumb = 0;
01055   mdb_err outErr = 0;
01056   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01057   if ( ev )
01058   {
01059     ev->StubMethodOnlyError();
01060     outErr = ev->AsErr();
01061   }
01062   if ( acqThumb )
01063     *acqThumb = outThumb;
01064   return outErr;
01065 }
01066 
01067 /*virtual*/ mdb_err
01068 orkinStore::ImportFile( // import content from port
01069   nsIMdbEnv* mev, // context
01070   nsIMdbFile* ioFile, // the file with content to add to store
01071   nsIMdbThumb** acqThumb) // acquire thumb for incremental import
01072 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
01073 // then the import will be finished.
01074 {
01075   nsIMdbThumb* outThumb = 0;
01076   mdb_err outErr = 0;
01077   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01078   if ( ev )
01079   {
01080     if ( ioFile && acqThumb )
01081     {
01082       ev->StubMethodOnlyError();
01083     }
01084     else
01085       ev->NilPointerError();
01086     
01087     outErr = ev->AsErr();
01088   }
01089   if ( acqThumb )
01090     *acqThumb = outThumb;
01091   return outErr;
01092 }
01093 // } ----- end inport/export methods -----
01094 
01095 // { ----- begin hinting methods -----
01096 /*virtual*/ mdb_err
01097 orkinStore::ShareAtomColumnsHint( // advise re shared col content atomizing
01098   nsIMdbEnv* mev, // context
01099   mdb_scope inScopeHint, // zero, or suggested shared namespace
01100   const mdbColumnSet* inColumnSet) // cols desired tokenized together
01101 {
01102   MORK_USED_2(inColumnSet,inScopeHint);
01103   mdb_err outErr = 0;
01104   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01105   if ( ev )
01106   {
01107     // ev->StubMethodOnlyError(); // okay to do nothing for a hint method
01108     outErr = ev->AsErr();
01109   }
01110   return outErr;
01111 }
01112 
01113 /*virtual*/ mdb_err
01114 orkinStore::AvoidAtomColumnsHint( // advise col w/ poor atomizing prospects
01115   nsIMdbEnv* mev, // context
01116   const mdbColumnSet* inColumnSet) // cols with poor atomizing prospects
01117 {
01118   MORK_USED_1(inColumnSet);
01119   mdb_err outErr = 0;
01120   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01121   if ( ev )
01122   {
01123     // ev->StubMethodOnlyError(); // okay to do nothing for a hint method
01124     outErr = ev->AsErr();
01125   }
01126   return outErr;
01127 }
01128 // } ----- end hinting methods -----
01129 
01130 // { ----- begin commit methods -----
01131 /*virtual*/ mdb_err
01132 orkinStore::SmallCommit( // save minor changes if convenient and uncostly
01133   nsIMdbEnv* mev) // context
01134 {
01135   mdb_err outErr = 0;
01136   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01137   if ( ev )
01138   {
01139     // ev->StubMethodOnlyError(); // it's okay to do nothing for small commit
01140     outErr = ev->AsErr();
01141   }
01142   return outErr;
01143 }
01144 
01145 /*virtual*/ mdb_err
01146 orkinStore::LargeCommit( // save important changes if at all possible
01147   nsIMdbEnv* mev, // context
01148   nsIMdbThumb** acqThumb) // acquire thumb for incremental commit
01149 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
01150 // then the commit will be finished.  Note the store is effectively write
01151 // locked until commit is finished or canceled through the thumb instance.
01152 // Until the commit is done, the store will report it has readonly status.
01153 {
01154   mdb_err outErr = 0;
01155   nsIMdbThumb* outThumb = 0;
01156   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01157   if ( ev )
01158   {
01159     morkStore* store = (morkStore*) mHandle_Object;
01160     nsIMdbHeap* heap = store->mPort_Heap;
01161     
01162     morkThumb* thumb = 0;
01163     // morkFile* file = store->mStore_File;
01164     if ( store->DoPreferLargeOverCompressCommit(ev) )
01165     {
01166       thumb = morkThumb::Make_LargeCommit(ev, heap, store);
01167     }
01168     else
01169     {
01170       mork_bool doCollect = morkBool_kFalse;
01171       thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
01172     }
01173     
01174     if ( thumb )
01175     {
01176       outThumb = thumb;
01177       thumb->AddRef();
01178     }
01179       
01180     outErr = ev->AsErr();
01181   }
01182   if ( acqThumb )
01183     *acqThumb = outThumb;
01184   return outErr;
01185 }
01186 
01187 /*virtual*/ mdb_err
01188 orkinStore::SessionCommit( // save all changes if large commits delayed
01189   nsIMdbEnv* mev, // context
01190   nsIMdbThumb** acqThumb) // acquire thumb for incremental commit
01191 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
01192 // then the commit will be finished.  Note the store is effectively write
01193 // locked until commit is finished or canceled through the thumb instance.
01194 // Until the commit is done, the store will report it has readonly status.
01195 {
01196   mdb_err outErr = 0;
01197   nsIMdbThumb* outThumb = 0;
01198   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01199   if ( ev )
01200   {
01201     morkStore* store = (morkStore*) mHandle_Object;
01202     nsIMdbHeap* heap = store->mPort_Heap;
01203     
01204     morkThumb* thumb = 0;
01205     if ( store->DoPreferLargeOverCompressCommit(ev) )
01206     {
01207       thumb = morkThumb::Make_LargeCommit(ev, heap, store);
01208     }
01209     else
01210     {
01211       mork_bool doCollect = morkBool_kFalse;
01212       thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
01213     }
01214     
01215     if ( thumb )
01216     {
01217       outThumb = thumb;
01218       thumb->AddRef();
01219     }
01220     outErr = ev->AsErr();
01221   }
01222   if ( acqThumb )
01223     *acqThumb = outThumb;
01224   return outErr;
01225 }
01226 
01227 /*virtual*/ mdb_err
01228 orkinStore::CompressCommit( // commit and make db smaller if possible
01229   nsIMdbEnv* mev, // context
01230   nsIMdbThumb** acqThumb) // acquire thumb for incremental commit
01231 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
01232 // then the commit will be finished.  Note the store is effectively write
01233 // locked until commit is finished or canceled through the thumb instance.
01234 // Until the commit is done, the store will report it has readonly status.
01235 {
01236   mdb_err outErr = 0;
01237   nsIMdbThumb* outThumb = 0;
01238   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01239   if ( ev )
01240   {
01241     morkStore* store = (morkStore*) mHandle_Object;
01242     nsIMdbHeap* heap = store->mPort_Heap;
01243     mork_bool doCollect = morkBool_kFalse;
01244     morkThumb* thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
01245     if ( thumb )
01246     {
01247       outThumb = thumb;
01248       thumb->AddRef();
01249       store->mStore_CanWriteIncremental = morkBool_kTrue;
01250     }
01251       
01252     outErr = ev->AsErr();
01253   }
01254   if ( acqThumb )
01255     *acqThumb = outThumb;
01256   return outErr;
01257 }
01258 
01259 // } ----- end commit methods -----
01260 
01261 // } ===== end nsIMdbStore methods =====
01262 
01263 
01264 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789