diff options
Diffstat (limited to 'db/mork/src/morkStore.cpp')
-rw-r--r-- | db/mork/src/morkStore.cpp | 2290 |
1 files changed, 2290 insertions, 0 deletions
diff --git a/db/mork/src/morkStore.cpp b/db/mork/src/morkStore.cpp new file mode 100644 index 0000000000..47f145c83b --- /dev/null +++ b/db/mork/src/morkStore.cpp @@ -0,0 +1,2290 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _MDB_ +#include "mdb.h" +#endif + +#ifndef _MORK_ +#include "mork.h" +#endif + +#ifndef _MORKNODE_ +#include "morkNode.h" +#endif + +#ifndef _MORKBLOB_ +#include "morkBlob.h" +#endif + +#ifndef _MORKMAP_ +#include "morkMap.h" +#endif + +#ifndef _MORKENV_ +#include "morkEnv.h" +#endif + +#ifndef _MORKSTORE_ +#include "morkStore.h" +#endif + +#ifndef _MORKFACTORY_ +#include "morkFactory.h" +#endif + +#ifndef _MORKNODEMAP_ +#include "morkNodeMap.h" +#endif + +#ifndef _MORKROW_ +#include "morkRow.h" +#endif + +#ifndef _MORKTHUMB_ +#include "morkThumb.h" +#endif +// #ifndef _MORKFILE_ +// #include "morkFile.h" +// #endif + +#ifndef _MORKBUILDER_ +#include "morkBuilder.h" +#endif + +#ifndef _MORKATOMSPACE_ +#include "morkAtomSpace.h" +#endif + +#ifndef _MORKSTREAM_ +#include "morkStream.h" +#endif + +#ifndef _MORKATOMSPACE_ +#include "morkAtomSpace.h" +#endif + +#ifndef _MORKROWSPACE_ +#include "morkRowSpace.h" +#endif + +#ifndef _MORKPORTTABLECURSOR_ +#include "morkPortTableCursor.h" +#endif + +#ifndef _MORKTABLE_ +#include "morkTable.h" +#endif + +#ifndef _MORKROWMAP_ +#include "morkRowMap.h" +#endif + +#ifndef _MORKPARSER_ +#include "morkParser.h" +#endif + +#include "nsCOMPtr.h" + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +// ````` ````` ````` ````` ````` +// { ===== begin morkNode interface ===== + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + +// ````` ````` ````` ````` ````` +// { ===== begin morkNode interface ===== + +/*public virtual*/ void +morkStore::CloseMorkNode(morkEnv* ev) // ClosePort() only if open +{ + if ( this->IsOpenNode() ) + { + this->MarkClosing(); + this->CloseStore(ev); + this->MarkShut(); + } +} + +/*public non-poly*/ void +morkStore::ClosePort(morkEnv* ev) // called by CloseMorkNode(); +{ + if ( this->IsNode() ) + { + morkFactory::SlotWeakFactory((morkFactory*) 0, ev, &mPort_Factory); + nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mPort_Heap); + this->CloseObject(ev); + this->MarkShut(); + } + else + this->NonNodeError(ev); +} + +/*public virtual*/ +morkStore::~morkStore() // assert CloseStore() executed earlier +{ + MOZ_COUNT_DTOR(morkStore); + if (IsOpenNode()) + CloseMorkNode(mMorkEnv); + MORK_ASSERT(this->IsShutNode()); + MORK_ASSERT(mStore_File==0); + MORK_ASSERT(mStore_InStream==0); + MORK_ASSERT(mStore_OutStream==0); + MORK_ASSERT(mStore_Builder==0); + MORK_ASSERT(mStore_OidAtomSpace==0); + MORK_ASSERT(mStore_GroundAtomSpace==0); + MORK_ASSERT(mStore_GroundColumnSpace==0); + MORK_ASSERT(mStore_RowSpaces.IsShutNode()); + MORK_ASSERT(mStore_AtomSpaces.IsShutNode()); + MORK_ASSERT(mStore_Pool.IsShutNode()); +} + +/*public non-poly*/ +morkStore::morkStore(morkEnv* ev, const morkUsage& inUsage, + nsIMdbHeap* ioNodeHeap, // the heap (if any) for this node instance + morkFactory* inFactory, // the factory for this + nsIMdbHeap* ioPortHeap // the heap to hold all content in the port + ) +: morkObject(ev, inUsage, ioNodeHeap, morkColor_kNone, (morkHandle*) 0) +, mPort_Env( ev ) +, mPort_Factory( 0 ) +, mPort_Heap( 0 ) +, mStore_OidAtomSpace( 0 ) +, mStore_GroundAtomSpace( 0 ) +, mStore_GroundColumnSpace( 0 ) + +, mStore_File( 0 ) +, mStore_InStream( 0 ) +, mStore_Builder( 0 ) +, mStore_OutStream( 0 ) + +, mStore_RowSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap) +, mStore_AtomSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap) +, mStore_Zone(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap) +, mStore_Pool(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap) + +, mStore_CommitGroupIdentity( 0 ) + +, mStore_FirstCommitGroupPos( 0 ) +, mStore_SecondCommitGroupPos( 0 ) + +// disable auto-assignment of atom IDs until someone knows it is okay: +, mStore_CanAutoAssignAtomIdentity( morkBool_kFalse ) +, mStore_CanDirty( morkBool_kFalse ) // not until the store is open +, mStore_CanWriteIncremental( morkBool_kTrue ) // always with few exceptions +{ + MOZ_COUNT_CTOR(morkStore); + if ( ev->Good() ) + { + if ( inFactory && ioPortHeap ) + { + morkFactory::SlotWeakFactory(inFactory, ev, &mPort_Factory); + nsIMdbHeap_SlotStrongHeap(ioPortHeap, ev, &mPort_Heap); + if ( ev->Good() ) + mNode_Derived = morkDerived_kPort; + } + else + ev->NilPointerError(); + } + if ( ev->Good() ) + { + mNode_Derived = morkDerived_kStore; + + } +} + +NS_IMPL_ISUPPORTS_INHERITED(morkStore, morkObject, nsIMdbStore) + +/*public non-poly*/ void +morkStore::CloseStore(morkEnv* ev) // called by CloseMorkNode(); +{ + if ( this->IsNode() ) + { + + nsIMdbFile* file = mStore_File; + file->AddRef(); + + morkFactory::SlotWeakFactory((morkFactory*) 0, ev, &mPort_Factory); + nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mPort_Heap); + morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev, + &mStore_OidAtomSpace); + morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev, + &mStore_GroundAtomSpace); + morkAtomSpace::SlotStrongAtomSpace((morkAtomSpace*) 0, ev, + &mStore_GroundColumnSpace); + mStore_RowSpaces.CloseMorkNode(ev); + mStore_AtomSpaces.CloseMorkNode(ev); + morkBuilder::SlotStrongBuilder((morkBuilder*) 0, ev, &mStore_Builder); + + nsIMdbFile_SlotStrongFile((nsIMdbFile*) 0, ev, + &mStore_File); + + file->Release(); + + morkStream::SlotStrongStream((morkStream*) 0, ev, &mStore_InStream); + morkStream::SlotStrongStream((morkStream*) 0, ev, &mStore_OutStream); + + mStore_Pool.CloseMorkNode(ev); + mStore_Zone.CloseMorkNode(ev); + this->ClosePort(ev); + this->MarkShut(); + } + else + this->NonNodeError(ev); +} + +// } ===== end morkNode methods ===== +// ````` ````` ````` ````` ````` + + +mork_bool morkStore::DoPreferLargeOverCompressCommit(morkEnv* ev) + // true when mStore_CanWriteIncremental && store has file large enough +{ + nsIMdbFile* file = mStore_File; + if ( file && mStore_CanWriteIncremental ) + { + mdb_pos fileEof = 0; + file->Eof(ev->AsMdbEnv(), &fileEof); + if ( ev->Good() && fileEof > 128 ) + return morkBool_kTrue; + } + return morkBool_kFalse; +} + +mork_percent morkStore::PercentOfStoreWasted(morkEnv* ev) +{ + mork_percent outPercent = 0; + nsIMdbFile* file = mStore_File; + + if ( file ) + { + mork_pos firstPos = mStore_FirstCommitGroupPos; + mork_pos secondPos = mStore_SecondCommitGroupPos; + if ( firstPos || secondPos ) + { + if ( firstPos < 512 && secondPos > firstPos ) + firstPos = secondPos; // better approximation of first commit + + mork_pos fileLength = 0; + file->Eof(ev->AsMdbEnv(), &fileLength); // end of file + if ( ev->Good() && fileLength > firstPos ) + { + mork_size groupContent = fileLength - firstPos; + outPercent = ( groupContent * 100 ) / fileLength; + } + } + } + else + this->NilStoreFileError(ev); + + return outPercent; +} + +void +morkStore::SetStoreAndAllSpacesCanDirty(morkEnv* ev, mork_bool inCanDirty) +{ + mStore_CanDirty = inCanDirty; + + mork_change* c = 0; + mork_scope* key = 0; // ignore keys in maps + + if ( ev->Good() ) + { + morkAtomSpaceMapIter asi(ev, &mStore_AtomSpaces); + + morkAtomSpace* atomSpace = 0; // old val node in the map + + for ( c = asi.FirstAtomSpace(ev, key, &atomSpace); c && ev->Good(); + c = asi.NextAtomSpace(ev, key, &atomSpace) ) + { + if ( atomSpace ) + { + if ( atomSpace->IsAtomSpace() ) + atomSpace->mSpace_CanDirty = inCanDirty; + else + atomSpace->NonAtomSpaceTypeError(ev); + } + else + ev->NilPointerError(); + } + } + + if ( ev->Good() ) + { + morkRowSpaceMapIter rsi(ev, &mStore_RowSpaces); + morkRowSpace* rowSpace = 0; // old val node in the map + + for ( c = rsi.FirstRowSpace(ev, key, &rowSpace); c && ev->Good(); + c = rsi.NextRowSpace(ev, key, &rowSpace) ) + { + if ( rowSpace ) + { + if ( rowSpace->IsRowSpace() ) + rowSpace->mSpace_CanDirty = inCanDirty; + else + rowSpace->NonRowSpaceTypeError(ev); + } + } + } +} + +void +morkStore::RenumberAllCollectableContent(morkEnv* ev) +{ + MORK_USED_1(ev); + // do nothing currently +} + +nsIMdbStore* +morkStore::AcquireStoreHandle(morkEnv* ev) +{ + return this; +} + + +morkFarBookAtom* +morkStore::StageAliasAsFarBookAtom(morkEnv* ev, const morkMid* inMid, + morkAtomSpace* ioSpace, mork_cscode inForm) +{ + if ( inMid && inMid->mMid_Buf ) + { + const morkBuf* buf = inMid->mMid_Buf; + mork_size length = buf->mBuf_Fill; + if ( length <= morkBookAtom_kMaxBodySize ) + { + mork_aid dummyAid = 1; + //mStore_BookAtom.InitMaxBookAtom(ev, *buf, + // inForm, ioSpace, dummyAid); + + mStore_FarBookAtom.InitFarBookAtom(ev, *buf, + inForm, ioSpace, dummyAid); + return &mStore_FarBookAtom; + } + } + else + ev->NilPointerError(); + + return (morkFarBookAtom*) 0; +} + +morkFarBookAtom* +morkStore::StageYarnAsFarBookAtom(morkEnv* ev, const mdbYarn* inYarn, + morkAtomSpace* ioSpace) +{ + if ( inYarn && inYarn->mYarn_Buf ) + { + mork_size length = inYarn->mYarn_Fill; + if ( length <= morkBookAtom_kMaxBodySize ) + { + morkBuf buf(inYarn->mYarn_Buf, length); + mork_aid dummyAid = 1; + //mStore_BookAtom.InitMaxBookAtom(ev, buf, + // inYarn->mYarn_Form, ioSpace, dummyAid); + mStore_FarBookAtom.InitFarBookAtom(ev, buf, + inYarn->mYarn_Form, ioSpace, dummyAid); + return &mStore_FarBookAtom; + } + } + else + ev->NilPointerError(); + + return (morkFarBookAtom*) 0; +} + +morkFarBookAtom* +morkStore::StageStringAsFarBookAtom(morkEnv* ev, const char* inString, + mork_cscode inForm, morkAtomSpace* ioSpace) +{ + if ( inString ) + { + mork_size length = MORK_STRLEN(inString); + if ( length <= morkBookAtom_kMaxBodySize ) + { + morkBuf buf(inString, length); + mork_aid dummyAid = 1; + //mStore_BookAtom.InitMaxBookAtom(ev, buf, inForm, ioSpace, dummyAid); + mStore_FarBookAtom.InitFarBookAtom(ev, buf, inForm, ioSpace, dummyAid); + return &mStore_FarBookAtom; + } + } + else + ev->NilPointerError(); + + return (morkFarBookAtom*) 0; +} + +morkAtomSpace* morkStore::LazyGetOidAtomSpace(morkEnv* ev) +{ + MORK_USED_1(ev); + if ( !mStore_OidAtomSpace ) + { + } + return mStore_OidAtomSpace; +} + +morkAtomSpace* morkStore::LazyGetGroundAtomSpace(morkEnv* ev) +{ + if ( !mStore_GroundAtomSpace ) + { + mork_scope atomScope = morkStore_kValueSpaceScope; + nsIMdbHeap* heap = mPort_Heap; + morkAtomSpace* space = new(*heap, ev) + morkAtomSpace(ev, morkUsage::kHeap, atomScope, this, heap, heap); + + if ( space ) // successful space creation? + { + this->MaybeDirtyStore(); + + mStore_GroundAtomSpace = space; // transfer strong ref to this slot + mStore_AtomSpaces.AddAtomSpace(ev, space); + } + } + return mStore_GroundAtomSpace; +} + +morkAtomSpace* morkStore::LazyGetGroundColumnSpace(morkEnv* ev) +{ + if ( !mStore_GroundColumnSpace ) + { + mork_scope atomScope = morkStore_kGroundColumnSpace; + nsIMdbHeap* heap = mPort_Heap; + morkAtomSpace* space = new(*heap, ev) + morkAtomSpace(ev, morkUsage::kHeap, atomScope, this, heap, heap); + + if ( space ) // successful space creation? + { + this->MaybeDirtyStore(); + + mStore_GroundColumnSpace = space; // transfer strong ref to this slot + mStore_AtomSpaces.AddAtomSpace(ev, space); + } + } + return mStore_GroundColumnSpace; +} + +morkStream* morkStore::LazyGetInStream(morkEnv* ev) +{ + if ( !mStore_InStream ) + { + nsIMdbFile* file = mStore_File; + if ( file ) + { + morkStream* stream = new(*mPort_Heap, ev) + morkStream(ev, morkUsage::kHeap, mPort_Heap, file, + morkStore_kStreamBufSize, /*frozen*/ morkBool_kTrue); + if ( stream ) + { + this->MaybeDirtyStore(); + mStore_InStream = stream; // transfer strong ref to this slot + } + } + else + this->NilStoreFileError(ev); + } + return mStore_InStream; +} + +morkStream* morkStore::LazyGetOutStream(morkEnv* ev) +{ + if ( !mStore_OutStream ) + { + nsIMdbFile* file = mStore_File; + if ( file ) + { + morkStream* stream = new(*mPort_Heap, ev) + morkStream(ev, morkUsage::kHeap, mPort_Heap, file, + morkStore_kStreamBufSize, /*frozen*/ morkBool_kFalse); + if ( stream ) + { + this->MaybeDirtyStore(); + mStore_InStream = stream; // transfer strong ref to this slot + } + } + else + this->NilStoreFileError(ev); + } + return mStore_OutStream; +} + +void +morkStore::ForgetBuilder(morkEnv* ev) +{ + if ( mStore_Builder ) + morkBuilder::SlotStrongBuilder((morkBuilder*) 0, ev, &mStore_Builder); + if ( mStore_InStream ) + morkStream::SlotStrongStream((morkStream*) 0, ev, &mStore_InStream); +} + +morkBuilder* morkStore::LazyGetBuilder(morkEnv* ev) +{ + if ( !mStore_Builder ) + { + morkStream* stream = this->LazyGetInStream(ev); + if ( stream ) + { + nsIMdbHeap* heap = mPort_Heap; + morkBuilder* builder = new(*heap, ev) + morkBuilder(ev, morkUsage::kHeap, heap, stream, + morkBuilder_kDefaultBytesPerParseSegment, heap, this); + if ( builder ) + { + mStore_Builder = builder; // transfer strong ref to this slot + } + } + } + return mStore_Builder; +} + +morkRowSpace* +morkStore::LazyGetRowSpace(morkEnv* ev, mdb_scope inRowScope) +{ + morkRowSpace* outSpace = mStore_RowSpaces.GetRowSpace(ev, inRowScope); + if ( !outSpace && ev->Good() ) // try to make new space? + { + nsIMdbHeap* heap = mPort_Heap; + outSpace = new(*heap, ev) + morkRowSpace(ev, morkUsage::kHeap, inRowScope, this, heap, heap); + + if ( outSpace ) // successful space creation? + { + this->MaybeDirtyStore(); + + // note adding to node map creates its own strong ref... + if ( mStore_RowSpaces.AddRowSpace(ev, outSpace) ) + outSpace->CutStrongRef(ev); // ...so we can drop our strong ref + } + } + return outSpace; +} + +morkAtomSpace* +morkStore::LazyGetAtomSpace(morkEnv* ev, mdb_scope inAtomScope) +{ + morkAtomSpace* outSpace = mStore_AtomSpaces.GetAtomSpace(ev, inAtomScope); + if ( !outSpace && ev->Good() ) // try to make new space? + { + if ( inAtomScope == morkStore_kValueSpaceScope ) + outSpace = this->LazyGetGroundAtomSpace(ev); + + else if ( inAtomScope == morkStore_kGroundColumnSpace ) + outSpace = this->LazyGetGroundColumnSpace(ev); + else + { + nsIMdbHeap* heap = mPort_Heap; + outSpace = new(*heap, ev) + morkAtomSpace(ev, morkUsage::kHeap, inAtomScope, this, heap, heap); + + if ( outSpace ) // successful space creation? + { + this->MaybeDirtyStore(); + + // note adding to node map creates its own strong ref... + if ( mStore_AtomSpaces.AddAtomSpace(ev, outSpace) ) + outSpace->CutStrongRef(ev); // ...so we can drop our strong ref + } + } + } + return outSpace; +} + +/*static*/ void +morkStore::NonStoreTypeError(morkEnv* ev) +{ + ev->NewError("non morkStore"); +} + +/*static*/ void +morkStore::NilStoreFileError(morkEnv* ev) +{ + ev->NewError("nil mStore_File"); +} + +/*static*/ void +morkStore::CannotAutoAssignAtomIdentityError(morkEnv* ev) +{ + ev->NewError("false mStore_CanAutoAssignAtomIdentity"); +} + + +mork_bool +morkStore::OpenStoreFile(morkEnv* ev, mork_bool inFrozen, + // const char* inFilePath, + nsIMdbFile* ioFile, // db abstract file interface + const mdbOpenPolicy* inOpenPolicy) +{ + MORK_USED_2(inOpenPolicy,inFrozen); + nsIMdbFile_SlotStrongFile(ioFile, ev, &mStore_File); + + // if ( ev->Good() ) + // { + // morkFile* file = morkFile::OpenOldFile(ev, mPort_Heap, + // inFilePath, inFrozen); + // if ( ioFile ) + // { + // if ( ev->Good() ) + // morkFile::SlotStrongFile(file, ev, &mStore_File); + // else + // file->CutStrongRef(ev); + // + // } + // } + return ev->Good(); +} + +mork_bool +morkStore::CreateStoreFile(morkEnv* ev, + // const char* inFilePath, + nsIMdbFile* ioFile, // db abstract file interface + const mdbOpenPolicy* inOpenPolicy) +{ + MORK_USED_1(inOpenPolicy); + nsIMdbFile_SlotStrongFile(ioFile, ev, &mStore_File); + + return ev->Good(); +} + +morkAtom* +morkStore::CopyAtom(morkEnv* ev, const morkAtom* inAtom) +// copy inAtom (from some other store) over to this store +{ + morkAtom* outAtom = 0; + if ( inAtom ) + { + mdbYarn yarn; + if ( morkAtom::AliasYarn(inAtom, &yarn) ) + outAtom = this->YarnToAtom(ev, &yarn, true /* create */); + } + return outAtom; +} + +morkAtom* +morkStore::YarnToAtom(morkEnv* ev, const mdbYarn* inYarn, bool createIfMissing /* = true */) +{ + morkAtom* outAtom = 0; + if ( ev->Good() ) + { + morkAtomSpace* groundSpace = this->LazyGetGroundAtomSpace(ev); + if ( groundSpace ) + { + morkFarBookAtom* keyAtom = + this->StageYarnAsFarBookAtom(ev, inYarn, groundSpace); + + if ( keyAtom ) + { + morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies; + outAtom = map->GetAtom(ev, keyAtom); + if ( !outAtom && createIfMissing) + { + this->MaybeDirtyStore(); + outAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom); + } + } + else if ( ev->Good() ) + { + morkBuf b(inYarn->mYarn_Buf, inYarn->mYarn_Fill); + morkZone* z = &mStore_Zone; + outAtom = mStore_Pool.NewAnonAtom(ev, b, inYarn->mYarn_Form, z); + } + } + } + return outAtom; +} + +mork_bool +morkStore::MidToOid(morkEnv* ev, const morkMid& inMid, mdbOid* outOid) +{ + *outOid = inMid.mMid_Oid; + const morkBuf* buf = inMid.mMid_Buf; + if ( buf && !outOid->mOid_Scope ) + { + if ( buf->mBuf_Fill <= morkBookAtom_kMaxBodySize ) + { + if ( buf->mBuf_Fill == 1 ) + { + mork_u1* name = (mork_u1*) buf->mBuf_Body; + if ( name ) + { + outOid->mOid_Scope = (mork_scope) *name; + return ev->Good(); + } + } + morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev); + if ( groundSpace ) + { + mork_cscode form = 0; // default + mork_aid aid = 1; // dummy + mStore_FarBookAtom.InitFarBookAtom(ev, *buf, form, groundSpace, aid); + morkFarBookAtom* keyAtom = &mStore_FarBookAtom; + morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies; + morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom); + if ( bookAtom ) + outOid->mOid_Scope = bookAtom->mBookAtom_Id; + else + { + this->MaybeDirtyStore(); + bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom); + if ( bookAtom ) + { + outOid->mOid_Scope = bookAtom->mBookAtom_Id; + bookAtom->MakeCellUseForever(ev); + } + } + } + } + } + return ev->Good(); +} + +morkRow* +morkStore::MidToRow(morkEnv* ev, const morkMid& inMid) +{ + mdbOid tempOid; + this->MidToOid(ev, inMid, &tempOid); + return this->OidToRow(ev, &tempOid); +} + +morkTable* +morkStore::MidToTable(morkEnv* ev, const morkMid& inMid) +{ + mdbOid tempOid; + this->MidToOid(ev, inMid, &tempOid); + return this->OidToTable(ev, &tempOid, /*metarow*/ (mdbOid*) 0); +} + +mork_bool +morkStore::MidToYarn(morkEnv* ev, const morkMid& inMid, mdbYarn* outYarn) +{ + mdbOid tempOid; + this->MidToOid(ev, inMid, &tempOid); + return this->OidToYarn(ev, tempOid, outYarn); +} + +mork_bool +morkStore::OidToYarn(morkEnv* ev, const mdbOid& inOid, mdbYarn* outYarn) +{ + morkBookAtom* atom = 0; + + morkAtomSpace* atomSpace = mStore_AtomSpaces.GetAtomSpace(ev, inOid.mOid_Scope); + if ( atomSpace ) + { + morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids; + atom = map->GetAid(ev, (mork_aid) inOid.mOid_Id); + } + atom->GetYarn(outYarn); // note this is safe even when atom==nil + + return ev->Good(); +} + +morkBookAtom* +morkStore::MidToAtom(morkEnv* ev, const morkMid& inMid) +{ + morkBookAtom* outAtom = 0; + mdbOid oid; + if ( this->MidToOid(ev, inMid, &oid) ) + { + morkAtomSpace* atomSpace = mStore_AtomSpaces.GetAtomSpace(ev, oid.mOid_Scope); + if ( atomSpace ) + { + morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids; + outAtom = map->GetAid(ev, (mork_aid) oid.mOid_Id); + } + } + return outAtom; +} + +/*static*/ void +morkStore::SmallTokenToOneByteYarn(morkEnv* ev, mdb_token inToken, + mdbYarn* outYarn) +{ + MORK_USED_1(ev); + if ( outYarn->mYarn_Buf && outYarn->mYarn_Size ) // any space in yarn at all? + { + mork_u1* buf = (mork_u1*) outYarn->mYarn_Buf; // for byte arithmetic + buf[ 0 ] = (mork_u1) inToken; // write the single byte + outYarn->mYarn_Fill = 1; + outYarn->mYarn_More = 0; + } + else // just record we could not write the single byte + { + outYarn->mYarn_More = 1; + outYarn->mYarn_Fill = 0; + } +} + +void +morkStore::TokenToString(morkEnv* ev, mdb_token inToken, mdbYarn* outTokenName) +{ + if ( inToken > morkAtomSpace_kMaxSevenBitAid ) + { + morkBookAtom* atom = 0; + morkAtomSpace* space = mStore_GroundColumnSpace; + if ( space ) + atom = space->mAtomSpace_AtomAids.GetAid(ev, (mork_aid) inToken); + + atom->GetYarn(outTokenName); // note this is safe even when atom==nil + } + else // token is an "immediate" single byte string representation? + this->SmallTokenToOneByteYarn(ev, inToken, outTokenName); +} + +// void +// morkStore::SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom, +// const mdbOid* inOid) +// { +// mork_token mStore_MorkNoneToken; // token for "mork:none" // fill=9 +// mork_column mStore_CharsetToken; // token for "charset" // fill=7 +// mork_column mStore_AtomScopeToken; // token for "atomScope" // fill=9 +// mork_column mStore_RowScopeToken; // token for "rowScope" // fill=8 +// mork_column mStore_TableScopeToken; // token for "tableScope" // fill=10 +// mork_column mStore_ColumnScopeToken; // token for "columnScope" // fill=11 +// mork_kind mStore_TableKindToken; // token for "tableKind" // fill=9 +// ---------------------ruler-for-token-length-above---123456789012 +// +// if ( inOid->mOid_Scope == morkStore_kColumnSpaceScope && inAtom->IsWeeBook() ) +// { +// const mork_u1* body = ((const morkWeeBookAtom*) inAtom)->mWeeBookAtom_Body; +// mork_size size = inAtom->mAtom_Size; +// +// if ( size >= 7 && size <= 11 ) +// { +// if ( size == 9 ) +// { +// if ( *body == 'm' ) +// { +// if ( MORK_MEMCMP(body, "mork:none", 9) == 0 ) +// mStore_MorkNoneToken = inAtom->mBookAtom_Id; +// } +// else if ( *body == 'a' ) +// { +// if ( MORK_MEMCMP(body, "atomScope", 9) == 0 ) +// mStore_AtomScopeToken = inAtom->mBookAtom_Id; +// } +// else if ( *body == 't' ) +// { +// if ( MORK_MEMCMP(body, "tableKind", 9) == 0 ) +// mStore_TableKindToken = inAtom->mBookAtom_Id; +// } +// } +// else if ( size == 7 && *body == 'c' ) +// { +// if ( MORK_MEMCMP(body, "charset", 7) == 0 ) +// mStore_CharsetToken = inAtom->mBookAtom_Id; +// } +// else if ( size == 8 && *body == 'r' ) +// { +// if ( MORK_MEMCMP(body, "rowScope", 8) == 0 ) +// mStore_RowScopeToken = inAtom->mBookAtom_Id; +// } +// else if ( size == 10 && *body == 't' ) +// { +// if ( MORK_MEMCMP(body, "tableScope", 10) == 0 ) +// mStore_TableScopeToken = inAtom->mBookAtom_Id; +// } +// else if ( size == 11 && *body == 'c' ) +// { +// if ( MORK_MEMCMP(body, "columnScope", 11) == 0 ) +// mStore_ColumnScopeToken = inAtom->mBookAtom_Id; +// } +// } +// } +// } + +morkAtom* +morkStore::AddAlias(morkEnv* ev, const morkMid& inMid, mork_cscode inForm) +{ + morkBookAtom* outAtom = 0; + if ( ev->Good() ) + { + const mdbOid* oid = &inMid.mMid_Oid; + morkAtomSpace* atomSpace = this->LazyGetAtomSpace(ev, oid->mOid_Scope); + if ( atomSpace ) + { + morkFarBookAtom* keyAtom = + this->StageAliasAsFarBookAtom(ev, &inMid, atomSpace, inForm); + if ( keyAtom ) + { + morkAtomAidMap* map = &atomSpace->mAtomSpace_AtomAids; + outAtom = map->GetAid(ev, (mork_aid) oid->mOid_Id); + if ( outAtom ) + { + if ( !outAtom->EqualFormAndBody(ev, keyAtom) ) + ev->NewError("duplicate alias ID"); + } + else + { + this->MaybeDirtyStore(); + keyAtom->mBookAtom_Id = oid->mOid_Id; + outAtom = atomSpace->MakeBookAtomCopyWithAid(ev, + *keyAtom, (mork_aid) oid->mOid_Id); + + // if ( outAtom && outAtom->IsWeeBook() ) + // { + // if ( oid->mOid_Scope == morkStore_kColumnSpaceScope ) + // { + // mork_size size = outAtom->mAtom_Size; + // if ( size >= 7 && size <= 11 ) + // this->SyncTokenIdChange(ev, outAtom, oid); + // } + // } + } + } + } + } + return outAtom; +} + +#define morkStore_kMaxCopyTokenSize 512 /* if larger, cannot be copied */ + +mork_token +morkStore::CopyToken(morkEnv* ev, mdb_token inToken, morkStore* inStore) +// copy inToken from inStore over to this store +{ + mork_token outToken = 0; + if ( inStore == this ) // same store? + outToken = inToken; // just return token unchanged + else + { + char yarnBuf[ morkStore_kMaxCopyTokenSize ]; + mdbYarn yarn; + yarn.mYarn_Buf = yarnBuf; + yarn.mYarn_Fill = 0; + yarn.mYarn_Size = morkStore_kMaxCopyTokenSize; + yarn.mYarn_More = 0; + yarn.mYarn_Form = 0; + yarn.mYarn_Grow = 0; + + inStore->TokenToString(ev, inToken, &yarn); + if ( ev->Good() ) + { + morkBuf buf(yarn.mYarn_Buf, yarn.mYarn_Fill); + outToken = this->BufToToken(ev, &buf); + } + } + return outToken; +} + +mork_token +morkStore::BufToToken(morkEnv* ev, const morkBuf* inBuf) +{ + mork_token outToken = 0; + if ( ev->Good() ) + { + const mork_u1* s = (const mork_u1*) inBuf->mBuf_Body; + mork_bool nonAscii = ( *s > 0x7F ); + mork_size length = inBuf->mBuf_Fill; + if ( nonAscii || length > 1 ) // more than one byte? + { + mork_cscode form = 0; // default charset + morkAtomSpace* space = this->LazyGetGroundColumnSpace(ev); + if ( space ) + { + morkFarBookAtom* keyAtom = 0; + if ( length <= morkBookAtom_kMaxBodySize ) + { + mork_aid aid = 1; // dummy + //mStore_BookAtom.InitMaxBookAtom(ev, *inBuf, form, space, aid); + mStore_FarBookAtom.InitFarBookAtom(ev, *inBuf, form, space, aid); + keyAtom = &mStore_FarBookAtom; + } + if ( keyAtom ) + { + morkAtomBodyMap* map = &space->mAtomSpace_AtomBodies; + morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom); + if ( bookAtom ) + outToken = bookAtom->mBookAtom_Id; + else + { + this->MaybeDirtyStore(); + bookAtom = space->MakeBookAtomCopy(ev, *keyAtom); + if ( bookAtom ) + { + outToken = bookAtom->mBookAtom_Id; + bookAtom->MakeCellUseForever(ev); + } + } + } + } + } + else // only a single byte in inTokenName string: + outToken = *s; + } + + return outToken; +} + +mork_token +morkStore::StringToToken(morkEnv* ev, const char* inTokenName) +{ + mork_token outToken = 0; + if ( ev->Good() ) + { + const mork_u1* s = (const mork_u1*) inTokenName; + mork_bool nonAscii = ( *s > 0x7F ); + if ( nonAscii || ( *s && s[ 1 ] ) ) // more than one byte? + { + mork_cscode form = 0; // default charset + morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev); + if ( groundSpace ) + { + morkFarBookAtom* keyAtom = + this->StageStringAsFarBookAtom(ev, inTokenName, form, groundSpace); + if ( keyAtom ) + { + morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies; + morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom); + if ( bookAtom ) + outToken = bookAtom->mBookAtom_Id; + else + { + this->MaybeDirtyStore(); + bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom); + if ( bookAtom ) + { + outToken = bookAtom->mBookAtom_Id; + bookAtom->MakeCellUseForever(ev); + } + } + } + } + } + else // only a single byte in inTokenName string: + outToken = *s; + } + + return outToken; +} + +mork_token +morkStore::QueryToken(morkEnv* ev, const char* inTokenName) +{ + mork_token outToken = 0; + if ( ev->Good() ) + { + const mork_u1* s = (const mork_u1*) inTokenName; + mork_bool nonAscii = ( *s > 0x7F ); + if ( nonAscii || ( *s && s[ 1 ] ) ) // more than one byte? + { + mork_cscode form = 0; // default charset + morkAtomSpace* groundSpace = this->LazyGetGroundColumnSpace(ev); + if ( groundSpace ) + { + morkFarBookAtom* keyAtom = + this->StageStringAsFarBookAtom(ev, inTokenName, form, groundSpace); + if ( keyAtom ) + { + morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies; + morkBookAtom* bookAtom = map->GetAtom(ev, keyAtom); + if ( bookAtom ) + { + outToken = bookAtom->mBookAtom_Id; + bookAtom->MakeCellUseForever(ev); + } + } + } + } + else // only a single byte in inTokenName string: + outToken = *s; + } + + return outToken; +} + +mork_bool +morkStore::HasTableKind(morkEnv* ev, mdb_scope inRowScope, + mdb_kind inTableKind, mdb_count* outTableCount) +{ + MORK_USED_2(inRowScope,inTableKind); + mork_bool outBool = morkBool_kFalse; + mdb_count tableCount = 0; + + ev->StubMethodOnlyError(); + + if ( outTableCount ) + *outTableCount = tableCount; + return outBool; +} + +morkTable* +morkStore::GetTableKind(morkEnv* ev, mdb_scope inRowScope, + mdb_kind inTableKind, mdb_count* outTableCount, + mdb_bool* outMustBeUnique) +{ + morkTable* outTable = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope); + if ( rowSpace ) + { + outTable = rowSpace->FindTableByKind(ev, inTableKind); + if ( outTable ) + { + if ( outTableCount ) + *outTableCount = outTable->GetRowCount(); + if ( outMustBeUnique ) + *outMustBeUnique = outTable->IsTableUnique(); + } + } + } + return outTable; +} + +morkRow* +morkStore::FindRow(morkEnv* ev, mdb_scope inScope, mdb_column inColumn, + const mdbYarn* inYarn) +{ + morkRow* outRow = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inScope); + if ( rowSpace ) + { + outRow = rowSpace->FindRow(ev, inColumn, inYarn); + } + } + return outRow; +} + +morkRow* +morkStore::GetRow(morkEnv* ev, const mdbOid* inOid) +{ + morkRow* outRow = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope); + if ( rowSpace ) + { + outRow = rowSpace->mRowSpace_Rows.GetOid(ev, inOid); + } + } + return outRow; +} + +morkTable* +morkStore::GetTable(morkEnv* ev, const mdbOid* inOid) +{ + morkTable* outTable = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope); + if ( rowSpace ) + { + outTable = rowSpace->FindTableByTid(ev, inOid->mOid_Id); + } + } + return outTable; +} + +morkTable* +morkStore::NewTable(morkEnv* ev, mdb_scope inRowScope, + mdb_kind inTableKind, mdb_bool inMustBeUnique, + const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying +{ + morkTable* outTable = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope); + if ( rowSpace ) + outTable = rowSpace->NewTable(ev, inTableKind, inMustBeUnique, + inOptionalMetaRowOid); + } + return outTable; +} + +morkPortTableCursor* +morkStore::GetPortTableCursor(morkEnv* ev, mdb_scope inRowScope, + mdb_kind inTableKind) +{ + morkPortTableCursor* outCursor = 0; + if ( ev->Good() ) + { + nsIMdbHeap* heap = mPort_Heap; + outCursor = new(*heap, ev) + morkPortTableCursor(ev, morkUsage::kHeap, heap, this, + inRowScope, inTableKind, heap); + } + NS_IF_ADDREF(outCursor); + return outCursor; +} + +morkRow* +morkStore::NewRow(morkEnv* ev, mdb_scope inRowScope) +{ + morkRow* outRow = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inRowScope); + if ( rowSpace ) + outRow = rowSpace->NewRow(ev); + } + return outRow; +} + +morkRow* +morkStore::NewRowWithOid(morkEnv* ev, const mdbOid* inOid) +{ + morkRow* outRow = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope); + if ( rowSpace ) + outRow = rowSpace->NewRowWithOid(ev, inOid); + } + return outRow; +} + +morkRow* +morkStore::OidToRow(morkEnv* ev, const mdbOid* inOid) + // OidToRow() finds old row with oid, or makes new one if not found. +{ + morkRow* outRow = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope); + if ( rowSpace ) + { + outRow = rowSpace->mRowSpace_Rows.GetOid(ev, inOid); + if ( !outRow && ev->Good() ) + outRow = rowSpace->NewRowWithOid(ev, inOid); + } + } + return outRow; +} + +morkTable* +morkStore::OidToTable(morkEnv* ev, const mdbOid* inOid, + const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying + // OidToTable() finds old table with oid, or makes new one if not found. +{ + morkTable* outTable = 0; + if ( ev->Good() ) + { + morkRowSpace* rowSpace = this->LazyGetRowSpace(ev, inOid->mOid_Scope); + if ( rowSpace ) + { + outTable = rowSpace->mRowSpace_Tables.GetTable(ev, inOid->mOid_Id); + if ( !outTable && ev->Good() ) + { + mork_kind tableKind = morkStore_kNoneToken; + outTable = rowSpace->NewTableWithTid(ev, inOid->mOid_Id, tableKind, + inOptionalMetaRowOid); + } + } + } + return outTable; +} + +// { ===== begin nsIMdbObject methods ===== + +// { ----- begin ref counting for well-behaved cyclic graphs ----- +NS_IMETHODIMP +morkStore::GetWeakRefCount(nsIMdbEnv* mev, // weak refs + mdb_count* outCount) +{ + *outCount = WeakRefsOnly(); + return NS_OK; +} +NS_IMETHODIMP +morkStore::GetStrongRefCount(nsIMdbEnv* mev, // strong refs + mdb_count* outCount) +{ + *outCount = StrongRefsOnly(); + return NS_OK; +} +// ### TODO - clean up this cast, if required +NS_IMETHODIMP +morkStore::AddWeakRef(nsIMdbEnv* mev) +{ + morkEnv *ev = morkEnv::FromMdbEnv(mev); + // XXX Casting mork_refs to nsresult + return static_cast<nsresult>(morkNode::AddWeakRef(ev)); +} +#ifndef _MSC_VER +NS_IMETHODIMP_(mork_uses) +morkStore::AddStrongRef(morkEnv* mev) +{ + return AddRef(); +} +#endif +NS_IMETHODIMP_(mork_uses) +morkStore::AddStrongRef(nsIMdbEnv* mev) +{ + return AddRef(); +} +NS_IMETHODIMP +morkStore::CutWeakRef(nsIMdbEnv* mev) +{ + morkEnv *ev = morkEnv::FromMdbEnv(mev); + // XXX Casting mork_refs to nsresult + return static_cast<nsresult>(morkNode::CutWeakRef(ev)); +} +#ifndef _MSC_VER +NS_IMETHODIMP_(mork_uses) +morkStore::CutStrongRef(morkEnv* mev) +{ + return Release(); +} +#endif +NS_IMETHODIMP +morkStore::CutStrongRef(nsIMdbEnv* mev) +{ + // XXX Casting nsrefcnt to nsresult + return static_cast<nsresult>(Release()); +} + +NS_IMETHODIMP +morkStore::CloseMdbObject(nsIMdbEnv* mev) +{ + morkEnv *ev = morkEnv::FromMdbEnv(mev); + CloseMorkNode(ev); + Release(); + return NS_OK; +} + +NS_IMETHODIMP +morkStore::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen) +{ + *outOpen = IsOpenNode(); + return NS_OK; +} +// } ----- end ref counting ----- + +// } ===== end nsIMdbObject methods ===== + +// { ===== begin nsIMdbPort methods ===== + +// { ----- begin attribute methods ----- +NS_IMETHODIMP +morkStore::GetIsPortReadonly(nsIMdbEnv* mev, mdb_bool* outBool) +{ + nsresult outErr = NS_OK; + mdb_bool isReadOnly = morkBool_kFalse; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + ev->StubMethodOnlyError(); + outErr = ev->AsErr(); + } + if ( outBool ) + *outBool = isReadOnly; + return outErr; +} + +morkEnv* +morkStore::CanUseStore(nsIMdbEnv* mev, mork_bool inMutable, + nsresult* outErr) const +{ + morkEnv* outEnv = 0; + morkEnv* ev = morkEnv::FromMdbEnv(mev); + if ( ev ) + { + if (IsStore()) + outEnv = ev; + else + NonStoreTypeError(ev); + *outErr = ev->AsErr(); + } + MORK_ASSERT(outEnv); + return outEnv; +} + +NS_IMETHODIMP +morkStore::GetIsStore(nsIMdbEnv* mev, mdb_bool* outBool) +{ + MORK_USED_1(mev); + if ( outBool ) + *outBool = morkBool_kTrue; + return NS_OK; +} + +NS_IMETHODIMP +morkStore::GetIsStoreAndDirty(nsIMdbEnv* mev, mdb_bool* outBool) +{ + nsresult outErr = NS_OK; + mdb_bool isStoreAndDirty = morkBool_kFalse; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + ev->StubMethodOnlyError(); + outErr = ev->AsErr(); + } + if ( outBool ) + *outBool = isStoreAndDirty; + return outErr; +} + +NS_IMETHODIMP +morkStore::GetUsagePolicy(nsIMdbEnv* mev, + mdbUsagePolicy* ioUsagePolicy) +{ + MORK_USED_1(ioUsagePolicy); + nsresult outErr = NS_OK; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + ev->StubMethodOnlyError(); + outErr = ev->AsErr(); + } + return outErr; +} + +NS_IMETHODIMP +morkStore::SetUsagePolicy(nsIMdbEnv* mev, + const mdbUsagePolicy* inUsagePolicy) +{ + MORK_USED_1(inUsagePolicy); + nsresult outErr = NS_OK; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + // ev->StubMethodOnlyError(); // okay to do nothing? + outErr = ev->AsErr(); + } + return outErr; +} +// } ----- end attribute methods ----- + +// { ----- begin memory policy methods ----- +NS_IMETHODIMP +morkStore::IdleMemoryPurge( // do memory management already scheduled + nsIMdbEnv* mev, // context + mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed +{ + nsresult outErr = NS_OK; + mdb_size estimatedBytesFreed = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + // ev->StubMethodOnlyError(); // okay to do nothing? + outErr = ev->AsErr(); + } + if ( outEstimatedBytesFreed ) + *outEstimatedBytesFreed = estimatedBytesFreed; + return outErr; +} + +NS_IMETHODIMP +morkStore::SessionMemoryPurge( // request specific footprint decrease + nsIMdbEnv* mev, // context + mdb_size inDesiredBytesFreed, // approximate number of bytes wanted + mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed +{ + MORK_USED_1(inDesiredBytesFreed); + nsresult outErr = NS_OK; + mdb_size estimate = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + // ev->StubMethodOnlyError(); // okay to do nothing? + outErr = ev->AsErr(); + } + if ( outEstimatedBytesFreed ) + *outEstimatedBytesFreed = estimate; + return outErr; +} + +NS_IMETHODIMP +morkStore::PanicMemoryPurge( // desperately free all possible memory + nsIMdbEnv* mev, // context + mdb_size* outEstimatedBytesFreed) // approximate bytes actually freed +{ + nsresult outErr = NS_OK; + mdb_size estimate = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + // ev->StubMethodOnlyError(); // okay to do nothing? + outErr = ev->AsErr(); + } + if ( outEstimatedBytesFreed ) + *outEstimatedBytesFreed = estimate; + return outErr; +} +// } ----- end memory policy methods ----- + +// { ----- begin filepath methods ----- +NS_IMETHODIMP +morkStore::GetPortFilePath( + nsIMdbEnv* mev, // context + mdbYarn* outFilePath, // name of file holding port content + mdbYarn* outFormatVersion) // file format description +{ + nsresult outErr = NS_OK; + if ( outFormatVersion ) + outFormatVersion->mYarn_Fill = 0; + if ( outFilePath ) + outFilePath->mYarn_Fill = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + if ( mStore_File ) + mStore_File->Path(mev, outFilePath); + else + NilStoreFileError(ev); + + outErr = ev->AsErr(); + } + return outErr; +} + +NS_IMETHODIMP +morkStore::GetPortFile( + nsIMdbEnv* mev, // context + nsIMdbFile** acqFile) // acquire file used by port or store +{ + nsresult outErr = NS_OK; + if ( acqFile ) + *acqFile = 0; + + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + + if ( mStore_File ) + { + if ( acqFile ) + { + mStore_File->AddRef(); + if ( ev->Good() ) + *acqFile = mStore_File; + } + } + else + NilStoreFileError(ev); + + outErr = ev->AsErr(); + } + return outErr; +} +// } ----- end filepath methods ----- + +// { ----- begin export methods ----- +NS_IMETHODIMP +morkStore::BestExportFormat( // determine preferred export format + nsIMdbEnv* mev, // context + mdbYarn* outFormatVersion) // file format description +{ + nsresult outErr = NS_OK; + if ( outFormatVersion ) + outFormatVersion->mYarn_Fill = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + ev->StubMethodOnlyError(); + outErr = ev->AsErr(); + } + return outErr; +} + +NS_IMETHODIMP +morkStore::CanExportToFormat( // can export content in given specific format? + nsIMdbEnv* mev, // context + const char* inFormatVersion, // file format description + mdb_bool* outCanExport) // whether ExportSource() might succeed +{ + MORK_USED_1(inFormatVersion); + mdb_bool canExport = morkBool_kFalse; + nsresult outErr = NS_OK; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + ev->StubMethodOnlyError(); + outErr = ev->AsErr(); + } + if ( outCanExport ) + *outCanExport = canExport; + return outErr; +} + +NS_IMETHODIMP +morkStore::ExportToFormat( // export content in given specific format + nsIMdbEnv* mev, // context + // const char* inFilePath, // the file to receive exported content + nsIMdbFile* ioFile, // destination abstract file interface + const char* inFormatVersion, // file format description + nsIMdbThumb** acqThumb) // acquire thumb for incremental export +// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and +// then the export will be finished. +{ + nsresult outErr = NS_OK; + nsIMdbThumb* outThumb = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + if ( ioFile && inFormatVersion && acqThumb ) + { + ev->StubMethodOnlyError(); + } + else + ev->NilPointerError(); + + outErr = ev->AsErr(); + } + if ( acqThumb ) + *acqThumb = outThumb; + return outErr; +} + +// } ----- end export methods ----- + +// { ----- begin token methods ----- +NS_IMETHODIMP +morkStore::TokenToString( // return a string name for an integer token + nsIMdbEnv* mev, // context + mdb_token inToken, // token for inTokenName inside this port + mdbYarn* outTokenName) // the type of table to access +{ + nsresult outErr = NS_OK; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + TokenToString(ev, inToken, outTokenName); + outErr = ev->AsErr(); + } + return outErr; +} + +NS_IMETHODIMP +morkStore::StringToToken( // return an integer token for scope name + nsIMdbEnv* mev, // context + const char* inTokenName, // Latin1 string to tokenize if possible + mdb_token* outToken) // token for inTokenName inside this port + // String token zero is never used and never supported. If the port + // is a mutable store, then StringToToken() to create a new + // association of inTokenName with a new integer token if possible. + // But a readonly port will return zero for an unknown scope name. +{ + nsresult outErr = NS_OK; + mdb_token token = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + token = StringToToken(ev, inTokenName); + outErr = ev->AsErr(); + } + if ( outToken ) + *outToken = token; + return outErr; +} + + +NS_IMETHODIMP +morkStore::QueryToken( // like StringToToken(), but without adding + nsIMdbEnv* mev, // context + const char* inTokenName, // Latin1 string to tokenize if possible + mdb_token* outToken) // token for inTokenName inside this port + // QueryToken() will return a string token if one already exists, + // but unlike StringToToken(), will not assign a new token if not + // already in use. +{ + nsresult outErr = NS_OK; + mdb_token token = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + token = QueryToken(ev, inTokenName); + outErr = ev->AsErr(); + } + if ( outToken ) + *outToken = token; + return outErr; +} + + +// } ----- end token methods ----- + +// { ----- begin row methods ----- +NS_IMETHODIMP +morkStore::HasRow( // contains a row with the specified oid? + nsIMdbEnv* mev, // context + const mdbOid* inOid, // hypothetical row oid + mdb_bool* outHasRow) // whether GetRow() might succeed +{ + nsresult outErr = NS_OK; + mdb_bool hasRow = morkBool_kFalse; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkRow* row = GetRow(ev, inOid); + if ( row ) + hasRow = morkBool_kTrue; + + outErr = ev->AsErr(); + } + if ( outHasRow ) + *outHasRow = hasRow; + return outErr; +} + +NS_IMETHODIMP +morkStore::GetRow( // access one row with specific oid + nsIMdbEnv* mev, // context + const mdbOid* inOid, // hypothetical row oid + nsIMdbRow** acqRow) // acquire specific row (or null) +{ + nsresult outErr = NS_OK; + nsIMdbRow* outRow = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkRow* row = GetRow(ev, inOid); + if ( row && ev->Good() ) + outRow = row->AcquireRowHandle(ev, this); + + outErr = ev->AsErr(); + } + if ( acqRow ) + *acqRow = outRow; + return outErr; +} + +NS_IMETHODIMP +morkStore::GetRowRefCount( // get number of tables that contain a row + nsIMdbEnv* mev, // context + const mdbOid* inOid, // hypothetical row oid + mdb_count* outRefCount) // number of tables containing inRowKey +{ + nsresult outErr = NS_OK; + mdb_count count = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkRow* row = GetRow(ev, inOid); + if ( row && ev->Good() ) + count = row->mRow_GcUses; + + outErr = ev->AsErr(); + } + if ( outRefCount ) + *outRefCount = count; + return outErr; +} + +NS_IMETHODIMP +morkStore::FindRow(nsIMdbEnv* mev, // search for row with matching cell + mdb_scope inRowScope, // row scope for row ids + mdb_column inColumn, // the column to search (and maintain an index) + const mdbYarn* inTargetCellValue, // cell value for which to search + mdbOid* outRowOid, // out row oid on match (or {0,-1} for no match) + nsIMdbRow** acqRow) // acquire matching row (or nil for no match) + // FindRow() searches for one row that has a cell in column inColumn with + // a contained value with the same form (i.e. charset) and is byte-wise + // identical to the blob described by yarn inTargetCellValue. Both content + // and form of the yarn must be an exact match to find a matching row. + // + // (In other words, both a yarn's blob bytes and form are significant. The + // form is not expected to vary in columns used for identity anyway. This + // is intended to make the cost of FindRow() cheaper for MDB implementors, + // since any cell value atomization performed internally must necessarily + // make yarn form significant in order to avoid data loss in atomization.) + // + // FindRow() can lazily create an index on attribute inColumn for all rows + // with that attribute in row space scope inRowScope, so that subsequent + // calls to FindRow() will perform faster. Such an index might or might + // not be persistent (but this seems desirable if it is cheap to do so). + // Note that lazy index creation in readonly DBs is not very feasible. + // + // This FindRow() interface assumes that attribute inColumn is effectively + // an alternative means of unique identification for a row in a rowspace, + // so correct behavior is only guaranteed when no duplicates for this col + // appear in the given set of rows. (If more than one row has the same cell + // value in this column, no more than one will be found; and cutting one of + // two duplicate rows can cause the index to assume no other such row lives + // in the row space, so future calls return nil for negative search results + // even though some duplicate row might still live within the rowspace.) + // + // In other words, the FindRow() implementation is allowed to assume simple + // hash tables mapping unqiue column keys to associated row values will be + // sufficient, where any duplication is not recorded because only one copy + // of a given key need be remembered. Implementors are not required to sort + // all rows by the specified column. +{ + nsresult outErr = NS_OK; + nsIMdbRow* outRow = 0; + mdbOid rowOid; + rowOid.mOid_Scope = 0; + rowOid.mOid_Id = (mdb_id) -1; + + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkRow* row = FindRow(ev, inRowScope, inColumn, inTargetCellValue); + if ( row && ev->Good() ) + { + rowOid = row->mRow_Oid; + if ( acqRow ) + outRow = row->AcquireRowHandle(ev, this); + } + outErr = ev->AsErr(); + } + if ( acqRow ) + *acqRow = outRow; + if ( outRowOid ) + *outRowOid = rowOid; + + return outErr; +} + +// } ----- end row methods ----- + +// { ----- begin table methods ----- +NS_IMETHODIMP +morkStore::HasTable( // supports a table with the specified oid? + nsIMdbEnv* mev, // context + const mdbOid* inOid, // hypothetical table oid + mdb_bool* outHasTable) // whether GetTable() might succeed +{ + nsresult outErr = NS_OK; + mork_bool hasTable = morkBool_kFalse; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkTable* table = GetTable(ev, inOid); + if ( table ) + hasTable = morkBool_kTrue; + + outErr = ev->AsErr(); + } + if ( outHasTable ) + *outHasTable = hasTable; + return outErr; +} + +NS_IMETHODIMP +morkStore::GetTable( // access one table with specific oid + nsIMdbEnv* mev, // context + const mdbOid* inOid, // hypothetical table oid + nsIMdbTable** acqTable) // acquire specific table (or null) +{ + nsresult outErr = NS_OK; + nsIMdbTable* outTable = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkTable* table = GetTable(ev, inOid); + if ( table && ev->Good() ) + outTable = table->AcquireTableHandle(ev); + outErr = ev->AsErr(); + } + if ( acqTable ) + *acqTable = outTable; + return outErr; +} + +NS_IMETHODIMP +morkStore::HasTableKind( // supports a table of the specified type? + nsIMdbEnv* mev, // context + mdb_scope inRowScope, // rid scope for row ids + mdb_kind inTableKind, // the type of table to access + mdb_count* outTableCount, // current number of such tables + mdb_bool* outSupportsTable) // whether GetTableKind() might succeed +{ + nsresult outErr = NS_OK; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + *outSupportsTable = HasTableKind(ev, inRowScope, + inTableKind, outTableCount); + outErr = ev->AsErr(); + } + return outErr; +} + +NS_IMETHODIMP +morkStore::GetTableKind( // access one (random) table of specific type + nsIMdbEnv* mev, // context + mdb_scope inRowScope, // row scope for row ids + mdb_kind inTableKind, // the type of table to access + mdb_count* outTableCount, // current number of such tables + mdb_bool* outMustBeUnique, // whether port can hold only one of these + nsIMdbTable** acqTable) // acquire scoped collection of rows +{ + nsresult outErr = NS_OK; + nsIMdbTable* outTable = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkTable* table = GetTableKind(ev, inRowScope, + inTableKind, outTableCount, outMustBeUnique); + if ( table && ev->Good() ) + outTable = table->AcquireTableHandle(ev); + outErr = ev->AsErr(); + } + if ( acqTable ) + *acqTable = outTable; + return outErr; +} + +NS_IMETHODIMP +morkStore::GetPortTableCursor( // get cursor for all tables of specific type + nsIMdbEnv* mev, // context + mdb_scope inRowScope, // row scope for row ids + mdb_kind inTableKind, // the type of table to access + nsIMdbPortTableCursor** acqCursor) // all such tables in the port +{ + nsresult outErr = NS_OK; + nsIMdbPortTableCursor* outCursor = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkPortTableCursor* cursor = + GetPortTableCursor(ev, inRowScope, + inTableKind); + if ( cursor && ev->Good() ) + outCursor = cursor; + + outErr = ev->AsErr(); + } + if ( acqCursor ) + *acqCursor = outCursor; + return outErr; +} +// } ----- end table methods ----- + +// { ----- begin commit methods ----- + +NS_IMETHODIMP +morkStore::ShouldCompress( // store wastes at least inPercentWaste? + nsIMdbEnv* mev, // context + mdb_percent inPercentWaste, // 0..100 percent file size waste threshold + mdb_percent* outActualWaste, // 0..100 percent of file actually wasted + mdb_bool* outShould) // true when about inPercentWaste% is wasted +{ + mdb_percent actualWaste = 0; + mdb_bool shouldCompress = morkBool_kFalse; + nsresult outErr = NS_OK; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + actualWaste = PercentOfStoreWasted(ev); + if ( inPercentWaste > 100 ) + inPercentWaste = 100; + shouldCompress = ( actualWaste >= inPercentWaste ); + outErr = ev->AsErr(); + } + if ( outActualWaste ) + *outActualWaste = actualWaste; + if ( outShould ) + *outShould = shouldCompress; + return outErr; +} + + +// } ===== end nsIMdbPort methods ===== + +NS_IMETHODIMP +morkStore::NewTable( // make one new table of specific type + nsIMdbEnv* mev, // context + mdb_scope inRowScope, // row scope for row ids + mdb_kind inTableKind, // the type of table to access + mdb_bool inMustBeUnique, // whether store can hold only one of these + const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying + nsIMdbTable** acqTable) // acquire scoped collection of rows +{ + nsresult outErr = NS_OK; + nsIMdbTable* outTable = 0; + morkEnv* ev = this->CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkTable* table = NewTable(ev, inRowScope, + inTableKind, inMustBeUnique, inOptionalMetaRowOid); + if ( table && ev->Good() ) + outTable = table->AcquireTableHandle(ev); + outErr = ev->AsErr(); + } + if ( acqTable ) + *acqTable = outTable; + return outErr; +} + +NS_IMETHODIMP +morkStore::NewTableWithOid( // make one new table of specific type + nsIMdbEnv* mev, // context + const mdbOid* inOid, // caller assigned oid + mdb_kind inTableKind, // the type of table to access + mdb_bool inMustBeUnique, // whether store can hold only one of these + const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying + nsIMdbTable** acqTable) // acquire scoped collection of rows +{ + nsresult outErr = NS_OK; + nsIMdbTable* outTable = 0; + morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkTable* table = OidToTable(ev, inOid, + inOptionalMetaRowOid); + if ( table && ev->Good() ) + { + table->mTable_Kind = inTableKind; + if ( inMustBeUnique ) + table->SetTableUnique(); + outTable = table->AcquireTableHandle(ev); + } + outErr = ev->AsErr(); + } + if ( acqTable ) + *acqTable = outTable; + return outErr; +} +// } ----- end table methods ----- + +// { ----- begin row scope methods ----- +NS_IMETHODIMP +morkStore::RowScopeHasAssignedIds(nsIMdbEnv* mev, + mdb_scope inRowScope, // row scope for row ids + mdb_bool* outCallerAssigned, // nonzero if caller assigned specified + mdb_bool* outStoreAssigned) // nonzero if store db assigned specified +{ + NS_ASSERTION(false, " not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +morkStore::SetCallerAssignedIds(nsIMdbEnv* mev, + mdb_scope inRowScope, // row scope for row ids + mdb_bool* outCallerAssigned, // nonzero if caller assigned specified + mdb_bool* outStoreAssigned) // nonzero if store db assigned specified +{ + NS_ASSERTION(false, " not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +morkStore::SetStoreAssignedIds(nsIMdbEnv* mev, + mdb_scope inRowScope, // row scope for row ids + mdb_bool* outCallerAssigned, // nonzero if caller assigned specified + mdb_bool* outStoreAssigned) // nonzero if store db assigned specified +{ + NS_ASSERTION(false, " not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +} +// } ----- end row scope methods ----- + +// { ----- begin row methods ----- +NS_IMETHODIMP +morkStore::NewRowWithOid(nsIMdbEnv* mev, // new row w/ caller assigned oid + const mdbOid* inOid, // caller assigned oid + nsIMdbRow** acqRow) // create new row +{ + nsresult outErr = NS_OK; + nsIMdbRow* outRow = 0; + morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkRow* row = NewRowWithOid(ev, inOid); + if ( row && ev->Good() ) + outRow = row->AcquireRowHandle(ev, this); + + outErr = ev->AsErr(); + } + if ( acqRow ) + *acqRow = outRow; + return outErr; +} + +NS_IMETHODIMP +morkStore::NewRow(nsIMdbEnv* mev, // new row with db assigned oid + mdb_scope inRowScope, // row scope for row ids + nsIMdbRow** acqRow) // create new row +// Note this row must be added to some table or cell child before the +// store is closed in order to make this row persist across sesssions. +{ + nsresult outErr = NS_OK; + nsIMdbRow* outRow = 0; + morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + morkRow* row = NewRow(ev, inRowScope); + if ( row && ev->Good() ) + outRow = row->AcquireRowHandle(ev, this); + + outErr = ev->AsErr(); + } + if ( acqRow ) + *acqRow = outRow; + return outErr; +} +// } ----- end row methods ----- + +// { ----- begin inport/export methods ----- +NS_IMETHODIMP +morkStore::ImportContent( // import content from port + nsIMdbEnv* mev, // context + mdb_scope inRowScope, // scope for rows (or zero for all?) + nsIMdbPort* ioPort, // the port with content to add to store + nsIMdbThumb** acqThumb) // acquire thumb for incremental import +// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and +// then the import will be finished. +{ + NS_ASSERTION(false, " not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +morkStore::ImportFile( // import content from port + nsIMdbEnv* mev, // context + nsIMdbFile* ioFile, // the file with content to add to store + nsIMdbThumb** acqThumb) // acquire thumb for incremental import +// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and +// then the import will be finished. +{ + NS_ASSERTION(false, " not implemented"); + return NS_ERROR_NOT_IMPLEMENTED; +} +// } ----- end inport/export methods ----- + +// { ----- begin hinting methods ----- +NS_IMETHODIMP +morkStore::ShareAtomColumnsHint( // advise re shared col content atomizing + nsIMdbEnv* mev, // context + mdb_scope inScopeHint, // zero, or suggested shared namespace + const mdbColumnSet* inColumnSet) // cols desired tokenized together +{ + MORK_USED_2(inColumnSet,inScopeHint); + nsresult outErr = NS_OK; + morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + // ev->StubMethodOnlyError(); // okay to do nothing for a hint method + outErr = ev->AsErr(); + } + return outErr; +} + +NS_IMETHODIMP +morkStore::AvoidAtomColumnsHint( // advise col w/ poor atomizing prospects + nsIMdbEnv* mev, // context + const mdbColumnSet* inColumnSet) // cols with poor atomizing prospects +{ + MORK_USED_1(inColumnSet); + nsresult outErr = NS_OK; + morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + // ev->StubMethodOnlyError(); // okay to do nothing for a hint method + outErr = ev->AsErr(); + } + return outErr; +} +// } ----- end hinting methods ----- + +// { ----- begin commit methods ----- +NS_IMETHODIMP +morkStore::LargeCommit( // save important changes if at all possible + nsIMdbEnv* mev, // context + nsIMdbThumb** acqThumb) // acquire thumb for incremental commit +// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and +// then the commit will be finished. Note the store is effectively write +// locked until commit is finished or canceled through the thumb instance. +// Until the commit is done, the store will report it has readonly status. +{ + nsresult outErr = NS_OK; + nsIMdbThumb* outThumb = 0; + morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + + morkThumb* thumb = 0; + // morkFile* file = store->mStore_File; + if ( DoPreferLargeOverCompressCommit(ev) ) + { + thumb = morkThumb::Make_LargeCommit(ev, mPort_Heap, this); + } + else + { + mork_bool doCollect = morkBool_kFalse; + thumb = morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect); + } + + if ( thumb ) + { + outThumb = thumb; + thumb->AddRef(); + } + + outErr = ev->AsErr(); + } + if ( acqThumb ) + *acqThumb = outThumb; + return outErr; +} + +NS_IMETHODIMP +morkStore::SessionCommit( // save all changes if large commits delayed + nsIMdbEnv* mev, // context + nsIMdbThumb** acqThumb) // acquire thumb for incremental commit +// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and +// then the commit will be finished. Note the store is effectively write +// locked until commit is finished or canceled through the thumb instance. +// Until the commit is done, the store will report it has readonly status. +{ + nsresult outErr = NS_OK; + nsIMdbThumb* outThumb = 0; + morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + + morkThumb* thumb = 0; + if ( DoPreferLargeOverCompressCommit(ev) ) + { + thumb = morkThumb::Make_LargeCommit(ev, mPort_Heap, this); + } + else + { + mork_bool doCollect = morkBool_kFalse; + thumb = morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect); + } + + if ( thumb ) + { + outThumb = thumb; + thumb->AddRef(); + } + outErr = ev->AsErr(); + } + if ( acqThumb ) + *acqThumb = outThumb; + return outErr; +} + +NS_IMETHODIMP +morkStore::CompressCommit( // commit and make db smaller if possible + nsIMdbEnv* mev, // context + nsIMdbThumb** acqThumb) // acquire thumb for incremental commit +// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and +// then the commit will be finished. Note the store is effectively write +// locked until commit is finished or canceled through the thumb instance. +// Until the commit is done, the store will report it has readonly status. +{ + nsresult outErr = NS_OK; + nsIMdbThumb* outThumb = 0; + morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr); + if ( ev ) + { + mork_bool doCollect = morkBool_kFalse; + morkThumb* thumb = morkThumb::Make_CompressCommit(ev, mPort_Heap, this, doCollect); + if ( thumb ) + { + outThumb = thumb; + thumb->AddRef(); + mStore_CanWriteIncremental = morkBool_kTrue; + } + + outErr = ev->AsErr(); + } + if ( acqThumb ) + *acqThumb = outThumb; + return outErr; +} + +// } ----- end commit methods ----- + +// } ===== end nsIMdbStore methods ===== + + +//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789 + |