2331 lines
63 KiB
C++
2331 lines
63 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1999
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#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 )
|
|
{
|
|
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);
|
|
}
|
|
else
|
|
ev->NilPointerError();
|
|
}
|
|
|
|
/*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_INHERITED1(morkStore, morkObject, nsIMdbStore)
|
|
|
|
/*public non-poly*/ void
|
|
morkStore::CloseStore(morkEnv* ev) // called by CloseMorkNode();
|
|
{
|
|
if ( this )
|
|
{
|
|
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);
|
|
}
|
|
else
|
|
ev->NilPointerError();
|
|
}
|
|
|
|
// } ===== 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 it's 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 it's 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 ( inAtom->AliasYarn(&yarn) )
|
|
outAtom = this->YarnToAtom(ev, &yarn, PR_TRUE /* create */);
|
|
}
|
|
return outAtom;
|
|
}
|
|
|
|
morkAtom*
|
|
morkStore::YarnToAtom(morkEnv* ev, const mdbYarn* inYarn, PRBool createIfMissing /* = PR_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);
|
|
return morkNode::AddWeakRef(ev);
|
|
}
|
|
NS_IMETHODIMP
|
|
morkStore::AddStrongRef(nsIMdbEnv* mev)
|
|
{
|
|
return AddRef();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
morkStore::CutWeakRef(nsIMdbEnv* mev)
|
|
{
|
|
morkEnv *ev = morkEnv::FromMdbEnv(mev);
|
|
return morkNode::CutWeakRef(ev);
|
|
}
|
|
NS_IMETHODIMP
|
|
morkStore::CutStrongRef(nsIMdbEnv* mev)
|
|
{
|
|
return 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)
|
|
{
|
|
mdb_err outErr = 0;
|
|
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, mdb_err* 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 0;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
morkStore::GetIsStoreAndDirty(nsIMdbEnv* mev, mdb_bool* outBool)
|
|
{
|
|
mdb_err outErr = 0;
|
|
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);
|
|
mdb_err outErr = 0;
|
|
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);
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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);
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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;
|
|
mdb_err outErr = 0;
|
|
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.
|
|
{
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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.
|
|
{
|
|
mdb_err outErr = 0;
|
|
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.
|
|
{
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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)
|
|
{
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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.
|
|
{
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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)
|
|
{
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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;
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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(PR_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(PR_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(PR_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
|
|
{
|
|
mdb_err outErr = 0;
|
|
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.
|
|
{
|
|
mdb_err outErr = 0;
|
|
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(PR_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(PR_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);
|
|
mdb_err outErr = 0;
|
|
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);
|
|
mdb_err outErr = 0;
|
|
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::SmallCommit( // save minor changes if convenient and uncostly
|
|
nsIMdbEnv* mev) // context
|
|
{
|
|
mdb_err outErr = 0;
|
|
morkEnv* ev = CanUseStore(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
|
if ( ev )
|
|
{
|
|
// ev->StubMethodOnlyError(); // it's okay to do nothing for small commit
|
|
outErr = ev->AsErr();
|
|
}
|
|
return outErr;
|
|
}
|
|
|
|
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 = 0;
|
|
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
|
|
|