/* -*- 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 //3456789_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(); mork_num outSlots = mRowSpace_Rows.MapFill(); #ifdef MORK_ENABLE_ZONE_ARENAS MORK_USED_2(ev, ioPool); return 0; #else /*MORK_ENABLE_ZONE_ARENAS*/ 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*/ } #endif /*MORK_ENABLE_ZONE_ARENAS*/ return outSlots; } 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; } //3456789_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; } //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789