Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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"
// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
// ````` ````` ````` ````` `````
// { ===== begin morkNode interface =====
// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
// 456789_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
{
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
{
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 = 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);
}
morkAtom::GetYarn(atom, outYarn);
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);
morkAtom::GetYarn(atom, outTokenName);
} 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 unique 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 sessions.
{
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 import/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 import/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 =====
// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789