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 _MORKMAP_
# include "morkMap.h"
#endif
#ifndef _MORKSPACE_
# include "morkSpace.h"
#endif
#ifndef _MORKNODEMAP_
# include "morkNodeMap.h"
#endif
#ifndef _MORKROWMAP_
# include "morkRowMap.h"
#endif
#ifndef _MORKENV_
# include "morkEnv.h"
#endif
#ifndef _MORKROWSPACE_
# include "morkRowSpace.h"
#endif
#ifndef _MORKPOOL_
# include "morkPool.h"
#endif
#ifndef _MORKSTORE_
# include "morkStore.h"
#endif
#ifndef _MORKTABLE_
# include "morkTable.h"
#endif
#ifndef _MORKROW_
# include "morkRow.h"
#endif
#ifndef _MORKATOMMAP_
# include "morkAtomMap.h"
#endif
#ifndef _MORKROWOBJECT_
# include "morkRowObject.h"
#endif
// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
// ````` ````` ````` ````` `````
// { ===== begin morkNode interface =====
/*public virtual*/ void morkRowSpace::CloseMorkNode(
morkEnv* ev) // CloseRowSpace() only if open
{
if (this->IsOpenNode()) {
this->MarkClosing();
this->CloseRowSpace(ev);
this->MarkShut();
}
}
/*public virtual*/
morkRowSpace::~morkRowSpace() // assert CloseRowSpace() executed earlier
{
MORK_ASSERT(this->IsShutNode());
}
/*public non-poly*/
morkRowSpace::morkRowSpace(morkEnv* ev, const morkUsage& inUsage,
mork_scope inScope, morkStore* ioStore,
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
: morkSpace(ev, inUsage, inScope, ioStore, ioHeap, ioSlotHeap),
mRowSpace_SlotHeap(ioSlotHeap),
mRowSpace_Rows(ev, morkUsage::kMember, (nsIMdbHeap*)0, ioSlotHeap,
morkRowSpace_kStartRowMapSlotCount),
mRowSpace_Tables(ev, morkUsage::kMember, (nsIMdbHeap*)0, ioSlotHeap),
mRowSpace_NextTableId(1),
mRowSpace_NextRowId(1)
,
mRowSpace_IndexCount(0) {
morkAtomRowMap** cache = mRowSpace_IndexCache;
morkAtomRowMap** cacheEnd = cache + morkRowSpace_kPrimeCacheSize;
while (cache < cacheEnd)
*cache++ = 0; // put nil into every slot of cache table
if (ev->Good()) {
if (ioSlotHeap) {
mNode_Derived = morkDerived_kRowSpace;
// the morkSpace base constructor handles any dirty propagation
} else
ev->NilPointerError();
}
}
/*public non-poly*/ void morkRowSpace::CloseRowSpace(
morkEnv* ev) // called by CloseMorkNode();
{
if (this->IsNode()) {
morkAtomRowMap** cache = mRowSpace_IndexCache;
morkAtomRowMap** cacheEnd = cache + morkRowSpace_kPrimeCacheSize;
--cache; // prepare for preincrement:
while (++cache < cacheEnd) {
if (*cache) morkAtomRowMap::SlotStrongAtomRowMap(0, ev, cache);
}
mRowSpace_Tables.CloseMorkNode(ev);
morkStore* store = mSpace_Store;
if (store) this->CutAllRows(ev, &store->mStore_Pool);
mRowSpace_Rows.CloseMorkNode(ev);
this->CloseSpace(ev);
} else
this->NonNodeError(ev);
}
// } ===== end morkNode methods =====
// ````` ````` ````` ````` `````
/*static*/ void morkRowSpace::NonRowSpaceTypeError(morkEnv* ev) {
ev->NewError("non morkRowSpace");
}
/*static*/ void morkRowSpace::ZeroKindError(morkEnv* ev) {
ev->NewError("zero table kind");
}
/*static*/ void morkRowSpace::ZeroScopeError(morkEnv* ev) {
ev->NewError("zero row scope");
}
/*static*/ void morkRowSpace::ZeroTidError(morkEnv* ev) {
ev->NewError("zero table ID");
}
/*static*/ void morkRowSpace::MinusOneRidError(morkEnv* ev) {
ev->NewError("row ID is -1");
}
///*static*/ void
// morkRowSpace::ExpectAutoIdOnlyError(morkEnv* ev)
//{
// ev->NewError("zero row ID");
//}
///*static*/ void
// morkRowSpace::ExpectAutoIdNeverError(morkEnv* ev)
//{
//}
mork_num morkRowSpace::CutAllRows(morkEnv* ev, morkPool* ioPool) {
if (this->IsRowSpaceClean()) this->MaybeDirtyStoreAndSpace();
#ifdef MORK_ENABLE_ZONE_ARENAS
MORK_USED_2(ev, ioPool);
return 0;
#else /*MORK_ENABLE_ZONE_ARENAS*/
mork_num outSlots = mRowSpace_Rows.MapFill();
morkZone* zone = &mSpace_Store->mStore_Zone;
morkRow* r = 0; // old key row in the map
mork_change* c = 0;
# ifdef MORK_ENABLE_PROBE_MAPS
morkRowProbeMapIter i(ev, &mRowSpace_Rows);
# else /*MORK_ENABLE_PROBE_MAPS*/
morkRowMapIter i(ev, &mRowSpace_Rows);
# endif /*MORK_ENABLE_PROBE_MAPS*/
for (c = i.FirstRow(ev, &r); c && ev->Good(); c = i.NextRow(ev, &r)) {
if (r) {
if (r->IsRow()) {
if (r->mRow_Object) {
morkRowObject::SlotWeakRowObject((morkRowObject*)0, ev,
&r->mRow_Object);
}
ioPool->ZapRow(ev, r, zone);
} else
r->NonRowTypeWarning(ev);
} else
ev->NilPointerError();
# ifdef MORK_ENABLE_PROBE_MAPS
// cut nothing from the map
# else /*MORK_ENABLE_PROBE_MAPS*/
i.CutHereRow(ev, /*key*/ (morkRow**)0);
# endif /*MORK_ENABLE_PROBE_MAPS*/
}
return outSlots;
#endif /*MORK_ENABLE_ZONE_ARENAS*/
}
morkTable* morkRowSpace::FindTableByKind(morkEnv* ev, mork_kind inTableKind) {
if (inTableKind) {
#ifdef MORK_BEAD_OVER_NODE_MAPS
morkTableMapIter i(ev, &mRowSpace_Tables);
morkTable* table = i.FirstTable(ev);
for (; table && ev->Good(); table = i.NextTable(ev))
#else /*MORK_BEAD_OVER_NODE_MAPS*/
mork_tid* key = 0; // nil pointer to suppress key access
morkTable* table = 0; // old table in the map
mork_change* c = 0;
morkTableMapIter i(ev, &mRowSpace_Tables);
for (c = i.FirstTable(ev, key, &table); c && ev->Good();
c = i.NextTable(ev, key, &table))
#endif /*MORK_BEAD_OVER_NODE_MAPS*/
{
if (table->mTable_Kind == inTableKind) return table;
}
} else
this->ZeroKindError(ev);
return (morkTable*)0;
}
morkTable* morkRowSpace::NewTableWithTid(
morkEnv* ev, mork_tid inTid, mork_kind inTableKind,
const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
{
morkTable* outTable = 0;
morkStore* store = mSpace_Store;
if (inTableKind && store) {
mdb_bool mustBeUnique = morkBool_kFalse;
nsIMdbHeap* heap = store->mPort_Heap;
morkTable* table = new (*heap, ev)
morkTable(ev, morkUsage::kHeap, heap, store, heap, this,
inOptionalMetaRowOid, inTid, inTableKind, mustBeUnique);
if (table) {
if (mRowSpace_Tables.AddTable(ev, table)) {
outTable = table;
if (mRowSpace_NextTableId <= inTid) mRowSpace_NextTableId = inTid + 1;
}
if (this->IsRowSpaceClean() && store->mStore_CanDirty)
this->MaybeDirtyStoreAndSpace(); // morkTable does already
}
} else if (store)
this->ZeroKindError(ev);
else
this->NilSpaceStoreError(ev);
return outTable;
}
morkTable* morkRowSpace::NewTable(
morkEnv* ev, mork_kind inTableKind, mdb_bool inMustBeUnique,
const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
{
morkTable* outTable = 0;
morkStore* store = mSpace_Store;
if (inTableKind && store) {
if (inMustBeUnique) // need to look for existing table first?
outTable = this->FindTableByKind(ev, inTableKind);
if (!outTable && ev->Good()) {
mork_tid id = this->MakeNewTableId(ev);
if (id) {
nsIMdbHeap* heap = mSpace_Store->mPort_Heap;
morkTable* table = new (*heap, ev)
morkTable(ev, morkUsage::kHeap, heap, mSpace_Store, heap, this,
inOptionalMetaRowOid, id, inTableKind, inMustBeUnique);
if (table) {
if (mRowSpace_Tables.AddTable(ev, table))
outTable = table;
else
table->Release();
if (this->IsRowSpaceClean() && store->mStore_CanDirty)
this->MaybeDirtyStoreAndSpace(); // morkTable does already
}
}
}
} else if (store)
this->ZeroKindError(ev);
else
this->NilSpaceStoreError(ev);
return outTable;
}
mork_tid morkRowSpace::MakeNewTableId(morkEnv* ev) {
mork_tid outTid = 0;
mork_tid id = mRowSpace_NextTableId;
mork_num count = 9; // try up to eight times
while (!outTid && --count) // still trying to find an unused table ID?
{
if (!mRowSpace_Tables.GetTable(ev, id))
outTid = id;
else {
MORK_ASSERT(morkBool_kFalse); // alert developer about ID problems
++id;
}
}
mRowSpace_NextTableId = id + 1;
return outTid;
}
#define MAX_AUTO_ID (morkRow_kMinusOneRid - 2)
mork_rid morkRowSpace::MakeNewRowId(morkEnv* ev) {
mork_rid outRid = 0;
mork_rid id = mRowSpace_NextRowId;
mork_num count = 9; // try up to eight times
mdbOid oid;
oid.mOid_Scope = this->SpaceScope();
// still trying to find an unused row ID?
while (!outRid && --count && id <= MAX_AUTO_ID) {
oid.mOid_Id = id;
if (!mRowSpace_Rows.GetOid(ev, &oid))
outRid = id;
else {
MORK_ASSERT(morkBool_kFalse); // alert developer about ID problems
++id;
}
}
if (id < MAX_AUTO_ID) mRowSpace_NextRowId = id + 1;
return outRid;
}
morkAtomRowMap* morkRowSpace::make_index(morkEnv* ev, mork_column inCol) {
morkAtomRowMap* outMap = 0;
nsIMdbHeap* heap = mRowSpace_SlotHeap;
if (heap) // have expected heap for allocations?
{
morkAtomRowMap* map =
new (*heap, ev) morkAtomRowMap(ev, morkUsage::kHeap, heap, heap, inCol);
if (map) // able to create new map index?
{
if (ev->Good()) // no errors during construction?
{
#ifdef MORK_ENABLE_PROBE_MAPS
morkRowProbeMapIter i(ev, &mRowSpace_Rows);
#else /*MORK_ENABLE_PROBE_MAPS*/
morkRowMapIter i(ev, &mRowSpace_Rows);
#endif /*MORK_ENABLE_PROBE_MAPS*/
mork_change* c = 0;
morkRow* row = 0;
mork_aid aidKey = 0;
for (c = i.FirstRow(ev, &row); c && ev->Good();
c = i.NextRow(ev, &row)) // another row in space?
{
aidKey = row->GetCellAtomAid(ev, inCol);
if (aidKey) // row has indexed attribute?
map->AddAid(ev, aidKey, row); // include in map
}
}
if (ev->Good()) // no errors constructing index?
outMap = map; // return from function
else
map->CutStrongRef(ev); // discard map on error
}
} else
ev->NilPointerError();
return outMap;
}
morkAtomRowMap* morkRowSpace::ForceMap(morkEnv* ev, mork_column inCol) {
morkAtomRowMap* outMap = this->FindMap(ev, inCol);
if (!outMap && ev->Good()) // no such existing index?
{
if (mRowSpace_IndexCount < morkRowSpace_kMaxIndexCount) {
morkAtomRowMap* map = this->make_index(ev, inCol);
if (map) // created a new index for col?
{
mork_count wrap = 0; // count times wrap-around occurs
morkAtomRowMap** slot = mRowSpace_IndexCache; // table
morkAtomRowMap** end = slot + morkRowSpace_kPrimeCacheSize;
slot += (inCol % morkRowSpace_kPrimeCacheSize); // hash
while (*slot) // empty slot not yet found?
{
if (++slot >= end) // wrap around?
{
slot = mRowSpace_IndexCache; // back to table start
if (++wrap > 1) // wrapped more than once?
{
ev->NewError("no free cache slots"); // disaster
break; // end while loop
}
}
}
if (ev->Good()) // everything went just fine?
{
++mRowSpace_IndexCount; // note another new map
*slot = map; // install map in the hash table
outMap = map; // return the new map from function
} else
map->CutStrongRef(ev); // discard map on error
}
} else
ev->NewError("too many indexes"); // why so many indexes?
}
return outMap;
}
morkAtomRowMap* morkRowSpace::FindMap(morkEnv* ev, mork_column inCol) {
if (mRowSpace_IndexCount && ev->Good()) {
mork_count wrap = 0; // count times wrap-around occurs
morkAtomRowMap** slot = mRowSpace_IndexCache; // table
morkAtomRowMap** end = slot + morkRowSpace_kPrimeCacheSize;
slot += (inCol % morkRowSpace_kPrimeCacheSize); // hash
morkAtomRowMap* map = *slot;
while (map) // another used slot to examine?
{
if (inCol == map->mAtomRowMap_IndexColumn) // found col?
return map;
if (++slot >= end) // wrap around?
{
slot = mRowSpace_IndexCache;
if (++wrap > 1) // wrapped more than once?
return (morkAtomRowMap*)0; // stop searching
}
map = *slot;
}
}
return (morkAtomRowMap*)0;
}
morkRow* morkRowSpace::FindRow(morkEnv* ev, mork_column inCol,
const mdbYarn* inYarn) {
morkRow* outRow = 0;
// if yarn hasn't been atomized, there can't be a corresponding row,
// so pass in false to not create the row - should help history bloat
morkAtom* atom = mSpace_Store->YarnToAtom(ev, inYarn, false);
if (atom) // have or created an atom corresponding to input yarn?
{
mork_aid atomAid = atom->GetBookAtomAid();
if (atomAid) // atom has an identity for use in hash table?
{
morkAtomRowMap* map = this->ForceMap(ev, inCol);
if (map) // able to find or create index for col?
{
outRow = map->GetAid(ev, atomAid); // search for row
}
}
}
return outRow;
}
morkRow* morkRowSpace::NewRowWithOid(morkEnv* ev, const mdbOid* inOid) {
morkRow* outRow = mRowSpace_Rows.GetOid(ev, inOid);
MORK_ASSERT(outRow == 0);
if (!outRow && ev->Good()) {
morkStore* store = mSpace_Store;
if (store) {
morkPool* pool = this->GetSpaceStorePool();
morkRow* row = pool->NewRow(ev, &store->mStore_Zone);
if (row) {
row->InitRow(ev, inOid, this, /*length*/ 0, pool);
if (ev->Good() && mRowSpace_Rows.AddRow(ev, row)) {
outRow = row;
mork_rid rid = inOid->mOid_Id;
if (mRowSpace_NextRowId <= rid) mRowSpace_NextRowId = rid + 1;
} else
pool->ZapRow(ev, row, &store->mStore_Zone);
if (this->IsRowSpaceClean() && store->mStore_CanDirty)
this->MaybeDirtyStoreAndSpace(); // InitRow() does already
}
} else
this->NilSpaceStoreError(ev);
}
return outRow;
}
morkRow* morkRowSpace::NewRow(morkEnv* ev) {
morkRow* outRow = 0;
if (ev->Good()) {
mork_rid id = this->MakeNewRowId(ev);
if (id) {
morkStore* store = mSpace_Store;
if (store) {
mdbOid oid;
oid.mOid_Scope = this->SpaceScope();
oid.mOid_Id = id;
morkPool* pool = this->GetSpaceStorePool();
morkRow* row = pool->NewRow(ev, &store->mStore_Zone);
if (row) {
row->InitRow(ev, &oid, this, /*length*/ 0, pool);
if (ev->Good() && mRowSpace_Rows.AddRow(ev, row))
outRow = row;
else
pool->ZapRow(ev, row, &store->mStore_Zone);
if (this->IsRowSpaceClean() && store->mStore_CanDirty)
this->MaybeDirtyStoreAndSpace(); // InitRow() does already
}
} else
this->NilSpaceStoreError(ev);
}
}
return outRow;
}
// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
morkRowSpaceMap::~morkRowSpaceMap() {}
morkRowSpaceMap::morkRowSpaceMap(morkEnv* ev, const morkUsage& inUsage,
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
: morkNodeMap(ev, inUsage, ioHeap, ioSlotHeap) {
if (ev->Good()) mNode_Derived = morkDerived_kRowSpaceMap;
}
// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789