Back to index

lightning-sunbird  0.9+nobinonly
morkStore.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 _MORKBLOB_
00051 #include "morkBlob.h"
00052 #endif
00053 
00054 #ifndef _MORKMAP_
00055 #include "morkMap.h"
00056 #endif
00057 
00058 #ifndef _MORKENV_
00059 #include "morkEnv.h"
00060 #endif
00061 
00062 #ifndef _MORKSTORE_
00063 #include "morkStore.h"
00064 #endif
00065 
00066 #ifndef _MORKFACTORY_
00067 #include "morkFactory.h"
00068 #endif
00069 
00070 #ifndef _MORKNODEMAP_
00071 #include "morkNodeMap.h"
00072 #endif
00073 
00074 #ifndef _MORKROW_
00075 #include "morkRow.h"
00076 #endif
00077 
00078 #ifndef _MORKTHUMB_
00079 #include "morkThumb.h"
00080 #endif
00081 // #ifndef _MORKFILE_
00082 // #include "morkFile.h"
00083 // #endif
00084 
00085 #ifndef _MORKBUILDER_
00086 #include "morkBuilder.h"
00087 #endif
00088 
00089 #ifndef _MORKATOMSPACE_
00090 #include "morkAtomSpace.h"
00091 #endif
00092 
00093 #ifndef _MORKSTREAM_
00094 #include "morkStream.h"
00095 #endif
00096 
00097 #ifndef _MORKATOMSPACE_
00098 #include "morkAtomSpace.h"
00099 #endif
00100 
00101 #ifndef _MORKROWSPACE_
00102 #include "morkRowSpace.h"
00103 #endif
00104 
00105 #ifndef _MORKPORTTABLECURSOR_
00106 #include "morkPortTableCursor.h"
00107 #endif
00108 
00109 #ifndef _MORKTABLE_
00110 #include "morkTable.h"
00111 #endif
00112 
00113 #ifndef _MORKROWMAP_
00114 #include "morkRowMap.h"
00115 #endif
00116 
00117 #ifndef _MORKPARSER_
00118 #include "morkParser.h"
00119 #endif
00120 
00121 #include "nsCOMPtr.h"
00122 
00123 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00124 
00125 // ````` ````` ````` ````` ````` 
00126 // { ===== begin morkNode interface =====
00127 
00128 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00129 
00130 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00131 
00132 // ````` ````` ````` ````` ````` 
00133 // { ===== begin morkNode interface =====
00134 
00135 /*public virtual*/ void
00136 morkStore::CloseMorkNode(morkEnv* ev) // ClosePort() only if open
00137 {
00138   if ( this->IsOpenNode() )
00139   {
00140     this->MarkClosing();
00141     this->CloseStore(ev);
00142     this->MarkShut();
00143   }
00144 }
00145 
00146 /*public non-poly*/ void
00147 morkStore::ClosePort(morkEnv* ev) // called by CloseMorkNode();
00148 {
00149   if ( this )
00150   {
00151     if ( this->IsNode() )
00152     {
00153       morkFactory::SlotWeakFactory((morkFactory*) 0, ev, &mPort_Factory);
00154       nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mPort_Heap);
00155       this->CloseObject(ev);
00156       this->MarkShut();
00157     }
00158     else
00159       this->NonNodeError(ev);
00160   }
00161   else
00162     ev->NilPointerError();
00163 }
00164 
00165 /*public virtual*/
00166 morkStore::~morkStore() // assert CloseStore() executed earlier
00167 {
00168   MOZ_COUNT_DTOR(morkStore);
00169   if (IsOpenNode())
00170     CloseMorkNode(mMorkEnv);
00171   MORK_ASSERT(this->IsShutNode());
00172   MORK_ASSERT(mStore_File==0);
00173   MORK_ASSERT(mStore_InStream==0);
00174   MORK_ASSERT(mStore_OutStream==0);
00175   MORK_ASSERT(mStore_Builder==0);
00176   MORK_ASSERT(mStore_OidAtomSpace==0);
00177   MORK_ASSERT(mStore_GroundAtomSpace==0);
00178   MORK_ASSERT(mStore_GroundColumnSpace==0);
00179   MORK_ASSERT(mStore_RowSpaces.IsShutNode());
00180   MORK_ASSERT(mStore_AtomSpaces.IsShutNode());
00181   MORK_ASSERT(mStore_Pool.IsShutNode());
00182 }
00183 
00184 /*public non-poly*/
00185 morkStore::morkStore(morkEnv* ev, const morkUsage& inUsage,
00186      nsIMdbHeap* ioNodeHeap, // the heap (if any) for this node instance
00187      morkFactory* inFactory, // the factory for this
00188      nsIMdbHeap* ioPortHeap  // the heap to hold all content in the port
00189      )
00190 : morkObject(ev, inUsage, ioNodeHeap, morkColor_kNone, (morkHandle*) 0)
00191 , mPort_Env( ev )
00192 , mPort_Factory( 0 )
00193 , mPort_Heap( 0 )
00194 , mStore_OidAtomSpace( 0 )
00195 , mStore_GroundAtomSpace( 0 )
00196 , mStore_GroundColumnSpace( 0 )
00197 
00198 , mStore_File( 0 )
00199 , mStore_InStream( 0 )
00200 , mStore_Builder( 0 )
00201 , mStore_OutStream( 0 )
00202 
00203 , mStore_RowSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
00204 , mStore_AtomSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
00205 , mStore_Zone(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
00206 , mStore_Pool(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
00207 
00208 , mStore_CommitGroupIdentity( 0 )
00209 
00210 , mStore_FirstCommitGroupPos( 0 )
00211 , mStore_SecondCommitGroupPos( 0 )
00212 
00213 // disable auto-assignment of atom IDs until someone knows it is okay:
00214 , mStore_CanAutoAssignAtomIdentity( morkBool_kFalse )
00215 , mStore_CanDirty( morkBool_kFalse ) // not until the store is open
00216 , mStore_CanWriteIncremental( morkBool_kTrue ) // always with few exceptions
00217 {
00218   MOZ_COUNT_CTOR(morkStore);
00219   if ( ev->Good() )
00220   {
00221     if ( inFactory && ioPortHeap )
00222     {
00223       morkFactory::SlotWeakFactory(inFactory, ev, &mPort_Factory);
00224       nsIMdbHeap_SlotStrongHeap(ioPortHeap, ev, &mPort_Heap);
00225       if ( ev->Good() )
00226         mNode_Derived = morkDerived_kPort;
00227     }
00228     else
00229       ev->NilPointerError();
00230   }
00231   if ( ev->Good() )
00232   {
00233     mNode_Derived = morkDerived_kStore;
00234     
00235   }
00236 }
00237 
00238 NS_IMPL_ISUPPORTS_INHERITED1(morkStore, morkObject, nsIMdbStore)
00239 
00240 /*public non-poly*/ void
00241 morkStore::CloseStore(morkEnv* ev) // called by CloseMorkNode();
00242 {
00243   if ( this )
00244   {
00245     if ( this->IsNode() )
00246     {
00247 
00248       nsIMdbFile* file = mStore_File;
00249       file->AddRef();
00250 
00251       morkFactory::SlotWeakFactory((morkFactory*) 0, ev, &mPort_Factory);
00252       nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mPort_Heap);
00253       morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev,
00254         &mStore_OidAtomSpace);
00255       morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev,
00256         &mStore_GroundAtomSpace);
00257       morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev,
00258         &mStore_GroundColumnSpace);
00259       mStore_RowSpaces.CloseMorkNode(ev);
00260       mStore_AtomSpaces.CloseMorkNode(ev);
00261       morkBuilder::SlotStrongBuilder((morkBuilder*) 0, ev, &mStore_Builder);
00262       
00263       nsIMdbFile_SlotStrongFile((nsIMdbFile*) 0, ev,
00264         &mStore_File);
00265       
00266       file->Release();
00267 
00268       morkStream::SlotStrongStream((morkStream*) 0, ev, &mStore_InStream);
00269       morkStream::SlotStrongStream((morkStream*) 0, ev, &mStore_OutStream);
00270 
00271       mStore_Pool.CloseMorkNode(ev);
00272       mStore_Zone.CloseMorkNode(ev);
00273       this->ClosePort(ev);
00274       this->MarkShut();
00275     }
00276     else
00277       this->NonNodeError(ev);
00278   }
00279   else
00280     ev->NilPointerError();
00281 }
00282 
00283 // } ===== end morkNode methods =====
00284 // ````` ````` ````` ````` ````` 
00285 
00286 
00287 mork_bool morkStore::DoPreferLargeOverCompressCommit(morkEnv* ev)
00288   // true when mStore_CanWriteIncremental && store has file large enough 
00289 {
00290   nsIMdbFile* file = mStore_File;
00291   if ( file && mStore_CanWriteIncremental )
00292   {
00293     mdb_pos fileEof = 0;
00294     file->Eof(ev->AsMdbEnv(), &fileEof);
00295     if ( ev->Good() && fileEof > 128 )
00296       return morkBool_kTrue;
00297   }
00298   return morkBool_kFalse;
00299 }
00300 
00301 mork_percent morkStore::PercentOfStoreWasted(morkEnv* ev)
00302 {
00303   mork_percent outPercent = 0;
00304   nsIMdbFile* file = mStore_File;
00305   
00306   if ( file )
00307   {
00308     mork_pos firstPos = mStore_FirstCommitGroupPos;
00309     mork_pos secondPos = mStore_SecondCommitGroupPos;
00310     if ( firstPos || secondPos )
00311     {
00312       if ( firstPos < 512 && secondPos > firstPos )
00313         firstPos = secondPos; // better approximation of first commit
00314         
00315       mork_pos fileLength = 0;
00316       file->Eof(ev->AsMdbEnv(), &fileLength); // end of file
00317       if ( ev->Good() && fileLength > firstPos )
00318       {
00319         mork_size groupContent = fileLength - firstPos;
00320         outPercent = ( groupContent * 100 ) / fileLength;
00321       }
00322     }
00323   }
00324   else
00325     this->NilStoreFileError(ev);
00326     
00327   return outPercent;
00328 }
00329 
00330 void
00331 morkStore::SetStoreAndAllSpacesCanDirty(morkEnv* ev, mork_bool inCanDirty)
00332 {
00333   mStore_CanDirty = inCanDirty;
00334   
00335   mork_change* c = 0;
00336   mork_scope* key = 0; // ignore keys in maps
00337 
00338   if ( ev->Good() )
00339   {
00340     morkAtomSpaceMapIter asi(ev, &mStore_AtomSpaces);
00341 
00342     morkAtomSpace* atomSpace = 0; // old val node in the map
00343     
00344     for ( c = asi.FirstAtomSpace(ev, key, &atomSpace); c && ev->Good();
00345           c = asi.NextAtomSpace(ev, key, &atomSpace) )
00346     {
00347       if ( atomSpace )
00348       {
00349         if ( atomSpace->IsAtomSpace() )
00350           atomSpace->mSpace_CanDirty = inCanDirty;
00351         else
00352           atomSpace->NonAtomSpaceTypeError(ev);
00353       }
00354       else
00355         ev->NilPointerError();
00356     }
00357   }
00358 
00359   if ( ev->Good() )
00360   {
00361     morkRowSpaceMapIter rsi(ev, &mStore_RowSpaces);
00362     morkRowSpace* rowSpace = 0; // old val node in the map
00363     
00364     for ( c = rsi.FirstRowSpace(ev, key, &rowSpace); c && ev->Good();
00365           c = rsi.NextRowSpace(ev, key, &rowSpace) )
00366     {
00367       if ( rowSpace )
00368       {
00369         if ( rowSpace->IsRowSpace() )
00370           rowSpace->mSpace_CanDirty = inCanDirty;
00371         else
00372           rowSpace->NonRowSpaceTypeError(ev);
00373       }
00374     }
00375   }
00376 }
00377 
00378 void
00379 morkStore::RenumberAllCollectableContent(morkEnv* ev)
00380 {
00381   MORK_USED_1(ev);
00382   // do nothing currently
00383 }
00384 
00385 nsIMdbStore*
00386 morkStore::AcquireStoreHandle(morkEnv* ev)
00387 {
00388   return this;
00389 }
00390 
00391 
00392 morkFarBookAtom*
00393 morkStore::StageAliasAsFarBookAtom(morkEnv* ev, const morkMid* inMid,
00394    morkAtomSpace* ioSpace, mork_cscode inForm)
00395 {
00396   if ( inMid && inMid->mMid_Buf )
00397   {
00398     const morkBuf* buf = inMid->mMid_Buf;
00399     mork_size length = buf->mBuf_Fill;
00400     if ( length <= morkBookAtom_kMaxBodySize )
00401     {
00402       mork_aid dummyAid = 1;
00403       //mStore_BookAtom.InitMaxBookAtom(ev, *buf, 
00404       //  inForm, ioSpace, dummyAid);
00405        
00406       mStore_FarBookAtom.InitFarBookAtom(ev, *buf, 
00407         inForm, ioSpace, dummyAid);
00408       return &mStore_FarBookAtom;
00409     }
00410   }
00411   else
00412     ev->NilPointerError();
00413     
00414   return (morkFarBookAtom*) 0;
00415 }
00416 
00417 morkFarBookAtom*
00418 morkStore::StageYarnAsFarBookAtom(morkEnv* ev, const mdbYarn* inYarn,
00419    morkAtomSpace* ioSpace)
00420 {
00421   if ( inYarn && inYarn->mYarn_Buf )
00422   {
00423     mork_size length = inYarn->mYarn_Fill;
00424     if ( length <= morkBookAtom_kMaxBodySize )
00425     {
00426       morkBuf buf(inYarn->mYarn_Buf, length);
00427       mork_aid dummyAid = 1;
00428       //mStore_BookAtom.InitMaxBookAtom(ev, buf, 
00429       //  inYarn->mYarn_Form, ioSpace, dummyAid);
00430       mStore_FarBookAtom.InitFarBookAtom(ev, buf, 
00431         inYarn->mYarn_Form, ioSpace, dummyAid);
00432       return &mStore_FarBookAtom;
00433     }
00434   }
00435   else
00436     ev->NilPointerError();
00437     
00438   return (morkFarBookAtom*) 0;
00439 }
00440 
00441 morkFarBookAtom*
00442 morkStore::StageStringAsFarBookAtom(morkEnv* ev, const char* inString,
00443    mork_cscode inForm, morkAtomSpace* ioSpace)
00444 {
00445   if ( inString )
00446   {
00447     mork_size length = MORK_STRLEN(inString);
00448     if ( length <= morkBookAtom_kMaxBodySize )
00449     {
00450       morkBuf buf(inString, length);
00451       mork_aid dummyAid = 1;
00452       //mStore_BookAtom.InitMaxBookAtom(ev, buf, inForm, ioSpace, dummyAid);
00453       mStore_FarBookAtom.InitFarBookAtom(ev, buf, inForm, ioSpace, dummyAid);
00454       return &mStore_FarBookAtom;
00455     }
00456   }
00457   else
00458     ev->NilPointerError();
00459     
00460   return (morkFarBookAtom*) 0;
00461 }
00462 
00463 morkAtomSpace* morkStore::LazyGetOidAtomSpace(morkEnv* ev)
00464 {
00465   MORK_USED_1(ev);
00466   if ( !mStore_OidAtomSpace )
00467   {
00468   }
00469   return mStore_OidAtomSpace;
00470 }
00471 
00472 morkAtomSpace* morkStore::LazyGetGroundAtomSpace(morkEnv* ev)
00473 {
00474   if ( !mStore_GroundAtomSpace )
00475   {
00476     mork_scope atomScope = morkStore_kValueSpaceScope;
00477     nsIMdbHeap* heap = mPort_Heap;
00478     morkAtomSpace* space = new(*heap, ev) 
00479       morkAtomSpace(ev, morkUsage::kHeap, atomScope, this, heap, heap);
00480       
00481     if ( space ) // successful space creation?
00482     {
00483       this->MaybeDirtyStore();
00484     
00485       mStore_GroundAtomSpace = space; // transfer strong ref to this slot
00486       mStore_AtomSpaces.AddAtomSpace(ev, space);
00487     }
00488   }
00489   return mStore_GroundAtomSpace;
00490 }
00491 
00492 morkAtomSpace* morkStore::LazyGetGroundColumnSpace(morkEnv* ev)
00493 {
00494   if ( !mStore_GroundColumnSpace )
00495   {
00496     mork_scope atomScope = morkStore_kGroundColumnSpace;
00497     nsIMdbHeap* heap = mPort_Heap;
00498     morkAtomSpace* space = new(*heap, ev) 
00499       morkAtomSpace(ev, morkUsage::kHeap, atomScope, this, heap, heap);
00500       
00501     if ( space ) // successful space creation?
00502     {
00503       this->MaybeDirtyStore();
00504     
00505       mStore_GroundColumnSpace = space; // transfer strong ref to this slot
00506       mStore_AtomSpaces.AddAtomSpace(ev, space);
00507     }
00508   }
00509   return mStore_GroundColumnSpace;
00510 }
00511 
00512 morkStream* morkStore::LazyGetInStream(morkEnv* ev)
00513 {
00514   if ( !mStore_InStream )
00515   {
00516     nsIMdbFile* file = mStore_File;
00517     if ( file )
00518     {
00519       morkStream* stream = new(*mPort_Heap, ev) 
00520         morkStream(ev, morkUsage::kHeap, mPort_Heap, file,
00521           morkStore_kStreamBufSize, /*frozen*/ morkBool_kTrue);
00522       if ( stream )
00523       {
00524         this->MaybeDirtyStore();
00525         mStore_InStream = stream; // transfer strong ref to this slot
00526       }
00527     }
00528     else
00529       this->NilStoreFileError(ev);
00530   }
00531   return mStore_InStream;
00532 }
00533 
00534 morkStream* morkStore::LazyGetOutStream(morkEnv* ev)
00535 {
00536   if ( !mStore_OutStream )
00537   {
00538     nsIMdbFile* file = mStore_File;
00539     if ( file )
00540     {
00541       morkStream* stream = new(*mPort_Heap, ev) 
00542         morkStream(ev, morkUsage::kHeap, mPort_Heap, file,
00543           morkStore_kStreamBufSize, /*frozen*/ morkBool_kFalse);
00544       if ( stream )
00545       {
00546         this->MaybeDirtyStore();
00547         mStore_InStream = stream; // transfer strong ref to this slot
00548       }
00549     }
00550     else
00551       this->NilStoreFileError(ev);
00552   }
00553   return mStore_OutStream;
00554 }
00555 
00556 void
00557 morkStore::ForgetBuilder(morkEnv* ev)
00558 {
00559   if ( mStore_Builder )
00560     morkBuilder::SlotStrongBuilder((morkBuilder*) 0, ev, &mStore_Builder);
00561   if ( mStore_InStream )
00562     morkStream::SlotStrongStream((morkStream*) 0, ev, &mStore_InStream);
00563 }
00564 
00565 morkBuilder* morkStore::LazyGetBuilder(morkEnv* ev)
00566 {
00567   if ( !mStore_Builder )
00568   {
00569     morkStream* stream = this->LazyGetInStream(ev);
00570     if ( stream )
00571     {
00572       nsIMdbHeap* heap = mPort_Heap;
00573       morkBuilder* builder = new(*heap, ev) 
00574         morkBuilder(ev, morkUsage::kHeap, heap, stream,
00575           morkBuilder_kDefaultBytesPerParseSegment, heap, this);
00576       if ( builder )
00577       {
00578         mStore_Builder = builder; // transfer strong ref to this slot
00579       }
00580     }
00581   }
00582   return mStore_Builder;
00583 }
00584 
00585 morkRowSpace*
00586 morkStore::LazyGetRowSpace(morkEnv* ev, mdb_scope inRowScope)
00587 {
00588   morkRowSpace* outSpace = mStore_RowSpaces.GetRowSpace(ev, inRowScope);
00589   if ( !outSpace && ev->Good() ) // try to make new space?
00590   {
00591     nsIMdbHeap* heap = mPort_Heap;
00592     outSpace = new(*heap, ev) 
00593       morkRowSpace(ev, morkUsage::kHeap, inRowScope, this, heap, heap);
00594       
00595     if ( outSpace ) // successful space creation?
00596     {
00597       this->MaybeDirtyStore();
00598     
00599       // note adding to node map creates it's own strong ref...
00600       if ( mStore_RowSpaces.AddRowSpace(ev, outSpace) )
00601         outSpace->CutStrongRef(ev); // ...so we can drop our strong ref
00602     }
00603   }
00604   return outSpace;
00605 }
00606 
00607 morkAtomSpace*
00608 morkStore::LazyGetAtomSpace(morkEnv* ev, mdb_scope inAtomScope)
00609 {
00610   morkAtomSpace* outSpace = mStore_AtomSpaces.GetAtomSpace(ev, inAtomScope);
00611   if ( !outSpace && ev->Good() ) // try to make new space?
00612   {
00613     if ( inAtomScope == morkStore_kValueSpaceScope )
00614       outSpace = this->LazyGetGroundAtomSpace(ev);
00615       
00616     else if ( inAtomScope == morkStore_kGroundColumnSpace )
00617       outSpace = this->LazyGetGroundColumnSpace(ev);
00618     else
00619     {
00620       nsIMdbHeap* heap = mPort_Heap;
00621       outSpace = new(*heap, ev) 
00622         morkAtomSpace(ev, morkUsage::kHeap, inAtomScope, this, heap, heap);
00623         
00624       if ( outSpace ) // successful space creation?
00625       {
00626         this->MaybeDirtyStore();
00627     
00628         // note adding to node map creates it's own strong ref...
00629         if ( mStore_AtomSpaces.AddAtomSpace(ev, outSpace) )
00630           outSpace->CutStrongRef(ev); // ...so we can drop our strong ref
00631       }
00632     }
00633   }
00634   return outSpace;
00635 }
00636 
00637 /*static*/ void
00638 morkStore::NonStoreTypeError(morkEnv* ev)
00639 {
00640   ev->NewError("non morkStore");
00641 }
00642 
00643 /*static*/ void
00644 morkStore::NilStoreFileError(morkEnv* ev)
00645 {
00646   ev->NewError("nil mStore_File");
00647 }
00648 
00649 /*static*/ void
00650 morkStore::CannotAutoAssignAtomIdentityError(morkEnv* ev)
00651 {
00652   ev->NewError("false mStore_CanAutoAssignAtomIdentity");
00653 }
00654 
00655 
00656 mork_bool
00657 morkStore::OpenStoreFile(morkEnv* ev, mork_bool inFrozen,
00658     // const char* inFilePath,
00659     nsIMdbFile* ioFile, // db abstract file interface
00660     const mdbOpenPolicy* inOpenPolicy)
00661 {
00662   MORK_USED_2(inOpenPolicy,inFrozen);
00663   nsIMdbFile_SlotStrongFile(ioFile, ev, &mStore_File);
00664   
00665   // if ( ev->Good() )
00666   // {
00667   //   morkFile* file = morkFile::OpenOldFile(ev, mPort_Heap,
00668   //     inFilePath, inFrozen);
00669   //   if ( ioFile )
00670   //   {
00671   //     if ( ev->Good() )
00672   //       morkFile::SlotStrongFile(file, ev, &mStore_File);
00673   //     else
00674   //       file->CutStrongRef(ev);
00675   //       
00676   //   }
00677   // }
00678   return ev->Good();
00679 }
00680 
00681 mork_bool
00682 morkStore::CreateStoreFile(morkEnv* ev,
00683     // const char* inFilePath,
00684     nsIMdbFile* ioFile, // db abstract file interface
00685     const mdbOpenPolicy* inOpenPolicy)
00686 {
00687   MORK_USED_1(inOpenPolicy);
00688   nsIMdbFile_SlotStrongFile(ioFile, ev, &mStore_File);
00689   
00690   return ev->Good();
00691 }
00692 
00693 morkAtom*
00694 morkStore::CopyAtom(morkEnv* ev, const morkAtom* inAtom)
00695 // copy inAtom (from some other store) over to this store
00696 {
00697   morkAtom* outAtom = 0;
00698   if ( inAtom )
00699   {
00700     mdbYarn yarn;
00701     if ( inAtom->AliasYarn(&yarn) )
00702       outAtom = this->YarnToAtom(ev, &yarn, PR_TRUE /* create */);
00703   }
00704   return outAtom;
00705 }
00706  
00707 morkAtom*
00708 morkStore::YarnToAtom(morkEnv* ev, const mdbYarn* inYarn, PRBool createIfMissing /* = PR_TRUE */)
00709 {
00710   morkAtom* outAtom = 0;
00711   if ( ev->Good() )
00712   {
00713     morkAtomSpace* groundSpace = this->LazyGetGroundAtomSpace(ev);
00714     if ( groundSpace )
00715     {
00716       morkFarBookAtom* keyAtom =
00717         this->StageYarnAsFarBookAtom(ev, inYarn, groundSpace);
00718         
00719       if ( keyAtom )
00720       {
00721         morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
00722         outAtom = map->GetAtom(ev, keyAtom);
00723         if ( !outAtom && createIfMissing)
00724         {
00725           this->MaybeDirtyStore();
00726           outAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
00727         }
00728       }
00729       else if ( ev->Good() )
00730       {
00731         morkBuf b(inYarn->mYarn_Buf, inYarn->mYarn_Fill);
00732         morkZone* z = &mStore_Zone;
00733         outAtom = mStore_Pool.NewAnonAtom(ev, b, inYarn->mYarn_Form, z);
00734       }
00735     }
00736   }
00737   return outAtom;
00738 }
00739 
00740 mork_bool
00741 morkStore::MidToOid(morkEnv* ev, const morkMid& inMid, mdbOid* outOid)
00742 {
00743   *outOid = inMid.mMid_Oid;
00744   const morkBuf* buf = inMid.mMid_Buf;
00745   if ( buf && !outOid->mOid_Scope )
00746   {
00747     if ( buf->mBuf_Fill <= morkBookAtom_kMaxBodySize )
00748     {
00749       if ( buf->mBuf_Fill == 1 )
00750       {
00751         mork_u1* name = (mork_u1*) buf->mBuf_Body;
00752         if ( name )
00753         {
00754           outOid->mOid_Scope = (mork_scope) *name;
00755           return ev->Good();
00756         }
00757       }
00758       morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev);
00759       if ( groundSpace )
00760       {
00761         mork_cscode form = 0; // default
00762         mork_aid aid = 1; // dummy
00763         mStore_FarBookAtom.InitFarBookAtom(ev, *buf, form, groundSpace, aid);
00764         morkFarBookAtom* keyAtom = &mStore_FarBookAtom;
00765         morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
00766         morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
00767         if ( bookAtom )
00768           outOid->mOid_Scope = bookAtom->mBookAtom_Id;
00769         else
00770         {
00771           this->MaybeDirtyStore();
00772           bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
00773           if ( bookAtom )
00774           {
00775             outOid->mOid_Scope = bookAtom->mBookAtom_Id;
00776             bookAtom->MakeCellUseForever(ev);
00777           }
00778         }
00779       }
00780     }
00781   }
00782   return ev->Good();
00783 }
00784 
00785 morkRow*
00786 morkStore::MidToRow(morkEnv* ev, const morkMid& inMid)
00787 {
00788   mdbOid tempOid;
00789   this->MidToOid(ev, inMid, &tempOid);
00790   return this->OidToRow(ev, &tempOid);
00791 }
00792 
00793 morkTable*
00794 morkStore::MidToTable(morkEnv* ev, const morkMid& inMid)
00795 {
00796   mdbOid tempOid;
00797   this->MidToOid(ev, inMid, &tempOid);
00798   return this->OidToTable(ev, &tempOid, /*metarow*/ (mdbOid*) 0);
00799 }
00800 
00801 mork_bool
00802 morkStore::MidToYarn(morkEnv* ev, const morkMid& inMid, mdbYarn* outYarn)
00803 {
00804   mdbOid tempOid;
00805   this->MidToOid(ev, inMid, &tempOid);
00806   return this->OidToYarn(ev, tempOid, outYarn);
00807 }
00808 
00809 mork_bool
00810 morkStore::OidToYarn(morkEnv* ev, const mdbOid& inOid, mdbYarn* outYarn)
00811 {
00812   morkBookAtom* atom = 0;
00813       
00814   morkAtomSpace* atomSpace = mStore_AtomSpaces.GetAtomSpace(ev, inOid.mOid_Scope);
00815   if ( atomSpace )
00816   {
00817     morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids;
00818     atom = map->GetAid(ev, (mork_aid) inOid.mOid_Id);
00819   }
00820   atom->GetYarn(outYarn); // note this is safe even when atom==nil
00821 
00822   return ev->Good();
00823 }
00824 
00825 morkBookAtom*
00826 morkStore::MidToAtom(morkEnv* ev, const morkMid& inMid)
00827 {
00828   morkBookAtom* outAtom = 0;
00829   mdbOid oid;
00830   if ( this->MidToOid(ev, inMid, &oid) )
00831   {
00832     morkAtomSpace* atomSpace = mStore_AtomSpaces.GetAtomSpace(ev, oid.mOid_Scope);
00833     if ( atomSpace )
00834     {
00835       morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids;
00836       outAtom = map->GetAid(ev, (mork_aid) oid.mOid_Id);
00837     }
00838   }
00839   return outAtom;
00840 }
00841 
00842 /*static*/ void
00843 morkStore::SmallTokenToOneByteYarn(morkEnv* ev, mdb_token inToken,
00844   mdbYarn* outYarn)
00845 {
00846   MORK_USED_1(ev);
00847   if ( outYarn->mYarn_Buf && outYarn->mYarn_Size ) // any space in yarn at all?
00848   {
00849     mork_u1* buf = (mork_u1*) outYarn->mYarn_Buf; // for byte arithmetic
00850     buf[ 0 ] = (mork_u1) inToken; // write the single byte
00851     outYarn->mYarn_Fill = 1;
00852     outYarn->mYarn_More = 0;
00853   }
00854   else // just record we could not write the single byte
00855   {
00856     outYarn->mYarn_More = 1;
00857     outYarn->mYarn_Fill = 0;
00858   }
00859 }
00860 
00861 void
00862 morkStore::TokenToString(morkEnv* ev, mdb_token inToken, mdbYarn* outTokenName)
00863 {
00864   if ( inToken > morkAtomSpace_kMaxSevenBitAid )
00865   {
00866     morkBookAtom* atom = 0;
00867     morkAtomSpace* space = mStore_GroundColumnSpace;
00868     if ( space )
00869       atom = space->mAtomSpace_AtomAids.GetAid(ev, (mork_aid) inToken);
00870       
00871     atom->GetYarn(outTokenName); // note this is safe even when atom==nil
00872   }
00873   else // token is an "immediate" single byte string representation?
00874     this->SmallTokenToOneByteYarn(ev, inToken, outTokenName);
00875 }
00876   
00877 // void
00878 // morkStore::SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom,
00879 //   const mdbOid* inOid)
00880 // {
00881 // mork_token   mStore_MorkNoneToken;    // token for "mork:none"   // fill=9
00882 // mork_column  mStore_CharsetToken;     // token for "charset"     // fill=7
00883 // mork_column  mStore_AtomScopeToken;   // token for "atomScope"   // fill=9
00884 // mork_column  mStore_RowScopeToken;    // token for "rowScope"    // fill=8
00885 // mork_column  mStore_TableScopeToken;  // token for "tableScope"  // fill=10
00886 // mork_column  mStore_ColumnScopeToken; // token for "columnScope" // fill=11
00887 // mork_kind    mStore_TableKindToken;   // token for "tableKind"   // fill=9
00888 // ---------------------ruler-for-token-length-above---123456789012
00889 // 
00890 //   if ( inOid->mOid_Scope == morkStore_kColumnSpaceScope && inAtom->IsWeeBook() )
00891 //   {
00892 //     const mork_u1* body = ((const morkWeeBookAtom*) inAtom)->mWeeBookAtom_Body;
00893 //     mork_size size = inAtom->mAtom_Size;
00894 // 
00895 //     if ( size >= 7 && size <= 11 )
00896 //     {
00897 //       if ( size == 9 )
00898 //       {
00899 //         if ( *body == 'm' )
00900 //         {
00901 //           if ( MORK_MEMCMP(body, "mork:none", 9) == 0 )
00902 //             mStore_MorkNoneToken = inAtom->mBookAtom_Id;
00903 //         }
00904 //         else if ( *body == 'a' )
00905 //         {
00906 //           if ( MORK_MEMCMP(body, "atomScope", 9) == 0 )
00907 //             mStore_AtomScopeToken = inAtom->mBookAtom_Id;
00908 //         }
00909 //         else if ( *body == 't' )
00910 //         {
00911 //           if ( MORK_MEMCMP(body, "tableKind", 9) == 0 )
00912 //             mStore_TableKindToken = inAtom->mBookAtom_Id;
00913 //         }
00914 //       }
00915 //       else if ( size == 7 && *body == 'c' )
00916 //       {
00917 //         if ( MORK_MEMCMP(body, "charset", 7) == 0 )
00918 //           mStore_CharsetToken = inAtom->mBookAtom_Id;
00919 //       }
00920 //       else if ( size == 8 && *body == 'r' )
00921 //       {
00922 //         if ( MORK_MEMCMP(body, "rowScope", 8) == 0 )
00923 //           mStore_RowScopeToken = inAtom->mBookAtom_Id;
00924 //       }
00925 //       else if ( size == 10 && *body == 't' )
00926 //       {
00927 //         if ( MORK_MEMCMP(body, "tableScope", 10) == 0 )
00928 //           mStore_TableScopeToken = inAtom->mBookAtom_Id;
00929 //       }
00930 //       else if ( size == 11 && *body == 'c' )
00931 //       {
00932 //         if ( MORK_MEMCMP(body, "columnScope", 11) == 0 )
00933 //           mStore_ColumnScopeToken = inAtom->mBookAtom_Id;
00934 //       }
00935 //     }
00936 //   }
00937 // }
00938 
00939 morkAtom*
00940 morkStore::AddAlias(morkEnv* ev, const morkMid& inMid, mork_cscode inForm)
00941 {
00942   morkBookAtom* outAtom = 0;
00943   if ( ev->Good() )
00944   {
00945     const mdbOid* oid = &inMid.mMid_Oid;
00946     morkAtomSpace* atomSpace = this->LazyGetAtomSpace(ev, oid->mOid_Scope);
00947     if ( atomSpace )
00948     {
00949       morkFarBookAtom* keyAtom =
00950         this->StageAliasAsFarBookAtom(ev, &inMid, atomSpace, inForm);
00951       if ( keyAtom )
00952       {
00953          morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids;
00954         outAtom = map->GetAid(ev, (mork_aid) oid->mOid_Id);
00955         if ( outAtom )
00956         {
00957           if ( !outAtom->EqualFormAndBody(ev, keyAtom) )
00958               ev->NewError("duplicate alias ID");
00959         }
00960         else
00961         {
00962           this->MaybeDirtyStore();
00963           keyAtom->mBookAtom_Id = oid->mOid_Id;
00964           outAtom = atomSpace->MakeBookAtomCopyWithAid(ev,
00965             *keyAtom, (mork_aid) oid->mOid_Id);
00966             
00967           // if ( outAtom && outAtom->IsWeeBook() )
00968           // {
00969           //   if ( oid->mOid_Scope == morkStore_kColumnSpaceScope )
00970           //   {
00971           //    mork_size size = outAtom->mAtom_Size;
00972           //     if ( size >= 7 && size <= 11 )
00973           //       this->SyncTokenIdChange(ev, outAtom, oid);
00974           //   }
00975           // }
00976         }
00977       }
00978     }
00979   }
00980   return outAtom;
00981 }
00982 
00983 #define morkStore_kMaxCopyTokenSize 512 /* if larger, cannot be copied */
00984   
00985 mork_token
00986 morkStore::CopyToken(morkEnv* ev, mdb_token inToken, morkStore* inStore)
00987 // copy inToken from inStore over to this store
00988 {
00989   mork_token outToken = 0;
00990   if ( inStore == this ) // same store?
00991     outToken = inToken; // just return token unchanged
00992   else
00993   {
00994     char yarnBuf[ morkStore_kMaxCopyTokenSize ];
00995     mdbYarn yarn;
00996     yarn.mYarn_Buf = yarnBuf;
00997     yarn.mYarn_Fill = 0;
00998     yarn.mYarn_Size = morkStore_kMaxCopyTokenSize;
00999     yarn.mYarn_More = 0;
01000     yarn.mYarn_Form = 0;
01001     yarn.mYarn_Grow = 0;
01002     
01003     inStore->TokenToString(ev, inToken, &yarn);
01004     if ( ev->Good() )
01005     {
01006       morkBuf buf(yarn.mYarn_Buf, yarn.mYarn_Fill);
01007       outToken = this->BufToToken(ev, &buf);
01008     }
01009   }
01010   return outToken;
01011 }
01012 
01013 mork_token
01014 morkStore::BufToToken(morkEnv* ev, const morkBuf* inBuf)
01015 {
01016   mork_token outToken = 0;
01017   if ( ev->Good() )
01018   {
01019     const mork_u1* s = (const mork_u1*) inBuf->mBuf_Body;
01020     mork_bool nonAscii = ( *s > 0x7F );
01021     mork_size length = inBuf->mBuf_Fill;
01022     if ( nonAscii || length > 1 ) // more than one byte?
01023     {
01024       mork_cscode form = 0; // default charset
01025       morkAtomSpace* space = this->LazyGetGroundColumnSpace(ev);
01026       if ( space )
01027       {
01028         morkFarBookAtom* keyAtom = 0;
01029         if ( length <= morkBookAtom_kMaxBodySize )
01030         {
01031           mork_aid aid = 1; // dummy
01032           //mStore_BookAtom.InitMaxBookAtom(ev, *inBuf, form, space, aid);
01033           mStore_FarBookAtom.InitFarBookAtom(ev, *inBuf, form, space, aid);
01034           keyAtom = &mStore_FarBookAtom;
01035         }
01036         if ( keyAtom )
01037         {
01038           morkAtomBodyMap* map = &space->mAtomSpace_AtomBodies;
01039           morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
01040           if ( bookAtom )
01041             outToken = bookAtom->mBookAtom_Id;
01042           else
01043           {
01044             this->MaybeDirtyStore();
01045             bookAtom = space->MakeBookAtomCopy(ev, *keyAtom);
01046             if ( bookAtom )
01047             {
01048               outToken = bookAtom->mBookAtom_Id;
01049               bookAtom->MakeCellUseForever(ev);
01050             }
01051           }
01052         }
01053       }
01054     }
01055     else // only a single byte in inTokenName string:
01056       outToken = *s;
01057   }
01058   
01059   return outToken;
01060 }
01061 
01062 mork_token
01063 morkStore::StringToToken(morkEnv* ev, const char* inTokenName)
01064 {
01065   mork_token outToken = 0;
01066   if ( ev->Good() )
01067   {
01068     const mork_u1* s = (const mork_u1*) inTokenName;
01069     mork_bool nonAscii = ( *s > 0x7F );
01070     if ( nonAscii || ( *s && s[ 1 ] ) ) // more than one byte?
01071     {
01072       mork_cscode form = 0; // default charset
01073       morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev);
01074       if ( groundSpace )
01075       {
01076         morkFarBookAtom* keyAtom =
01077           this->StageStringAsFarBookAtom(ev, inTokenName, form, groundSpace);
01078         if ( keyAtom )
01079         {
01080           morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
01081           morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
01082           if ( bookAtom )
01083             outToken = bookAtom->mBookAtom_Id;
01084           else
01085           {
01086             this->MaybeDirtyStore();
01087             bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
01088             if ( bookAtom )
01089             {
01090               outToken = bookAtom->mBookAtom_Id;
01091               bookAtom->MakeCellUseForever(ev);
01092             }
01093           }
01094         }
01095       }
01096     }
01097     else // only a single byte in inTokenName string:
01098       outToken = *s;
01099   }
01100   
01101   return outToken;
01102 }
01103 
01104 mork_token
01105 morkStore::QueryToken(morkEnv* ev, const char* inTokenName)
01106 {
01107   mork_token outToken = 0;
01108   if ( ev->Good() )
01109   {
01110     const mork_u1* s = (const mork_u1*) inTokenName;
01111     mork_bool nonAscii = ( *s > 0x7F );
01112     if ( nonAscii || ( *s && s[ 1 ] ) ) // more than one byte?
01113     {
01114       mork_cscode form = 0; // default charset
01115       morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev);
01116       if ( groundSpace )
01117       {
01118         morkFarBookAtom* keyAtom =
01119           this->StageStringAsFarBookAtom(ev, inTokenName, form, groundSpace);
01120         if ( keyAtom )
01121         {
01122           morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
01123           morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom);
01124           if ( bookAtom )
01125           {
01126             outToken = bookAtom->mBookAtom_Id;
01127             bookAtom->MakeCellUseForever(ev);
01128           }
01129         }
01130       }
01131     }
01132     else // only a single byte in inTokenName string:
01133       outToken = *s;
01134   }
01135   
01136   return outToken;
01137 }
01138 
01139 mork_bool
01140 morkStore::HasTableKind(morkEnv* ev, mdb_scope inRowScope, 
01141   mdb_kind inTableKind, mdb_count* outTableCount)
01142 {
01143   MORK_USED_2(inRowScope,inTableKind);
01144   mork_bool outBool = morkBool_kFalse;
01145   mdb_count tableCount = 0;
01146 
01147   ev->StubMethodOnlyError();
01148   
01149   if ( outTableCount )
01150     *outTableCount = tableCount;
01151   return outBool;
01152 }
01153 
01154 morkTable*
01155 morkStore::GetTableKind(morkEnv* ev, mdb_scope inRowScope, 
01156   mdb_kind inTableKind, mdb_count* outTableCount,
01157   mdb_bool* outMustBeUnique)
01158 {
01159   morkTable* outTable = 0;
01160   if ( ev->Good() )
01161   {
01162     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope);
01163     if ( rowSpace )
01164     {
01165       outTable = rowSpace->FindTableByKind(ev, inTableKind);
01166       if ( outTable )
01167       {
01168         if ( outTableCount )
01169           *outTableCount = outTable->GetRowCount();
01170         if ( outMustBeUnique )
01171           *outMustBeUnique = outTable->IsTableUnique();
01172       }
01173     }
01174   }
01175   return outTable;
01176 }
01177 
01178 morkRow*
01179 morkStore::FindRow(morkEnv* ev, mdb_scope inScope, mdb_column inColumn,
01180   const mdbYarn* inYarn)
01181 {
01182   morkRow* outRow = 0;
01183   if ( ev->Good() )
01184   {
01185     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inScope);
01186     if ( rowSpace )
01187     {
01188       outRow = rowSpace->FindRow(ev, inColumn, inYarn);
01189     }
01190   }
01191   return outRow;
01192 }
01193 
01194 morkRow*
01195 morkStore::GetRow(morkEnv* ev, const mdbOid* inOid)
01196 {
01197   morkRow* outRow = 0;
01198   if ( ev->Good() )
01199   {
01200     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
01201     if ( rowSpace )
01202     {
01203       outRow = rowSpace->mRowSpace_Rows.GetOid(ev, inOid);
01204     }
01205   }
01206   return outRow;
01207 }
01208 
01209 morkTable*
01210 morkStore::GetTable(morkEnv* ev, const mdbOid* inOid)
01211 {
01212   morkTable* outTable = 0;
01213   if ( ev->Good() )
01214   {
01215     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
01216     if ( rowSpace )
01217     {
01218       outTable = rowSpace->FindTableByTid(ev, inOid->mOid_Id);
01219     }
01220   }
01221   return outTable;
01222 }
01223   
01224 morkTable*
01225 morkStore::NewTable(morkEnv* ev, mdb_scope inRowScope,
01226   mdb_kind inTableKind, mdb_bool inMustBeUnique,
01227   const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying 
01228 {
01229   morkTable* outTable = 0;
01230   if ( ev->Good() )
01231   {
01232     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope);
01233     if ( rowSpace )
01234       outTable = rowSpace->NewTable(ev, inTableKind, inMustBeUnique,
01235         inOptionalMetaRowOid);
01236   }
01237   return outTable;
01238 }
01239 
01240 morkPortTableCursor*
01241 morkStore::GetPortTableCursor(morkEnv* ev, mdb_scope inRowScope,
01242   mdb_kind inTableKind)
01243 {
01244   morkPortTableCursor* outCursor = 0;
01245   if ( ev->Good() )
01246   {
01247     nsIMdbHeap* heap = mPort_Heap;
01248     outCursor = new(*heap, ev) 
01249       morkPortTableCursor(ev, morkUsage::kHeap, heap, this,
01250         inRowScope, inTableKind, heap);
01251   }
01252   NS_IF_ADDREF(outCursor);
01253   return outCursor;
01254 }
01255 
01256 morkRow*
01257 morkStore::NewRow(morkEnv* ev, mdb_scope inRowScope)
01258 {
01259   morkRow* outRow = 0;
01260   if ( ev->Good() )
01261   {
01262     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope);
01263     if ( rowSpace )
01264       outRow = rowSpace->NewRow(ev);
01265   }
01266   return outRow;
01267 }
01268 
01269 morkRow*
01270 morkStore::NewRowWithOid(morkEnv* ev, const mdbOid* inOid)
01271 {
01272   morkRow* outRow = 0;
01273   if ( ev->Good() )
01274   {
01275     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
01276     if ( rowSpace )
01277       outRow = rowSpace->NewRowWithOid(ev, inOid);
01278   }
01279   return outRow;
01280 }
01281 
01282 morkRow*
01283 morkStore::OidToRow(morkEnv* ev, const mdbOid* inOid)
01284   // OidToRow() finds old row with oid, or makes new one if not found.
01285 {
01286   morkRow* outRow = 0;
01287   if ( ev->Good() )
01288   {
01289     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
01290     if ( rowSpace )
01291     {
01292       outRow = rowSpace->mRowSpace_Rows.GetOid(ev, inOid);
01293       if ( !outRow && ev->Good() )
01294         outRow = rowSpace->NewRowWithOid(ev, inOid);
01295     }
01296   }
01297   return outRow;
01298 }
01299 
01300 morkTable*
01301 morkStore::OidToTable(morkEnv* ev, const mdbOid* inOid,
01302   const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying 
01303   // OidToTable() finds old table with oid, or makes new one if not found.
01304 {
01305   morkTable* outTable = 0;
01306   if ( ev->Good() )
01307   {
01308     morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope);
01309     if ( rowSpace )
01310     {
01311       outTable = rowSpace->mRowSpace_Tables.GetTable(ev, inOid->mOid_Id);
01312       if ( !outTable && ev->Good() )
01313       {
01314         mork_kind tableKind = morkStore_kNoneToken;
01315         outTable = rowSpace->NewTableWithTid(ev, inOid->mOid_Id, tableKind,
01316           inOptionalMetaRowOid);
01317       }
01318     }
01319   }
01320   return outTable;
01321 }
01322 
01323 // { ===== begin nsIMdbObject methods =====
01324 
01325 // { ----- begin ref counting for well-behaved cyclic graphs -----
01326 NS_IMETHODIMP
01327 morkStore::GetWeakRefCount(nsIMdbEnv* mev, // weak refs
01328   mdb_count* outCount)
01329 {
01330   *outCount = WeakRefsOnly();
01331   return NS_OK;
01332 }  
01333 NS_IMETHODIMP
01334 morkStore::GetStrongRefCount(nsIMdbEnv* mev, // strong refs
01335   mdb_count* outCount)
01336 {
01337   *outCount = StrongRefsOnly();
01338   return NS_OK;
01339 }
01340 // ### TODO - clean up this cast, if required
01341 NS_IMETHODIMP
01342 morkStore::AddWeakRef(nsIMdbEnv* mev)
01343 {
01344   morkEnv *ev  = morkEnv::FromMdbEnv(mev);
01345   return morkNode::AddWeakRef(ev);
01346 }
01347 NS_IMETHODIMP
01348 morkStore::AddStrongRef(nsIMdbEnv* mev)
01349 {
01350   return AddRef();
01351 }
01352 
01353 NS_IMETHODIMP
01354 morkStore::CutWeakRef(nsIMdbEnv* mev)
01355 {
01356   morkEnv *ev  = morkEnv::FromMdbEnv(mev);
01357   return morkNode::CutWeakRef(ev);
01358 }
01359 NS_IMETHODIMP
01360 morkStore::CutStrongRef(nsIMdbEnv* mev)
01361 {
01362   return Release();
01363 }
01364 
01365 NS_IMETHODIMP
01366 morkStore::CloseMdbObject(nsIMdbEnv* mev)
01367 {
01368   morkEnv *ev = morkEnv::FromMdbEnv(mev);
01369   CloseMorkNode(ev);
01370   Release();
01371   return NS_OK;
01372 }
01373 
01374 NS_IMETHODIMP
01375 morkStore::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen)
01376 {
01377   *outOpen = IsOpenNode();
01378   return NS_OK;
01379 }
01380 // } ----- end ref counting -----
01381 
01382 // } ===== end nsIMdbObject methods =====
01383 
01384 // { ===== begin nsIMdbPort methods =====
01385 
01386 // { ----- begin attribute methods -----
01387 NS_IMETHODIMP
01388 morkStore::GetIsPortReadonly(nsIMdbEnv* mev, mdb_bool* outBool)
01389 {
01390   mdb_err outErr = 0;
01391   mdb_bool isReadOnly = morkBool_kFalse;
01392   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01393   if ( ev )
01394   {
01395     ev->StubMethodOnlyError();
01396     outErr = ev->AsErr();
01397   }
01398   if ( outBool )
01399     *outBool = isReadOnly;
01400   return outErr;
01401 }
01402 
01403 morkEnv*
01404 morkStore::CanUseStore(nsIMdbEnv* mev,
01405   mork_bool inMutable, mdb_err* outErr) const
01406 {
01407   morkEnv* outEnv = 0;
01408   morkEnv* ev = morkEnv::FromMdbEnv(mev);
01409   if ( ev )
01410   {
01411     if (IsStore())
01412       outEnv = ev;
01413     else
01414       NonStoreTypeError(ev);
01415     *outErr = ev->AsErr();
01416   }
01417   MORK_ASSERT(outEnv);
01418   return outEnv;
01419 }
01420 
01421 NS_IMETHODIMP
01422 morkStore::GetIsStore(nsIMdbEnv* mev, mdb_bool* outBool)
01423 {
01424   MORK_USED_1(mev);
01425  if ( outBool )
01426     *outBool = morkBool_kTrue;
01427   return 0;
01428 }
01429 
01430 NS_IMETHODIMP
01431 morkStore::GetIsStoreAndDirty(nsIMdbEnv* mev, mdb_bool* outBool)
01432 {
01433   mdb_err outErr = 0;
01434   mdb_bool isStoreAndDirty = morkBool_kFalse;
01435   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01436   if ( ev )
01437   {
01438     ev->StubMethodOnlyError();
01439     outErr = ev->AsErr();
01440   }
01441   if ( outBool )
01442     *outBool = isStoreAndDirty;
01443   return outErr;
01444 }
01445 
01446 NS_IMETHODIMP
01447 morkStore::GetUsagePolicy(nsIMdbEnv* mev, 
01448   mdbUsagePolicy* ioUsagePolicy)
01449 {
01450   MORK_USED_1(ioUsagePolicy);
01451   mdb_err outErr = 0;
01452   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01453   if ( ev )
01454   {
01455     ev->StubMethodOnlyError();
01456     outErr = ev->AsErr();
01457   }
01458   return outErr;
01459 }
01460 
01461 NS_IMETHODIMP
01462 morkStore::SetUsagePolicy(nsIMdbEnv* mev, 
01463   const mdbUsagePolicy* inUsagePolicy)
01464 {
01465   MORK_USED_1(inUsagePolicy);
01466   mdb_err outErr = 0;
01467   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01468   if ( ev )
01469   {
01470     // ev->StubMethodOnlyError(); // okay to do nothing?
01471     outErr = ev->AsErr();
01472   }
01473   return outErr;
01474 }
01475 // } ----- end attribute methods -----
01476 
01477 // { ----- begin memory policy methods -----  
01478 NS_IMETHODIMP
01479 morkStore::IdleMemoryPurge( // do memory management already scheduled
01480   nsIMdbEnv* mev, // context
01481   mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed
01482 {
01483   mdb_err outErr = 0;
01484   mdb_size estimatedBytesFreed = 0;
01485   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01486   if ( ev )
01487   {
01488     // ev->StubMethodOnlyError(); // okay to do nothing?
01489     outErr = ev->AsErr();
01490   }
01491   if ( outEstimatedBytesFreed )
01492     *outEstimatedBytesFreed = estimatedBytesFreed;
01493   return outErr;
01494 }
01495 
01496 NS_IMETHODIMP
01497 morkStore::SessionMemoryPurge( // request specific footprint decrease
01498   nsIMdbEnv* mev, // context
01499   mdb_size inDesiredBytesFreed, // approximate number of bytes wanted
01500   mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed
01501 {
01502   MORK_USED_1(inDesiredBytesFreed);
01503   mdb_err outErr = 0;
01504   mdb_size estimate = 0;
01505   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01506   if ( ev )
01507   {
01508     // ev->StubMethodOnlyError(); // okay to do nothing?
01509     outErr = ev->AsErr();
01510   }
01511   if ( outEstimatedBytesFreed )
01512     *outEstimatedBytesFreed = estimate;
01513   return outErr;
01514 }
01515 
01516 NS_IMETHODIMP
01517 morkStore::PanicMemoryPurge( // desperately free all possible memory
01518   nsIMdbEnv* mev, // context
01519   mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed
01520 {
01521   mdb_err outErr = 0;
01522   mdb_size estimate = 0;
01523   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01524   if ( ev )
01525   {
01526     // ev->StubMethodOnlyError(); // okay to do nothing?
01527     outErr = ev->AsErr();
01528   }
01529   if ( outEstimatedBytesFreed )
01530     *outEstimatedBytesFreed = estimate;
01531   return outErr;
01532 }
01533 // } ----- end memory policy methods -----
01534 
01535 // { ----- begin filepath methods -----
01536 NS_IMETHODIMP
01537 morkStore::GetPortFilePath(
01538   nsIMdbEnv* mev, // context
01539   mdbYarn* outFilePath, // name of file holding port content
01540   mdbYarn* outFormatVersion) // file format description
01541 {
01542   mdb_err outErr = 0;
01543   if ( outFormatVersion )
01544     outFormatVersion->mYarn_Fill = 0;
01545   if ( outFilePath )
01546     outFilePath->mYarn_Fill = 0;
01547   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01548   if ( ev )
01549   {
01550     if ( mStore_File )
01551       mStore_File->Path(mev, outFilePath);
01552     else
01553       NilStoreFileError(ev);
01554     
01555     outErr = ev->AsErr();
01556   }
01557   return outErr;
01558 }
01559 
01560 NS_IMETHODIMP
01561 morkStore::GetPortFile(
01562   nsIMdbEnv* mev, // context
01563   nsIMdbFile** acqFile) // acquire file used by port or store
01564 {
01565   mdb_err outErr = 0;
01566   if ( acqFile )
01567     *acqFile = 0;
01568 
01569   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01570   if ( ev )
01571   {
01572     
01573     if ( mStore_File )
01574     {
01575       if ( acqFile )
01576       {
01577         mStore_File->AddRef();
01578         if ( ev->Good() )
01579           *acqFile = mStore_File;
01580       }
01581     }
01582     else
01583       NilStoreFileError(ev);
01584       
01585     outErr = ev->AsErr();
01586   }
01587   return outErr;
01588 }
01589 // } ----- end filepath methods -----
01590 
01591 // { ----- begin export methods -----
01592 NS_IMETHODIMP
01593 morkStore::BestExportFormat( // determine preferred export format
01594   nsIMdbEnv* mev, // context
01595   mdbYarn* outFormatVersion) // file format description
01596 {
01597   mdb_err outErr = 0;
01598   if ( outFormatVersion )
01599     outFormatVersion->mYarn_Fill = 0;
01600   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01601   if ( ev )
01602   {
01603     ev->StubMethodOnlyError();
01604     outErr = ev->AsErr();
01605   }
01606   return outErr;
01607 }
01608 
01609 NS_IMETHODIMP
01610 morkStore::CanExportToFormat( // can export content in given specific format?
01611   nsIMdbEnv* mev, // context
01612   const char* inFormatVersion, // file format description
01613   mdb_bool* outCanExport) // whether ExportSource() might succeed
01614 {
01615   MORK_USED_1(inFormatVersion);
01616   mdb_bool canExport = morkBool_kFalse;
01617   mdb_err outErr = 0;
01618   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01619   if ( ev )
01620   {
01621     ev->StubMethodOnlyError();
01622     outErr = ev->AsErr();
01623   }
01624   if ( outCanExport )
01625     *outCanExport = canExport;
01626   return outErr;
01627 }
01628 
01629 NS_IMETHODIMP
01630 morkStore::ExportToFormat( // export content in given specific format
01631   nsIMdbEnv* mev, // context
01632   // const char* inFilePath, // the file to receive exported content
01633   nsIMdbFile* ioFile, // destination abstract file interface
01634   const char* inFormatVersion, // file format description
01635   nsIMdbThumb** acqThumb) // acquire thumb for incremental export
01636 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
01637 // then the export will be finished.
01638 {
01639   mdb_err outErr = 0;
01640   nsIMdbThumb* outThumb = 0;
01641   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01642   if ( ev )
01643   {
01644     if ( ioFile && inFormatVersion && acqThumb )
01645     {
01646       ev->StubMethodOnlyError();
01647     }
01648     else
01649       ev->NilPointerError();
01650     
01651     outErr = ev->AsErr();
01652   }
01653   if ( acqThumb )
01654     *acqThumb = outThumb;
01655   return outErr;
01656 }
01657 
01658 // } ----- end export methods -----
01659 
01660 // { ----- begin token methods -----
01661 NS_IMETHODIMP
01662 morkStore::TokenToString( // return a string name for an integer token
01663   nsIMdbEnv* mev, // context
01664   mdb_token inToken, // token for inTokenName inside this port
01665   mdbYarn* outTokenName) // the type of table to access
01666 {
01667   mdb_err outErr = 0;
01668   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01669   if ( ev )
01670   {
01671     TokenToString(ev, inToken, outTokenName);
01672     outErr = ev->AsErr();
01673   }
01674   return outErr;
01675 }
01676 
01677 NS_IMETHODIMP
01678 morkStore::StringToToken( // return an integer token for scope name
01679   nsIMdbEnv* mev, // context
01680   const char* inTokenName, // Latin1 string to tokenize if possible
01681   mdb_token* outToken) // token for inTokenName inside this port
01682   // String token zero is never used and never supported. If the port
01683   // is a mutable store, then StringToToken() to create a new
01684   // association of inTokenName with a new integer token if possible.
01685   // But a readonly port will return zero for an unknown scope name.
01686 {
01687   mdb_err outErr = 0;
01688   mdb_token token = 0;
01689   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01690   if ( ev )
01691   {
01692     token = StringToToken(ev, inTokenName);
01693     outErr = ev->AsErr();
01694   }
01695   if ( outToken )
01696     *outToken = token;
01697   return outErr;
01698 }
01699   
01700 
01701 NS_IMETHODIMP
01702 morkStore::QueryToken( // like StringToToken(), but without adding
01703   nsIMdbEnv* mev, // context
01704   const char* inTokenName, // Latin1 string to tokenize if possible
01705   mdb_token* outToken) // token for inTokenName inside this port
01706   // QueryToken() will return a string token if one already exists,
01707   // but unlike StringToToken(), will not assign a new token if not
01708   // already in use.
01709 {
01710   mdb_err outErr = 0;
01711   mdb_token token = 0;
01712   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01713   if ( ev )
01714   {
01715     token = QueryToken(ev, inTokenName);
01716     outErr = ev->AsErr();
01717   }
01718   if ( outToken )
01719     *outToken = token;
01720   return outErr;
01721 }
01722 
01723 
01724 // } ----- end token methods -----
01725 
01726 // { ----- begin row methods -----  
01727 NS_IMETHODIMP
01728 morkStore::HasRow( // contains a row with the specified oid?
01729   nsIMdbEnv* mev, // context
01730   const mdbOid* inOid,  // hypothetical row oid
01731   mdb_bool* outHasRow) // whether GetRow() might succeed
01732 {
01733   mdb_err outErr = 0;
01734   mdb_bool hasRow = morkBool_kFalse;
01735   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01736   if ( ev )
01737   {
01738     morkRow* row = GetRow(ev, inOid);
01739     if ( row )
01740       hasRow = morkBool_kTrue;
01741       
01742     outErr = ev->AsErr();
01743   }
01744   if ( outHasRow )
01745     *outHasRow = hasRow;
01746   return outErr;
01747 }
01748   
01749 NS_IMETHODIMP
01750 morkStore::GetRow( // access one row with specific oid
01751   nsIMdbEnv* mev, // context
01752   const mdbOid* inOid,  // hypothetical row oid
01753   nsIMdbRow** acqRow) // acquire specific row (or null)
01754 {
01755   mdb_err outErr = 0;
01756   nsIMdbRow* outRow = 0;
01757   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01758   if ( ev )
01759   {
01760     morkRow* row = GetRow(ev, inOid);
01761     if ( row && ev->Good() )
01762       outRow = row->AcquireRowHandle(ev, this);
01763       
01764     outErr = ev->AsErr();
01765   }
01766   if ( acqRow )
01767     *acqRow = outRow;
01768   return outErr;
01769 }
01770 
01771 NS_IMETHODIMP
01772 morkStore::GetRowRefCount( // get number of tables that contain a row 
01773   nsIMdbEnv* mev, // context
01774   const mdbOid* inOid,  // hypothetical row oid
01775   mdb_count* outRefCount) // number of tables containing inRowKey 
01776 {
01777   mdb_err outErr = 0;
01778   mdb_count count = 0;
01779   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01780   if ( ev )
01781   {
01782     morkRow* row = GetRow(ev, inOid);
01783     if ( row && ev->Good() )
01784       count = row->mRow_GcUses;
01785       
01786     outErr = ev->AsErr();
01787   }
01788   if ( outRefCount )
01789     *outRefCount = count;
01790   return outErr;
01791 }
01792 
01793 NS_IMETHODIMP
01794 morkStore::FindRow(nsIMdbEnv* mev, // search for row with matching cell
01795     mdb_scope inRowScope,   // row scope for row ids
01796     mdb_column inColumn,   // the column to search (and maintain an index)
01797     const mdbYarn* inTargetCellValue, // cell value for which to search
01798     mdbOid* outRowOid, // out row oid on match (or {0,-1} for no match)
01799     nsIMdbRow** acqRow) // acquire matching row (or nil for no match)
01800   // FindRow() searches for one row that has a cell in column inColumn with
01801   // a contained value with the same form (i.e. charset) and is byte-wise
01802   // identical to the blob described by yarn inTargetCellValue.  Both content
01803   // and form of the yarn must be an exact match to find a matching row.
01804   //
01805   // (In other words, both a yarn's blob bytes and form are significant.  The
01806   // form is not expected to vary in columns used for identity anyway.  This
01807   // is intended to make the cost of FindRow() cheaper for MDB implementors,
01808   // since any cell value atomization performed internally must necessarily
01809   // make yarn form significant in order to avoid data loss in atomization.)
01810   //
01811   // FindRow() can lazily create an index on attribute inColumn for all rows
01812   // with that attribute in row space scope inRowScope, so that subsequent
01813   // calls to FindRow() will perform faster.  Such an index might or might
01814   // not be persistent (but this seems desirable if it is cheap to do so).
01815   // Note that lazy index creation in readonly DBs is not very feasible.
01816   //
01817   // This FindRow() interface assumes that attribute inColumn is effectively
01818   // an alternative means of unique identification for a row in a rowspace,
01819   // so correct behavior is only guaranteed when no duplicates for this col
01820   // appear in the given set of rows.  (If more than one row has the same cell
01821   // value in this column, no more than one will be found; and cutting one of
01822   // two duplicate rows can cause the index to assume no other such row lives
01823   // in the row space, so future calls return nil for negative search results
01824   // even though some duplicate row might still live within the rowspace.)
01825   //
01826   // In other words, the FindRow() implementation is allowed to assume simple
01827   // hash tables mapping unqiue column keys to associated row values will be
01828   // sufficient, where any duplication is not recorded because only one copy
01829   // of a given key need be remembered.  Implementors are not required to sort
01830   // all rows by the specified column.
01831 {
01832   mdb_err outErr = 0;
01833   nsIMdbRow* outRow = 0;
01834   mdbOid rowOid;
01835   rowOid.mOid_Scope = 0;
01836   rowOid.mOid_Id = (mdb_id) -1;
01837   
01838   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01839   if ( ev )
01840   {
01841     morkRow* row = FindRow(ev, inRowScope, inColumn, inTargetCellValue);
01842     if ( row && ev->Good() )
01843     {
01844       rowOid = row->mRow_Oid;
01845       if ( acqRow )
01846           outRow = row->AcquireRowHandle(ev, this);
01847     }
01848     outErr = ev->AsErr();
01849   }
01850   if ( acqRow )
01851     *acqRow = outRow;
01852   if ( outRowOid )
01853     *outRowOid = rowOid;
01854 
01855   return outErr;
01856 }
01857 
01858 // } ----- end row methods -----
01859 
01860 // { ----- begin table methods -----  
01861 NS_IMETHODIMP
01862 morkStore::HasTable( // supports a table with the specified oid?
01863   nsIMdbEnv* mev, // context
01864   const mdbOid* inOid,  // hypothetical table oid
01865   mdb_bool* outHasTable) // whether GetTable() might succeed
01866 {
01867   mdb_err outErr = 0;
01868   mork_bool hasTable = morkBool_kFalse;
01869   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01870   if ( ev )
01871   {
01872     morkTable* table = GetTable(ev, inOid);
01873     if ( table )
01874       hasTable = morkBool_kTrue;
01875     
01876     outErr = ev->AsErr();
01877   }
01878   if ( outHasTable )
01879     *outHasTable = hasTable;
01880   return outErr;
01881 }
01882   
01883 NS_IMETHODIMP
01884 morkStore::GetTable( // access one table with specific oid
01885   nsIMdbEnv* mev, // context
01886   const mdbOid* inOid,  // hypothetical table oid
01887   nsIMdbTable** acqTable) // acquire specific table (or null)
01888 {
01889   mdb_err outErr = 0;
01890   nsIMdbTable* outTable = 0;
01891   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01892   if ( ev )
01893   {
01894     morkTable* table = GetTable(ev, inOid);
01895     if ( table && ev->Good() )
01896       outTable = table->AcquireTableHandle(ev);
01897     outErr = ev->AsErr();
01898   }
01899   if ( acqTable )
01900     *acqTable = outTable;
01901   return outErr;
01902 }
01903 
01904 NS_IMETHODIMP
01905 morkStore::HasTableKind( // supports a table of the specified type?
01906   nsIMdbEnv* mev, // context
01907   mdb_scope inRowScope, // rid scope for row ids
01908   mdb_kind inTableKind, // the type of table to access
01909   mdb_count* outTableCount, // current number of such tables
01910   mdb_bool* outSupportsTable) // whether GetTableKind() might succeed
01911 {
01912   mdb_err outErr = 0;
01913   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01914   if ( ev )
01915   {
01916     *outSupportsTable = HasTableKind(ev, inRowScope,
01917         inTableKind, outTableCount);
01918     outErr = ev->AsErr();
01919   }
01920   return outErr;
01921 }
01922       
01923 NS_IMETHODIMP
01924 morkStore::GetTableKind( // access one (random) table of specific type
01925   nsIMdbEnv* mev, // context
01926   mdb_scope inRowScope,      // row scope for row ids
01927   mdb_kind inTableKind,      // the type of table to access
01928   mdb_count* outTableCount, // current number of such tables
01929   mdb_bool* outMustBeUnique, // whether port can hold only one of these
01930   nsIMdbTable** acqTable)      // acquire scoped collection of rows
01931 {
01932   mdb_err outErr = 0;
01933   nsIMdbTable* outTable = 0;
01934   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01935   if ( ev )
01936   {
01937     morkTable* table = GetTableKind(ev, inRowScope,
01938         inTableKind, outTableCount, outMustBeUnique);
01939     if ( table && ev->Good() )
01940       outTable = table->AcquireTableHandle(ev);
01941     outErr = ev->AsErr();
01942   }
01943   if ( acqTable )
01944     *acqTable = outTable;
01945   return outErr;
01946 }
01947   
01948 NS_IMETHODIMP
01949 morkStore::GetPortTableCursor( // get cursor for all tables of specific type
01950   nsIMdbEnv* mev, // context
01951   mdb_scope inRowScope, // row scope for row ids
01952   mdb_kind inTableKind, // the type of table to access
01953   nsIMdbPortTableCursor** acqCursor) // all such tables in the port
01954 {
01955   mdb_err outErr = 0;
01956   nsIMdbPortTableCursor* outCursor = 0;
01957   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01958   if ( ev )
01959   {
01960     morkPortTableCursor* cursor =
01961       GetPortTableCursor(ev, inRowScope,
01962         inTableKind);
01963     if ( cursor && ev->Good() )
01964       outCursor = cursor;
01965 
01966     outErr = ev->AsErr();
01967   }
01968   if ( acqCursor )
01969     *acqCursor = outCursor;
01970   return outErr;
01971 }
01972 // } ----- end table methods -----
01973 
01974 // { ----- begin commit methods -----
01975   
01976 NS_IMETHODIMP
01977 morkStore::ShouldCompress( // store wastes at least inPercentWaste?
01978   nsIMdbEnv* mev, // context
01979   mdb_percent inPercentWaste, // 0..100 percent file size waste threshold
01980   mdb_percent* outActualWaste, // 0..100 percent of file actually wasted
01981   mdb_bool* outShould) // true when about inPercentWaste% is wasted
01982 {
01983   mdb_percent actualWaste = 0;
01984   mdb_bool shouldCompress = morkBool_kFalse;
01985   mdb_err outErr = 0;
01986   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
01987   if ( ev )
01988   {
01989     actualWaste = PercentOfStoreWasted(ev);
01990     if ( inPercentWaste > 100 )
01991       inPercentWaste = 100;
01992     shouldCompress = ( actualWaste >= inPercentWaste );
01993     outErr = ev->AsErr();
01994   }
01995   if ( outActualWaste )
01996     *outActualWaste = actualWaste;
01997   if ( outShould )
01998     *outShould = shouldCompress;
01999   return outErr;
02000 }
02001 
02002 
02003 // } ===== end nsIMdbPort methods =====
02004 
02005 NS_IMETHODIMP
02006 morkStore::NewTable( // make one new table of specific type
02007   nsIMdbEnv* mev, // context
02008   mdb_scope inRowScope,    // row scope for row ids
02009   mdb_kind inTableKind,    // the type of table to access
02010   mdb_bool inMustBeUnique, // whether store can hold only one of these
02011   const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying 
02012   nsIMdbTable** acqTable)     // acquire scoped collection of rows
02013 {
02014   mdb_err outErr = 0;
02015   nsIMdbTable* outTable = 0;
02016   morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
02017   if ( ev )
02018   {
02019     morkTable* table = NewTable(ev, inRowScope,
02020         inTableKind, inMustBeUnique, inOptionalMetaRowOid);
02021     if ( table && ev->Good() )
02022       outTable = table->AcquireTableHandle(ev);
02023     outErr = ev->AsErr();
02024   }
02025   if ( acqTable )
02026     *acqTable = outTable;
02027   return outErr;
02028 }
02029 
02030 NS_IMETHODIMP
02031 morkStore::NewTableWithOid( // make one new table of specific type
02032   nsIMdbEnv* mev, // context
02033   const mdbOid* inOid,   // caller assigned oid
02034   mdb_kind inTableKind,    // the type of table to access
02035   mdb_bool inMustBeUnique, // whether store can hold only one of these
02036   const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying 
02037   nsIMdbTable** acqTable)     // acquire scoped collection of rows
02038 {
02039   mdb_err outErr = 0;
02040   nsIMdbTable* outTable = 0;
02041   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
02042   if ( ev )
02043   {
02044     morkTable* table = OidToTable(ev, inOid,
02045       inOptionalMetaRowOid);
02046     if ( table && ev->Good() )
02047     {
02048       table->mTable_Kind = inTableKind;
02049       if ( inMustBeUnique )
02050         table->SetTableUnique();
02051       outTable = table->AcquireTableHandle(ev);
02052     }
02053     outErr = ev->AsErr();
02054   }
02055   if ( acqTable )
02056     *acqTable = outTable;
02057   return outErr;
02058 }
02059 // } ----- end table methods -----
02060 
02061 // { ----- begin row scope methods -----
02062 NS_IMETHODIMP
02063 morkStore::RowScopeHasAssignedIds(nsIMdbEnv* mev,
02064   mdb_scope inRowScope,   // row scope for row ids
02065   mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
02066   mdb_bool* outStoreAssigned) // nonzero if store db assigned specified
02067 {
02068   NS_ASSERTION(PR_FALSE, " not implemented");
02069   return NS_ERROR_NOT_IMPLEMENTED;
02070 }
02071 
02072 NS_IMETHODIMP
02073 morkStore::SetCallerAssignedIds(nsIMdbEnv* mev,
02074   mdb_scope inRowScope,   // row scope for row ids
02075   mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
02076   mdb_bool* outStoreAssigned) // nonzero if store db assigned specified
02077 {
02078   NS_ASSERTION(PR_FALSE, " not implemented");
02079   return NS_ERROR_NOT_IMPLEMENTED;
02080 }
02081 
02082 NS_IMETHODIMP
02083 morkStore::SetStoreAssignedIds(nsIMdbEnv* mev,
02084   mdb_scope inRowScope,   // row scope for row ids
02085   mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
02086   mdb_bool* outStoreAssigned) // nonzero if store db assigned specified
02087 {
02088   NS_ASSERTION(PR_FALSE, " not implemented");
02089   return NS_ERROR_NOT_IMPLEMENTED;
02090 }
02091 // } ----- end row scope methods -----
02092 
02093 // { ----- begin row methods -----
02094 NS_IMETHODIMP
02095 morkStore::NewRowWithOid(nsIMdbEnv* mev, // new row w/ caller assigned oid
02096   const mdbOid* inOid,   // caller assigned oid
02097   nsIMdbRow** acqRow) // create new row
02098 {
02099   mdb_err outErr = 0;
02100   nsIMdbRow* outRow = 0;
02101   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
02102   if ( ev )
02103   {
02104     morkRow* row = NewRowWithOid(ev, inOid);
02105     if ( row && ev->Good() )
02106       outRow = row->AcquireRowHandle(ev, this);
02107       
02108     outErr = ev->AsErr();
02109   }
02110   if ( acqRow )
02111     *acqRow = outRow;
02112   return outErr;
02113 }
02114 
02115 NS_IMETHODIMP
02116 morkStore::NewRow(nsIMdbEnv* mev, // new row with db assigned oid
02117   mdb_scope inRowScope,   // row scope for row ids
02118   nsIMdbRow** acqRow) // create new row
02119 // Note this row must be added to some table or cell child before the
02120 // store is closed in order to make this row persist across sesssions.
02121 {
02122   mdb_err outErr = 0;
02123   nsIMdbRow* outRow = 0;
02124   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
02125   if ( ev )
02126   {
02127     morkRow* row = NewRow(ev, inRowScope);
02128     if ( row && ev->Good() )
02129       outRow = row->AcquireRowHandle(ev, this);
02130       
02131     outErr = ev->AsErr();
02132   }
02133   if ( acqRow )
02134     *acqRow = outRow;
02135   return outErr;
02136 }
02137 // } ----- end row methods -----
02138 
02139 // { ----- begin inport/export methods -----
02140 NS_IMETHODIMP
02141 morkStore::ImportContent( // import content from port
02142   nsIMdbEnv* mev, // context
02143   mdb_scope inRowScope, // scope for rows (or zero for all?)
02144   nsIMdbPort* ioPort, // the port with content to add to store
02145   nsIMdbThumb** acqThumb) // acquire thumb for incremental import
02146 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
02147 // then the import will be finished.
02148 {
02149   NS_ASSERTION(PR_FALSE, " not implemented");
02150   return NS_ERROR_NOT_IMPLEMENTED;
02151 }
02152 
02153 NS_IMETHODIMP
02154 morkStore::ImportFile( // import content from port
02155   nsIMdbEnv* mev, // context
02156   nsIMdbFile* ioFile, // the file with content to add to store
02157   nsIMdbThumb** acqThumb) // acquire thumb for incremental import
02158 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
02159 // then the import will be finished.
02160 {
02161   NS_ASSERTION(PR_FALSE, " not implemented");
02162   return NS_ERROR_NOT_IMPLEMENTED;
02163 }
02164 // } ----- end inport/export methods -----
02165 
02166 // { ----- begin hinting methods -----
02167 NS_IMETHODIMP
02168 morkStore::ShareAtomColumnsHint( // advise re shared col content atomizing
02169   nsIMdbEnv* mev, // context
02170   mdb_scope inScopeHint, // zero, or suggested shared namespace
02171   const mdbColumnSet* inColumnSet) // cols desired tokenized together
02172 {
02173   MORK_USED_2(inColumnSet,inScopeHint);
02174   mdb_err outErr = 0;
02175   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
02176   if ( ev )
02177   {
02178     // ev->StubMethodOnlyError(); // okay to do nothing for a hint method
02179     outErr = ev->AsErr();
02180   }
02181   return outErr;
02182 }
02183 
02184 NS_IMETHODIMP
02185 morkStore::AvoidAtomColumnsHint( // advise col w/ poor atomizing prospects
02186   nsIMdbEnv* mev, // context
02187   const mdbColumnSet* inColumnSet) // cols with poor atomizing prospects
02188 {
02189   MORK_USED_1(inColumnSet);
02190   mdb_err outErr = 0;
02191   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
02192   if ( ev )
02193   {
02194     // ev->StubMethodOnlyError(); // okay to do nothing for a hint method
02195     outErr = ev->AsErr();
02196   }
02197   return outErr;
02198 }
02199 // } ----- end hinting methods -----
02200 
02201 // { ----- begin commit methods -----
02202 NS_IMETHODIMP
02203 morkStore::SmallCommit( // save minor changes if convenient and uncostly
02204   nsIMdbEnv* mev) // context
02205 {
02206   mdb_err outErr = 0;
02207   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
02208   if ( ev )
02209   {
02210     // ev->StubMethodOnlyError(); // it's okay to do nothing for small commit
02211     outErr = ev->AsErr();
02212   }
02213   return outErr;
02214 }
02215 
02216 NS_IMETHODIMP
02217 morkStore::LargeCommit( // save important changes if at all possible
02218   nsIMdbEnv* mev, // context
02219   nsIMdbThumb** acqThumb) // acquire thumb for incremental commit
02220 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
02221 // then the commit will be finished.  Note the store is effectively write
02222 // locked until commit is finished or canceled through the thumb instance.
02223 // Until the commit is done, the store will report it has readonly status.
02224 {
02225   nsresult outErr = 0;
02226   nsIMdbThumb* outThumb = 0;
02227   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
02228   if ( ev )
02229   {
02230     
02231     morkThumb* thumb = 0;
02232     // morkFile* file = store->mStore_File;
02233     if ( DoPreferLargeOverCompressCommit(ev) )
02234     {
02235       thumb = morkThumb::Make_LargeCommit(ev, mPort_Heap, this);
02236     }
02237     else
02238     {
02239       mork_bool doCollect = morkBool_kFalse;
02240       thumb = morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect);
02241     }
02242     
02243     if ( thumb )
02244     {
02245       outThumb = thumb;
02246       thumb->AddRef();
02247     }
02248       
02249     outErr = ev->AsErr();
02250   }
02251   if ( acqThumb )
02252     *acqThumb = outThumb;
02253   return outErr;
02254 }
02255 
02256 NS_IMETHODIMP
02257 morkStore::SessionCommit( // save all changes if large commits delayed
02258   nsIMdbEnv* mev, // context
02259   nsIMdbThumb** acqThumb) // acquire thumb for incremental commit
02260 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
02261 // then the commit will be finished.  Note the store is effectively write
02262 // locked until commit is finished or canceled through the thumb instance.
02263 // Until the commit is done, the store will report it has readonly status.
02264 {
02265   nsresult outErr = NS_OK;
02266   nsIMdbThumb* outThumb = 0;
02267   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
02268   if ( ev )
02269   {
02270     
02271     morkThumb* thumb = 0;
02272     if ( DoPreferLargeOverCompressCommit(ev) )
02273     {
02274       thumb = morkThumb::Make_LargeCommit(ev, mPort_Heap, this);
02275     }
02276     else
02277     {
02278       mork_bool doCollect = morkBool_kFalse;
02279       thumb = morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect);
02280     }
02281     
02282     if ( thumb )
02283     {
02284       outThumb = thumb;
02285       thumb->AddRef();
02286     }
02287     outErr = ev->AsErr();
02288   }
02289   if ( acqThumb )
02290     *acqThumb = outThumb;
02291   return outErr;
02292 }
02293 
02294 NS_IMETHODIMP
02295 morkStore::CompressCommit( // commit and make db smaller if possible
02296   nsIMdbEnv* mev, // context
02297   nsIMdbThumb** acqThumb) // acquire thumb for incremental commit
02298 // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
02299 // then the commit will be finished.  Note the store is effectively write
02300 // locked until commit is finished or canceled through the thumb instance.
02301 // Until the commit is done, the store will report it has readonly status.
02302 {
02303   nsresult outErr = NS_OK;
02304   nsIMdbThumb* outThumb = 0;
02305   morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
02306   if ( ev )
02307   {
02308     mork_bool doCollect = morkBool_kFalse;
02309     morkThumb* thumb = morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect);
02310     if ( thumb )
02311     {
02312       outThumb = thumb;
02313       thumb->AddRef();
02314       mStore_CanWriteIncremental = morkBool_kTrue;
02315     }
02316       
02317     outErr = ev->AsErr();
02318   }
02319   if ( acqThumb )
02320     *acqThumb = outThumb;
02321   return outErr;
02322 }
02323 
02324 // } ----- end commit methods -----
02325 
02326 // } ===== end nsIMdbStore methods =====
02327 
02328 
02329 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
02330