add these. not part of the build yet.

This commit is contained in:
davidmc%netscape.com 1999-09-22 05:06:37 +00:00
Родитель 49af0dba87
Коммит 3e4dfe74cd
6 изменённых файлов: 3227 добавлений и 0 удалений

443
db/mork/src/morkBead.cpp Normal file
Просмотреть файл

@ -0,0 +1,443 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MDB_
#include "mdb.h"
#endif
#ifndef _MORK_
#include "mork.h"
#endif
#ifndef _MORKNODE_
#include "morkNode.h"
#endif
#ifndef _MORKENV_
#include "morkEnv.h"
#endif
#ifndef _MORKBEAD_
#include "morkBead.h"
#endif
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
// ````` ````` ````` ````` `````
// { ===== begin morkNode interface =====
/*public virtual*/ void
morkBead::CloseMorkNode(morkEnv* ev) // CloseBead() only if open
{
if ( this->IsOpenNode() )
{
this->MarkClosing();
this->CloseBead(ev);
this->MarkShut();
}
}
/*public virtual*/
morkBead::~morkBead() // assert CloseBead() executed earlier
{
MORK_ASSERT(mBead_Color==0 || mNode_Usage == morkUsage_kStack );
}
/*public non-poly*/
morkBead::morkBead(mork_color inBeadColor)
: morkNode( morkUsage_kStack )
, mBead_Color( inBeadColor )
{
}
/*public non-poly*/
morkBead::morkBead(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
mork_color inBeadColor)
: morkNode( inUsage, ioHeap )
, mBead_Color( inBeadColor )
{
}
/*public non-poly*/
morkBead::morkBead(morkEnv* ev,
const morkUsage& inUsage, nsIMdbHeap* ioHeap, mork_color inBeadColor)
: morkNode(ev, inUsage, ioHeap)
, mBead_Color( inBeadColor )
{
if ( ev->Good() )
{
if ( ev->Good() )
mNode_Derived = morkDerived_kBead;
}
}
/*public non-poly*/ void
morkBead::CloseBead(morkEnv* ev) // called by CloseMorkNode();
{
if ( this )
{
if ( this->IsNode() )
{
if ( !this->IsShutNode() )
{
mBead_Color = 0;
this->MarkShut();
}
}
else
this->NonNodeError(ev);
}
else
ev->NilPointerError();
}
// } ===== end morkNode methods =====
// ````` ````` ````` ````` `````
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
// ````` ````` ````` ````` `````
// { ===== begin morkNode interface =====
/*public virtual*/ void
morkBeadMap::CloseMorkNode(morkEnv* ev) // CloseBeadMap() only if open
{
if ( this->IsOpenNode() )
{
this->MarkClosing();
this->CloseBeadMap(ev);
this->MarkShut();
}
}
/*public virtual*/
morkBeadMap::~morkBeadMap() // assert CloseBeadMap() executed earlier
{
MORK_ASSERT(this->IsShutNode());
}
/*public non-poly*/
morkBeadMap::morkBeadMap(morkEnv* ev,
const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
: morkMap(ev, inUsage, ioHeap, sizeof(morkBead*), /*inValSize*/ 0,
/*slotCount*/ 11, ioSlotHeap, /*holdChanges*/ morkBool_kFalse)
{
if ( ev->Good() )
mNode_Derived = morkDerived_kBeadMap;
}
/*public non-poly*/ void
morkBeadMap::CloseBeadMap(morkEnv* ev) // called by CloseMorkNode();
{
if ( this )
{
if ( this->IsNode() )
{
this->CutAllBeads(ev);
this->CloseMap(ev);
this->MarkShut();
}
else
this->NonNodeError(ev);
}
else
ev->NilPointerError();
}
// } ===== end morkNode methods =====
// ````` ````` ````` ````` `````
mork_bool
morkBeadMap::AddBead(morkEnv* ev, morkBead* ioBead)
// the AddBead() boolean return equals ev->Good().
{
if ( ioBead && ev->Good() )
{
morkBead* oldBead = 0; // old key in the map
mork_bool put = this->Put(ev, &ioBead, /*val*/ (void*) 0,
/*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
if ( put ) // replaced an existing key?
{
if ( oldBead && oldBead != ioBead ) // need to release old node?
oldBead->CutStrongRef(ev);
}
}
else if ( !ioBead )
ev->NilPointerError();
return ev->Good();
}
mork_bool
morkBeadMap::CutBead(morkEnv* ev, mork_color inColor)
{
morkBead* oldBead = 0; // old key in the map
morkBead bead(inColor);
morkBead* key = &bead;
mork_bool outCutNode = this->Cut(ev, &key,
/*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
if ( oldBead )
oldBead->CutStrongRef(ev);
bead.CloseBead(ev);
return outCutNode;
}
morkBead*
morkBeadMap::GetBead(morkEnv* ev, mork_color inColor)
// Note the returned bead does NOT have an increase in refcount for this.
{
morkBead* oldBead = 0; // old key in the map
morkBead bead(inColor);
morkBead* key = &bead;
this->Get(ev, &key, /*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
bead.CloseBead(ev);
return oldBead;
}
mork_num
morkBeadMap::CutAllBeads(morkEnv* ev)
// CutAllBeads() releases all the referenced beads.
{
mork_num outSlots = mMap_Slots;
morkBeadMapIter i(ev, this);
morkBead* b = i.FirstBead(ev);
while ( b )
{
b->CutStrongRef(ev);
i.CutHereBead(ev);
b = i.NextBead(ev);
}
return outSlots;
}
// { ===== begin morkMap poly interface =====
/*virtual*/ mork_bool
morkBeadMap::Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const
{
MORK_USED_1(ev);
return (*(const morkBead**) inKeyA)->BeadEqual(
*(const morkBead**) inKeyB);
}
/*virtual*/ mork_u4
morkBeadMap::Hash(morkEnv* ev, const void* inKey) const
{
MORK_USED_1(ev);
return (*(const morkBead**) inKey)->BeadHash();
}
// } ===== end morkMap poly interface =====
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
morkBead* morkBeadMapIter::FirstBead(morkEnv* ev)
{
morkBead* bead = 0;
this->First(ev, &bead, /*val*/ (void*) 0);
return bead;
}
morkBead* morkBeadMapIter::NextBead(morkEnv* ev)
{
morkBead* bead = 0;
this->Next(ev, &bead, /*val*/ (void*) 0);
return bead;
}
morkBead* morkBeadMapIter::HereBead(morkEnv* ev)
{
morkBead* bead = 0;
this->Here(ev, &bead, /*val*/ (void*) 0);
return bead;
}
void morkBeadMapIter::CutHereBead(morkEnv* ev)
{
this->CutHere(ev, /*key*/ (void*) 0, /*val*/ (void*) 0);
}
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
// ````` ````` ````` ````` `````
// { ===== begin morkNode interface =====
/*public virtual*/ void
morkBeadProbeMap::CloseMorkNode(morkEnv* ev) // CloseBeadProbeMap() if open
{
if ( this->IsOpenNode() )
{
this->MarkClosing();
this->CloseBeadProbeMap(ev);
this->MarkShut();
}
}
/*public virtual*/
morkBeadProbeMap::~morkBeadProbeMap() // assert CloseBeadProbeMap() earlier
{
MORK_ASSERT(this->IsShutNode());
}
/*public non-poly*/
morkBeadProbeMap::morkBeadProbeMap(morkEnv* ev, const morkUsage& inUsage,
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
: morkProbeMap(ev, inUsage, ioHeap,
/*inKeySize*/ sizeof(morkBead*), /*inValSize*/ 0,
ioSlotHeap, /*startSlotCount*/ 11,
/*inZeroIsClearKey*/ morkBool_kTrue)
{
if ( ev->Good() )
mNode_Derived = morkDerived_kBeadProbeMap;
}
/*public non-poly*/ void
morkBeadProbeMap::CloseBeadProbeMap(morkEnv* ev) // called by CloseMorkNode();
{
if ( this )
{
if ( this->IsNode() )
{
this->CutAllBeads(ev);
this->CloseProbeMap(ev);
this->MarkShut();
}
else
this->NonNodeError(ev);
}
else
ev->NilPointerError();
}
// } ===== end morkNode methods =====
// ````` ````` ````` ````` `````
/*virtual*/ mork_test // hit(a,b) implies hash(a) == hash(b)
morkBeadProbeMap::MapTest(morkEnv* ev, const void* inMapKey,
const void* inAppKey) const
{
MORK_USED_1(ev);
const morkBead* key = *(const morkBead**) inMapKey;
if ( key )
{
mork_bool hit = key->BeadEqual(*(const morkBead**) inAppKey);
return ( hit ) ? morkTest_kHit : morkTest_kMiss;
}
else
return morkTest_kVoid;
}
/*virtual*/ mork_u4 // hit(a,b) implies hash(a) == hash(b)
morkBeadProbeMap::MapHash(morkEnv* ev, const void* inAppKey) const
{
const morkBead* key = *(const morkBead**) inAppKey;
if ( key )
return key->BeadHash();
else
{
ev->NilPointerWarning();
return 0;
}
}
/*virtual*/ mork_u4
morkBeadProbeMap::ProbeMapHashMapKey(morkEnv* ev,
const void* inMapKey) const
{
const morkBead* key = *(const morkBead**) inMapKey;
if ( key )
return key->BeadHash();
else
{
ev->NilPointerWarning();
return 0;
}
}
mork_bool
morkBeadProbeMap::AddBead(morkEnv* ev, morkBead* ioBead)
{
if ( ioBead && ev->Good() )
{
morkBead* bead = 0; // old key in the map
mork_bool put = this->MapAtPut(ev, &ioBead, /*val*/ (void*) 0,
/*key*/ &bead, /*val*/ (void*) 0);
if ( put ) // replaced an existing key?
{
if ( bead && bead != ioBead ) // need to release old node?
bead->CutStrongRef(ev);
}
}
else if ( !ioBead )
ev->NilPointerError();
return ev->Good();
}
morkBead*
morkBeadProbeMap::GetBead(morkEnv* ev, mork_color inColor)
{
morkBead* oldBead = 0; // old key in the map
morkBead bead(inColor);
morkBead* key = &bead;
this->MapAt(ev, &key, &oldBead, /*val*/ (void*) 0);
bead.CloseBead(ev);
return oldBead;
}
mork_num
morkBeadProbeMap::CutAllBeads(morkEnv* ev)
// CutAllBeads() releases all the referenced bead values.
{
mork_num outSlots = sMap_Slots;
morkBeadProbeMapIter i(ev, this);
morkBead* b = i.FirstBead(ev);
while ( b )
{
b->CutStrongRef(ev);
b = i.NextBead(ev);
}
this->MapCutAll(ev);
return outSlots;
}
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789

258
db/mork/src/morkBead.h Normal file
Просмотреть файл

@ -0,0 +1,258 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MORKBEAD_
#define _MORKBEAD_ 1
#ifndef _MORK_
#include "mork.h"
#endif
#ifndef _MORKNODE_
#include "morkNode.h"
#endif
#ifndef _MORKMAP_
#include "morkMap.h"
#endif
#ifndef _MORKPROBEMAP_
#include "morkProbeMap.h"
#endif
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
#define morkDerived_kBead /*i*/ 0x426F /* ascii 'Bo' */
/*| morkBead: subclass of morkNode that adds knowledge of db suite factory
**| and containing port to those objects that are exposed as instances of
**| nsIMdbBead in the public interface.
|*/
class morkBead : public morkNode {
// public: // slots inherited from morkNode (meant to inform only)
// nsIMdbHeap* mNode_Heap;
// mork_base mNode_Base; // must equal morkBase_kNode
// mork_derived mNode_Derived; // depends on specific node subclass
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
// mork_able mNode_Mutable; // can this node be modified?
// mork_load mNode_Load; // is this node clean or dirty?
// mork_uses mNode_Uses; // refcount for strong refs
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
public: // state is public because the entire Mork system is private
mork_color mBead_Color; // ID for this bead
public: // Hash() and Equal() for bead maps are same for all subclasses:
mork_u4 BeadHash() const { return (mork_u4) mBead_Color; }
mork_bool BeadEqual(const morkBead* inBead) const
{ return ( mBead_Color == inBead->mBead_Color); }
// { ===== begin morkNode interface =====
public: // morkNode virtual methods
virtual void CloseMorkNode(morkEnv* ev); // CloseBead() only if open
virtual ~morkBead(); // assert that CloseBead() executed earlier
public: // special case for stack construction for map usage:
morkBead(mork_color inBeadColor); // stack-based bead instance
protected: // special case for morkObject:
morkBead(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
mork_color inBeadColor);
public: // morkEnv construction & destruction
morkBead(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
mork_color inBeadColor);
void CloseBead(morkEnv* ev); // called by CloseMorkNode();
private: // copying is not allowed
morkBead(const morkBead& other);
morkBead& operator=(const morkBead& other);
public: // dynamic type identification
mork_bool IsBead() const
{ return IsNode() && mNode_Derived == morkDerived_kBead; }
// } ===== end morkNode methods =====
// void NewNilHandleError(morkEnv* ev); // mBead_Handle is nil
public: // typesafe refcounting inlines calling inherited morkNode methods
static void SlotWeakBead(morkBead* me,
morkEnv* ev, morkBead** ioSlot)
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
static void SlotStrongBead(morkBead* me,
morkEnv* ev, morkBead** ioSlot)
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
};
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
#define morkDerived_kBeadMap /*i*/ 0x744D /* ascii 'bM' */
/*| morkBeadMap: maps bead -> bead (key only using mBead_Color)
|*/
class morkBeadMap : public morkMap {
// { ===== begin morkNode interface =====
public: // morkNode virtual methods
virtual void CloseMorkNode(morkEnv* ev); // CloseBeadMap() only if open
virtual ~morkBeadMap(); // assert that CloseBeadMap() executed earlier
public: // morkMap construction & destruction
morkBeadMap(morkEnv* ev, const morkUsage& inUsage,
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
void CloseBeadMap(morkEnv* ev); // called by CloseMorkNode();
public: // dynamic type identification
mork_bool IsBeadMap() const
{ return IsNode() && mNode_Derived == morkDerived_kBeadMap; }
// } ===== end morkNode methods =====
// { ===== begin morkMap poly interface =====
public:
virtual mork_bool // *((mork_u4*) inKeyA) == *((mork_u4*) inKeyB)
Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const;
virtual mork_u4 // some integer function of *((mork_u4*) inKey)
Hash(morkEnv* ev, const void* inKey) const;
// } ===== end morkMap poly interface =====
public: // other map methods
mork_bool AddBead(morkEnv* ev, morkBead* ioBead);
// the AddBead() boolean return equals ev->Good().
mork_bool CutBead(morkEnv* ev, mork_color inColor);
// The CutBead() boolean return indicates whether removal happened.
morkBead* GetBead(morkEnv* ev, mork_color inColor);
// Note the returned bead does NOT have an increase in refcount for this.
mork_num CutAllBeads(morkEnv* ev);
// CutAllBeads() releases all the referenced beads.
};
class morkBeadMapIter: public morkMapIter{ // typesafe wrapper class
public:
morkBeadMapIter(morkEnv* ev, morkBeadMap* ioMap)
: morkMapIter(ev, ioMap) { }
morkBeadMapIter( ) : morkMapIter() { }
void InitBeadMapIter(morkEnv* ev, morkBeadMap* ioMap)
{ this->InitMapIter(ev, ioMap); }
morkBead* FirstBead(morkEnv* ev);
morkBead* NextBead(morkEnv* ev);
morkBead* HereBead(morkEnv* ev);
void CutHereBead(morkEnv* ev);
};
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
#define morkDerived_kBeadProbeMap /*i*/ 0x6D74 /* ascii 'mb' */
/*| morkBeadProbeMap: maps bead -> bead (key only using mBead_Color)
|*/
class morkBeadProbeMap : public morkProbeMap {
// { ===== begin morkNode interface =====
public: // morkNode virtual methods
virtual void CloseMorkNode(morkEnv* ev); // CloseBeadProbeMap() only if open
virtual ~morkBeadProbeMap(); // assert that CloseBeadProbeMap() executed earlier
public: // morkMap construction & destruction
morkBeadProbeMap(morkEnv* ev, const morkUsage& inUsage,
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
void CloseBeadProbeMap(morkEnv* ev); // called by CloseMorkNode();
public: // dynamic type identification
mork_bool IsBeadProbeMap() const
{ return IsNode() && mNode_Derived == morkDerived_kBeadProbeMap; }
// } ===== end morkNode methods =====
// { ===== begin morkProbeMap methods =====
public:
virtual mork_test // hit(a,b) implies hash(a) == hash(b)
MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
MapHash(morkEnv* ev, const void* inAppKey) const;
virtual mork_u4 ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
// virtual mork_bool ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
// virtual void ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
// void* ioMapKey, mork_count inKeyCount); // array of keys inside map
// virtual void ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
// const void* inAppKey, const void* inAppVal, // (key,val) outside map
// void* outMapKey, void* outMapVal); // (key,val) inside map
// virtual void ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
// const void* inMapKey, const void* inMapVal, // (key,val) inside map
// void* outAppKey, void* outAppVal) const; // (key,val) outside map
// } ===== end morkProbeMap methods =====
public: // other map methods
mork_bool AddBead(morkEnv* ev, morkBead* ioBead);
// the AddBead() boolean return equals ev->Good().
morkBead* GetBead(morkEnv* ev, mork_color inColor);
// Note the returned bead does NOT have an increase in refcount for this.
mork_num CutAllBeads(morkEnv* ev);
// CutAllBeads() releases all the referenced bead values.
};
class morkBeadProbeMapIter: public morkProbeMapIter { // typesafe wrapper class
public:
morkBeadProbeMapIter(morkEnv* ev, morkBeadProbeMap* ioMap)
: morkProbeMapIter(ev, ioMap) { }
morkBeadProbeMapIter( ) : morkProbeMapIter() { }
void InitBeadProbeMapIter(morkEnv* ev, morkBeadProbeMap* ioMap)
{ this->InitProbeMapIter(ev, ioMap); }
morkBead* FirstBead(morkEnv* ev)
{ return (morkBead*) this->IterFirstKey(ev); }
morkBead* NextBead(morkEnv* ev)
{ return (morkBead*) this->IterNextKey(ev); }
morkBead* HereBead(morkEnv* ev)
{ return (morkBead*) this->IterHereKey(ev); }
};
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
#endif /* _MORKBEAD_ */

1220
db/mork/src/morkProbeMap.cpp Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

414
db/mork/src/morkProbeMap.h Normal file
Просмотреть файл

@ -0,0 +1,414 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// This code is a port to NS Mork from public domain Mithril C++ sources.
// Note many code comments here come verbatim from cut-and-pasted Mithril.
// In many places, code is identical; Mithril versions stay public domain.
// Changes in porting are mainly class type and scalar type name changes.
#ifndef _MORKPROBEMAP_
#define _MORKPROBEMAP_ 1
#ifndef _MORK_
#include "mork.h"
#endif
#ifndef _MORKNODE_
#include "morkNode.h"
#endif
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
class morkMapScratch { // utility class used by map subclasses
public:
nsIMdbHeap* sMapScratch_Heap; // cached sMap_Heap
mork_count sMapScratch_Slots; // cached sMap_Slots
mork_u1* sMapScratch_Keys; // cached sMap_Keys
mork_u1* sMapScratch_Vals; // cached sMap_Vals
public:
void halt_map_scratch(morkEnv* ev);
};
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
#define morkDerived_kProbeMap 0x7072 /* ascii 'pr' */
#define morkProbeMap_kTag 0x70724D50 /* ascii 'prMP' */
#define morkProbeMap_kLazyClearOnAdd ((mork_u1) 'c')
class morkProbeMap: public morkNode {
protected:
// public: // slots inherited from morkNode (meant to inform only)
// nsIMdbHeap* mNode_Heap;
// mork_base mNode_Base; // must equal morkBase_kNode
// mork_derived mNode_Derived; // depends on specific node subclass
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
// mork_able mNode_Mutable; // can this node be modified?
// mork_load mNode_Load; // is this node clean or dirty?
// mork_uses mNode_Uses; // refcount for strong refs
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
protected:
// { begin morkMap slots
nsIMdbHeap* sMap_Heap; // strong ref to heap allocating all space
mork_u1* sMap_Keys;
mork_u1* sMap_Vals;
mork_count sMap_Seed; // change count of members or structure
mork_count sMap_Slots; // count of slots in the hash table
mork_fill sMap_Fill; // number of used slots in the hash table
mork_size sMap_KeySize; // size of each key (cannot be zero)
mork_size sMap_ValSize; // size of each val (zero allowed)
mork_bool sMap_KeyIsIP; // sMap_KeySize == sizeof(mork_ip)
mork_bool sMap_ValIsIP; // sMap_ValSize == sizeof(mork_ip)
mork_u1 sMap_Pad[ 2 ]; // for u4 alignment
// } end morkMap slots
friend class morkProbeMapIter; // for access to protected slots
public: // getters
mork_count MapSeed() const { return sMap_Seed; }
mork_count MapSlots() const { return sMap_Slots; }
mork_fill MapFill() const { return sMap_Fill; }
mork_size MapKeySize() const { return sMap_KeySize; }
mork_size MapValSize() const { return sMap_ValSize; }
mork_bool MapKeyIsIP() const { return sMap_KeyIsIP; }
mork_bool MapValIsIP() const { return sMap_ValIsIP; }
protected: // slots
// { begin morkProbeMap slots
mork_fill sProbeMap_MaxFill; // max sMap_Fill before map must grow
mork_u1 sProbeMap_LazyClearOnAdd; // true if kLazyClearOnAdd
mork_bool sProbeMap_ZeroIsClearKey; // zero is adequate to clear keys
mork_u1 sProbeMap_Pad[ 2 ]; // for u4 alignment
mork_u4 sProbeMap_Tag;
// } end morkProbeMap slots
friend class morkProbeMapIter; // for access to protected slots
public: // lazy clear on add
mork_bool need_lazy_init() const
{ return sProbeMap_LazyClearOnAdd == morkProbeMap_kLazyClearOnAdd; }
public: // typing
mork_bool GoodProbeMap() const
{ return sProbeMap_Tag == morkProbeMap_kTag; }
protected: // utilities
void* clear_alloc(morkEnv* ev, mork_size inSize);
mork_u1* map_new_vals(morkEnv* ev, mork_num inSlots);
mork_u1* map_new_keys(morkEnv* ev, mork_num inSlots);
void clear_probe_map(morkEnv* ev, nsIMdbHeap* ioMapHeap);
void init_probe_map(morkEnv* ev, mork_size inSlots);
void probe_map_lazy_init(morkEnv* ev);
mork_bool new_slots(morkEnv* ev, morkMapScratch* old, mork_num inSlots);
mork_test find_key_pos(morkEnv* ev, const void* inAppKey,
mork_u4 inHash, mork_pos* outPos) const;
void put_probe_kv(morkEnv* ev,
const void* inAppKey, const void* inAppVal, mork_pos inPos);
void get_probe_kv(morkEnv* ev,
void* outAppKey, void* outAppVal, mork_pos inPos) const;
mork_bool grow_probe_map(morkEnv* ev);
void rehash_old_map(morkEnv* ev, morkMapScratch* ioScratch);
void revert_map(morkEnv* ev, morkMapScratch* ioScratch);
public: // errors
void ProbeMapBadTagError(morkEnv* ev) const;
void WrapWithNoVoidSlotError(morkEnv* ev) const;
void GrowFailsMaxFillError(morkEnv* ev) const;
void MapKeyIsNotIPError(morkEnv* ev) const;
void MapValIsNotIPError(morkEnv* ev) const;
void MapNilKeysError(morkEnv* ev);
void MapZeroKeySizeError(morkEnv* ev);
void MapSeedOutOfSyncError(morkEnv* ev);
void MapFillUnderflowWarning(morkEnv* ev);
static void ProbeMapCutError(morkEnv* ev);
// { ===== begin morkMap methods =====
public:
virtual mork_test // hit(a,b) implies hash(a) == hash(b)
MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
// Note inMapKey is always a key already stored in the map, while inAppKey
// is always a method argument parameter from a client method call.
// This matters the most in morkProbeMap subclasses, which have the
// responsibility of putting 'app' keys into slots for 'map' keys, and
// the bit pattern representation might be different in such cases.
// morkTest_kHit means that inMapKey equals inAppKey (and this had better
// also imply that hash(inMapKey) == hash(inAppKey)).
// morkTest_kMiss means that inMapKey does NOT equal inAppKey (but this
// implies nothing at all about hash(inMapKey) and hash(inAppKey)).
// morkTest_kVoid means that inMapKey is not a valid key bit pattern,
// which means that key slot in the map is not being used. Note that
// kVoid is only expected as a return value in morkProbeMap subclasses,
// because morkProbeMap must ask whether a key slot is used or not.
// morkChainMap however, always knows when a key slot is used, so only
// key slots expected to have valid bit patterns will be presented to
// the MapTest() methods for morkChainMap subclasses.
//
// NOTE: it is very important that subclasses correctly return the value
// morkTest_kVoid whenever the slot for inMapKey contains a bit pattern
// that means the slot is not being used, because this is the only way a
// probe map can terminate an unsuccessful search for a key in the map.
virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
MapHash(morkEnv* ev, const void* inAppKey) const;
virtual mork_bool
MapAtPut(morkEnv* ev, const void* inAppKey, const void* inAppVal,
void* outAppKey, void* outAppVal);
virtual mork_bool
MapAt(morkEnv* ev, const void* inAppKey, void* outAppKey, void* outAppVal);
virtual mork_num
MapCutAll(morkEnv* ev);
// } ===== end morkMap methods =====
// { ===== begin morkProbeMap methods =====
public:
virtual mork_u4
ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
// ProbeMapHashMapKey() does logically the same thing as MapHash(), and
// the default implementation actually calls virtual MapHash(). However,
// Subclasses must override this method whenever the formats of keys in
// the map differ from app keys outside the map, because MapHash() only
// works on keys in 'app' format, while ProbeMapHashMapKey() only works
// on keys in 'map' format. This method is called in order to rehash all
// map keys when a map is grown, and this causes all old map members to
// move into new slot locations.
//
// Note it is absolutely imperative that a hash for a key in 'map' format
// be exactly the same the hash of the same key in 'app' format, or else
// maps will seem corrupt later when keys in 'app' format cannot be found.
virtual mork_bool
ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
// ProbeMapIsKeyNil() must say whether the representation of logical 'nil'
// is currently found inside the key at ioMapKey, for a key found within
// the map. The the map iterator uses this method to find map keys that
// are actually being used for valid map associations; otherwise the
// iterator cannot determine which map slots actually denote used keys.
// The default method version returns true if all the bits equal zero.
virtual void
ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
void* ioMapKey, mork_count inKeyCount); // array of keys inside map
// ProbeMapClearKey() must put some representation of logical 'nil' into
// every key slot in the map, such that MapTest() will later recognize
// that this bit pattern shows each key slot is not actually being used.
//
// This method is typically called whenever the map is either created or
// grown into a larger size, where ioMapKey is a pointer to an array of
// inKeyCount keys, where each key is this->MapKeySize() bytes in size.
// Note that keys are assumed immediately adjacent with no padding, so
// if any alignment requirements must be met, then subclasses should have
// already accounted for this when specifying a key size in the map.
//
// Since this method will be called when a map is being grown in size,
// nothing should be assumed about the state slots of the map, since the
// ioMapKey array might not yet live in sMap_Keys, and the array length
// inKeyCount might not yet live in sMap_Slots. However, the value kept
// in sMap_KeySize never changes, so this->MapKeySize() is always correct.
virtual void
ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
const void* inAppKey, const void* inAppVal, // (key,val) outside map
void* outMapKey, void* outMapVal); // (key,val) inside map
// This method actually puts keys and vals in the map in suitable format.
//
// ProbeMapPushIn() must copy a caller key and value in 'app' format
// into the map slots provided, which are in 'map' format. When the
// 'app' and 'map' formats are identical, then this is just a bitwise
// copy of this->MapKeySize() key bytes and this->MapValSize() val bytes,
// and this is exactly what the default implementation performs. However,
// if 'app' and 'map' formats are different, and MapTest() depends on this
// difference in format, then subclasses must override this method to do
// whatever is necessary to store the input app key in output map format.
//
// Do NOT write more than this->MapKeySize() bytes of a map key, or more
// than this->MapValSize() bytes of a map val, or corruption might ensue.
//
// The inAppKey and inAppVal parameters are the same ones passed into a
// call to MapAtPut(), and the outMapKey and outMapVal parameters are ones
// determined by how the map currently positions key inAppKey in the map.
//
// Note any key or val parameter can be a null pointer, in which case
// this method must do nothing with those parameters. In particular, do
// no key move at all when either inAppKey or outMapKey is nil, and do
// no val move at all when either inAppVal or outMapVal is nil. Note that
// outMapVal should always be nil when this->MapValSize() is nil.
virtual void
ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
const void* inMapKey, const void* inMapVal, // (key,val) inside map
void* outAppKey, void* outAppVal) const; // (key,val) outside map
// This method actually gets keys and vals from the map in suitable format.
//
// ProbeMapPullOut() must copy a key and val in 'map' format into the
// caller key and val slots provided, which are in 'app' format. When the
// 'app' and 'map' formats are identical, then this is just a bitwise
// copy of this->MapKeySize() key bytes and this->MapValSize() val bytes,
// and this is exactly what the default implementation performs. However,
// if 'app' and 'map' formats are different, and MapTest() depends on this
// difference in format, then subclasses must override this method to do
// whatever is necessary to store the input map key in output app format.
//
// The outAppKey and outAppVal parameters are the same ones passed into a
// call to either MapAtPut() or MapAt(), while inMapKey and inMapVal are
// determined by how the map currently positions the target key in the map.
//
// Note any key or val parameter can be a null pointer, in which case
// this method must do nothing with those parameters. In particular, do
// no key move at all when either inMapKey or outAppKey is nil, and do
// no val move at all when either inMapVal or outAppVal is nil. Note that
// inMapVal should always be nil when this->MapValSize() is nil.
// } ===== end morkProbeMap methods =====
// { ===== begin morkNode interface =====
public: // morkNode virtual methods
virtual void CloseMorkNode(morkEnv* ev); // CloseProbeMap() only if open
virtual ~morkProbeMap(); // assert that CloseProbeMap() executed earlier
public: // morkProbeMap construction & destruction
morkProbeMap(morkEnv* ev, const morkUsage& inUsage,
nsIMdbHeap* ioNodeHeap,
mork_size inKeySize, mork_size inValSize,
nsIMdbHeap* ioMapHeap, mork_size inSlots,
mork_bool inZeroIsClearKey);
void CloseProbeMap(morkEnv* ev); // called by
public: // dynamic type identification
mork_bool IsProbeMap() const
{ return IsNode() && mNode_Derived == morkDerived_kProbeMap; }
// } ===== end morkNode methods =====
public: // typesafe refcounting inlines calling inherited morkNode methods
static void SlotWeakMap(morkMap* me,
morkEnv* ev, morkMap** ioSlot)
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
static void SlotStrongMap(morkMap* me,
morkEnv* ev, morkMap** ioSlot)
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
};
/*============================================================================*/
/* morkProbeMapIter */
#define morkProbeMapIter_kBeforeIx ((mork_i4) -1) /* before first member */
#define morkProbeMapIter_kAfterIx ((mork_i4) -2) /* after last member */
class morkProbeMapIter {
protected:
morkProbeMap* sProbeMapIter_Map; // nonref
mork_num sProbeMapIter_Seed; // iter's cached copy of map's seed
mork_i4 sProbeMapIter_HereIx;
mork_change sProbeMapIter_Change; // morkMapIter API simulation dummy
mork_u1 sProbeMapIter_Pad[ 3 ]; // for u4 alignment
public:
morkProbeMapIter(morkEnv* ev, morkProbeMap* ioMap);
void CloseMapIter(morkEnv* ev);
morkProbeMapIter( ); // zero most slots; caller must call InitProbeMapIter()
protected: // protected so subclasses must provide suitable typesafe inlines:
void InitProbeMapIter(morkEnv* ev, morkProbeMap* ioMap);
void InitMapIter(morkEnv* ev, morkProbeMap* ioMap) // morkMapIter compatibility
{ this->InitProbeMapIter(ev, ioMap); }
mork_bool IterFirst(morkEnv* ev, void* outKey, void* outVal);
mork_bool IterNext(morkEnv* ev, void* outKey, void* outVal);
mork_bool IterHere(morkEnv* ev, void* outKey, void* outVal);
// NOTE: the following methods ONLY work for sMap_ValIsIP pointer values.
// (Note the implied assumption that zero is never a good value pattern.)
void* IterFirstVal(morkEnv* ev, void* outKey);
// equivalent to { void* v=0; this->IterFirst(ev, outKey, &v); return v; }
void* IterNextVal(morkEnv* ev, void* outKey);
// equivalent to { void* v=0; this->IterNext(ev, outKey, &v); return v; }
void* IterHereVal(morkEnv* ev, void* outKey);
// equivalent to { void* v=0; this->IterHere(ev, outKey, &v); return v; }
// NOTE: the following methods ONLY work for sMap_KeyIsIP pointer values.
// (Note the implied assumption that zero is never a good key pattern.)
void* IterFirstKey(morkEnv* ev);
// equivalent to { void* k=0; this->IterFirst(ev, &k, 0); return k; }
void* IterNextKey(morkEnv* ev);
// equivalent to { void* k=0; this->IterNext(ev, &k, 0); return k; }
void* IterHereKey(morkEnv* ev);
// equivalent to { void* k=0; this->IterHere(ev, &k, 0); return k; }
public: // simulation of the morkMapIter API for morkMap compatibility:
mork_change* First(morkEnv* ev, void* outKey, void* outVal);
mork_change* Next(morkEnv* ev, void* outKey, void* outVal);
mork_change* Here(morkEnv* ev, void* outKey, void* outVal);
mork_change* CutHere(morkEnv* ev, void* outKey, void* outVal);
};
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
#endif /* _MORKPROBEMAP_ */

557
db/mork/src/morkZone.cpp Normal file
Просмотреть файл

@ -0,0 +1,557 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MDB_
#include "mdb.h"
#endif
#ifndef _MORK_
#include "mork.h"
#endif
#ifndef _MORKNODE_
#include "morkNode.h"
#endif
#ifndef _MORKZONE_
#include "morkZone.h"
#endif
#ifndef _MORKENV_
#include "morkEnv.h"
#endif
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
// { ===== begin morkNode interface =====
// public: // morkNode virtual methods
void morkZone::CloseMorkNode(morkEnv* ev) // CloseZone() only if open
{
if ( this->IsOpenNode() )
{
this->MarkClosing();
this->CloseZone(ev);
this->MarkShut();
}
}
morkZone::~morkZone() // assert that CloseZone() executed earlier
{
MORK_ASSERT(this->IsShutNode());
}
// public: // morkMap construction & destruction
morkZone::morkZone(morkEnv* ev, const morkUsage& inUsage,
nsIMdbHeap* ioNodeHeap, nsIMdbHeap* ioZoneHeap)
: morkNode(ev, inUsage, ioNodeHeap)
, mZone_Heap( 0 )
, mZone_HeapVolume( 0 )
, mZone_BlockVolume( 0 )
, mZone_RunVolume( 0 )
, mZone_ChipVolume( 0 )
, mZone_FreeOldRunVolume( 0 )
, mZone_HunkCount( 0 )
, mZone_FreeOldRunCount( 0 )
, mZone_HunkList( 0 )
, mZone_FreeOldRunList( 0 )
, mZone_At( 0 )
, mZone_AtSize( 0 )
// morkRun* mZone_FreeRuns[ morkZone_kBuckets + 1 ];
{
morkRun** runs = mZone_FreeRuns;
morkRun** end = runs + (morkZone_kBuckets + 1); // one past last slot
--runs; // prepare for preincrement
while ( ++runs < end ) // another slot in array?
*runs = 0; // clear all the slots
if ( ev->Good() )
{
if ( ioZoneHeap )
{
nsIMdbHeap_SlotStrongHeap(ioZoneHeap, ev, &mZone_Heap);
if ( ev->Good() )
mNode_Derived = morkDerived_kZone;
}
else
ev->NilPointerError();
}
}
void morkZone::CloseZone(morkEnv* ev) // called by CloseMorkNode()
{
if ( this )
{
if ( this->IsNode() )
{
nsIMdbHeap* heap = mZone_Heap;
if ( heap )
{
morkHunk* hunk = 0;
nsIMdbEnv* mev = ev->AsMdbEnv();
morkHunk* next = mZone_HunkList;
while ( ( hunk = next ) != 0 )
{
#ifdef morkHunk_USE_TAG_SLOT
if ( !hunk->HunkGoodTag() )
hunk->BadHunkTagWarning(ev);
#endif /* morkHunk_USE_TAG_SLOT */
next = hunk->HunkNext();
heap->Free(mev, hunk);
}
}
nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mZone_Heap);
this->MarkShut();
}
else
this->NonNodeError(ev);
}
else
ev->NilPointerError();
}
// } ===== end morkNode methods =====
/*static*/ void
morkZone::NonZoneTypeError(morkEnv* ev)
{
ev->NewError("non morkZone");
}
/*static*/ void
morkZone::NilZoneHeapError(morkEnv* ev)
{
ev->NewError("nil mZone_Heap");
}
/*static*/ void
morkHunk::BadHunkTagWarning(morkEnv* ev)
{
ev->NewWarning("bad mHunk_Tag");
}
/*static*/ void
morkRun::BadRunTagError(morkEnv* ev)
{
ev->NewError("bad mRun_Tag");
}
/*static*/ void
morkRun::RunSizeAlignError(morkEnv* ev)
{
ev->NewError("bad RunSize() alignment");
}
// { ===== begin morkZone methods =====
mork_size morkZone::zone_grow_at(morkEnv* ev, mork_size inNeededSize)
{
mZone_At = 0; // remove any ref to current hunk
mZone_AtSize = 0; // zero available bytes in current hunk
mork_size runSize = 0; // actual size of a particular run
// try to find a run in old run list with at least inNeededSize bytes:
morkRun* run = mZone_FreeOldRunList; // cursor in list scan
morkRun* prev = 0; // the node before run in the list scan
while ( run ) // another run in list to check?
{
morkOldRun* oldRun = (morkOldRun*) run;
mork_size oldSize = oldRun->OldSize();
if ( oldSize >= inNeededSize ) // found one big enough?
{
runSize = oldSize;
break; // end while loop early
}
prev = run; // remember last position in singly linked list
run = run->RunNext(); // advance cursor to next node in list
}
if ( runSize && run ) // found a usable old run?
{
morkRun* next = run->RunNext();
if ( prev ) // another node in free list precedes run?
prev->RunSetNext(next); // unlink run
else
mZone_FreeOldRunList = run; // unlink run from head of list
run->RunSetSize(runSize);
mZone_At = (mork_u1*) run->RunAsBlock();
mZone_AtSize = runSize;
#ifdef morkZone_CONFIG_DEBUG
#ifdef morkZone_CONFIG_ALIGN_8
mork_ip lowThree = ((mork_ip) mZone_At) & 7;
if ( lowThree ) // not 8 byte aligned?
#else /*morkZone_CONFIG_ALIGN_8*/
mork_ip lowTwo = ((mork_ip) mZone_At) & 3;
if ( lowTwo ) // not 4 byte aligned?
#endif /*morkZone_CONFIG_ALIGN_8*/
ev->NewWarning("mZone_At not aligned");
#endif /*morkZone_CONFIG_DEBUG*/
}
else // need to allocate a brand new run
{
inNeededSize += 7; // allow for possible alignment padding
mork_size newSize = ( inNeededSize > morkZone_kNewHunkSize )?
inNeededSize : morkZone_kNewHunkSize;
morkHunk* hunk = this->zone_new_hunk(ev, newSize);
if ( hunk )
{
morkRun* hunkRun = hunk->HunkRun();
mork_u1* at = (mork_u1*) hunkRun->RunAsBlock();
mork_ip lowBits = ((mork_ip) at) & 7;
if ( lowBits ) // not 8 byte aligned?
{
mork_ip skip = (8 - lowBits); // skip the complement to align
at += skip;
newSize -= skip;
}
mZone_At = at;
mZone_AtSize = newSize;
}
}
return mZone_AtSize;
}
morkHunk* morkZone::zone_new_hunk(morkEnv* ev, mdb_size inSize) // alloc
{
mdb_size hunkSize = inSize + sizeof(morkHunk);
void* outBlock = 0; // we are going straight to the heap:
mZone_Heap->Alloc(ev->AsMdbEnv(), hunkSize, &outBlock);
if ( outBlock )
{
#ifdef morkZone_CONFIG_VOL_STATS
mZone_HeapVolume += hunkSize; // track all heap allocations
#endif /* morkZone_CONFIG_VOL_STATS */
morkHunk* hunk = (morkHunk*) outBlock;
#ifdef morkHunk_USE_TAG_SLOT
hunk->HunkInitTag();
#endif /* morkHunk_USE_TAG_SLOT */
hunk->HunkSetNext(mZone_HunkList);
mZone_HunkList = hunk;
++mZone_HunkCount;
morkRun* run = hunk->HunkRun();
run->RunSetSize(inSize);
#ifdef morkRun_USE_TAG_SLOT
run->RunInitTag();
#endif /* morkRun_USE_TAG_SLOT */
return hunk;
}
if ( ev->Good() ) // got this far without any error reported yet?
ev->OutOfMemoryError();
return (morkHunk*) 0;
}
void* morkZone::zone_new_chip(morkEnv* ev, mdb_size inSize) // alloc
{
#ifdef morkZone_CONFIG_VOL_STATS
mZone_BlockVolume += inSize; // sum sizes of both chips and runs
#endif /* morkZone_CONFIG_VOL_STATS */
mork_u1* at = mZone_At;
mork_size atSize = mZone_AtSize; // available bytes in current hunk
if ( atSize >= inSize ) // current hunk can satisfy request?
{
mZone_At = at + inSize;
mZone_AtSize = atSize - inSize;
return at;
}
else if ( atSize > morkZone_kMaxHunkWaste ) // over max waste allowed?
{
morkHunk* hunk = this->zone_new_hunk(ev, inSize);
if ( hunk )
return hunk->HunkRun();
return (void*) 0; // show allocation has failed
}
else // get ourselves a new hunk for suballocation:
{
atSize = this->zone_grow_at(ev, inSize); // get a new hunk
}
if ( atSize >= inSize ) // current hunk can satisfy request?
{
at = mZone_At;
mZone_At = at + inSize;
mZone_AtSize = atSize - inSize;
return at;
}
if ( ev->Good() ) // got this far without any error reported yet?
ev->OutOfMemoryError();
return (void*) 0; // show allocation has failed
}
void* morkZone::ZoneNewChip(morkEnv* ev, mdb_size inSize) // alloc
{
#ifdef morkZone_CONFIG_ARENA
#ifdef morkZone_CONFIG_DEBUG
if ( !this->IsZone() )
this->NonZoneTypeError(ev);
else if ( !mZone_Heap )
this->NilZoneHeapError(ev);
#endif /*morkZone_CONFIG_DEBUG*/
#ifdef morkZone_CONFIG_ALIGN_8
inSize += 7;
inSize &= ~((mork_ip) 7); // force to multiple of 8 bytes
#else /*morkZone_CONFIG_ALIGN_8*/
inSize += 3;
inSize &= ~((mork_ip) 3); // force to multiple of 4 bytes
#endif /*morkZone_CONFIG_ALIGN_8*/
#ifdef morkZone_CONFIG_VOL_STATS
mZone_ChipVolume += inSize; // sum sizes of chips only
#endif /* morkZone_CONFIG_VOL_STATS */
return this->zone_new_chip(ev, inSize);
#else /*morkZone_CONFIG_ARENA*/
void* outBlock = 0;
mZone_Heap->Alloc(ev->AsMdbEnv(), inSize, &outBlock);
return outBlock;
#endif /*morkZone_CONFIG_ARENA*/
}
// public: // ...but runs do indeed know how big they are
void* morkZone::ZoneNewRun(morkEnv* ev, mdb_size inSize) // alloc
{
#ifdef morkZone_CONFIG_ARENA
#ifdef morkZone_CONFIG_DEBUG
if ( !this->IsZone() )
this->NonZoneTypeError(ev);
else if ( !mZone_Heap )
this->NilZoneHeapError(ev);
#endif /*morkZone_CONFIG_DEBUG*/
inSize += morkZone_kRoundAdd;
inSize &= morkZone_kRoundMask;
if ( inSize <= morkZone_kMaxCachedRun )
{
morkRun** bucket = mZone_FreeRuns + (inSize >> morkZone_kRoundBits);
morkRun* hit = *bucket;
if ( hit ) // cache hit?
{
*bucket = hit->RunNext();
hit->RunSetSize(inSize);
return hit->RunAsBlock();
}
}
mdb_size blockSize = inSize + sizeof(morkRun); // plus run overhead
#ifdef morkZone_CONFIG_VOL_STATS
mZone_RunVolume += blockSize; // sum sizes of runs only
#endif /* morkZone_CONFIG_VOL_STATS */
morkRun* run = (morkRun*) this->zone_new_chip(ev, blockSize);
if ( run )
{
run->RunSetSize(inSize);
#ifdef morkRun_USE_TAG_SLOT
run->RunInitTag();
#endif /* morkRun_USE_TAG_SLOT */
return run->RunAsBlock();
}
if ( ev->Good() ) // got this far without any error reported yet?
ev->OutOfMemoryError();
return (void*) 0; // indicate failed allocation
#else /*morkZone_CONFIG_ARENA*/
void* outBlock = 0;
mZone_Heap->Alloc(ev->AsMdbEnv(), inSize, &outBlock);
return outBlock;
#endif /*morkZone_CONFIG_ARENA*/
}
void morkZone::ZoneZapRun(morkEnv* ev, void* ioRunBlock) // free
{
#ifdef morkZone_CONFIG_ARENA
morkRun* run = morkRun::BlockAsRun(ioRunBlock);
mdb_size runSize = run->RunSize();
#ifdef morkZone_CONFIG_VOL_STATS
mZone_BlockVolume -= runSize; // tracking sizes of both chips and runs
#endif /* morkZone_CONFIG_VOL_STATS */
#ifdef morkZone_CONFIG_DEBUG
if ( !this->IsZone() )
this->NonZoneTypeError(ev);
else if ( !mZone_Heap )
this->NilZoneHeapError(ev);
else if ( !ioRunBlock )
ev->NilPointerError();
else if ( runSize & morkZone_kRoundAdd )
run->RunSizeAlignError(ev);
#ifdef morkRun_USE_TAG_SLOT
else if ( !run->RunGoodTag() )
run->BadRunTagError(ev);
#endif /* morkRun_USE_TAG_SLOT */
#endif /*morkZone_CONFIG_DEBUG*/
if ( runSize <= morkZone_kMaxCachedRun ) // goes into free run list?
{
morkRun** bucket = mZone_FreeRuns + (runSize >> morkZone_kRoundBits);
run->RunSetNext(*bucket); // push onto free run list
*bucket = run;
}
else // free old run list
{
run->RunSetNext(mZone_FreeOldRunList); // push onto free old run list
mZone_FreeOldRunList = run;
++mZone_FreeOldRunCount;
#ifdef morkZone_CONFIG_VOL_STATS
mZone_FreeOldRunVolume += runSize;
#endif /* morkZone_CONFIG_VOL_STATS */
morkOldRun* oldRun = (morkOldRun*) run; // to access extra size slot
oldRun->OldSetSize(runSize); // so we know how big this is later
}
#else /*morkZone_CONFIG_ARENA*/
mZone_Heap->Free(ev->AsMdbEnv(), ioRunBlock);
#endif /*morkZone_CONFIG_ARENA*/
}
void* morkZone::ZoneGrowRun(morkEnv* ev, void* ioRunBlock, mdb_size inSize)
{
#ifdef morkZone_CONFIG_ARENA
morkRun* run = morkRun::BlockAsRun(ioRunBlock);
mdb_size runSize = run->RunSize();
#ifdef morkZone_CONFIG_DEBUG
if ( !this->IsZone() )
this->NonZoneTypeError(ev);
else if ( !mZone_Heap )
this->NilZoneHeapError(ev);
#endif /*morkZone_CONFIG_DEBUG*/
#ifdef morkZone_CONFIG_ALIGN_8
inSize += 7;
inSize &= ~((mork_ip) 7); // force to multiple of 8 bytes
#else /*morkZone_CONFIG_ALIGN_8*/
inSize += 3;
inSize &= ~((mork_ip) 3); // force to multiple of 4 bytes
#endif /*morkZone_CONFIG_ALIGN_8*/
if ( inSize > runSize )
{
void* newBuf = this->ZoneNewRun(ev, inSize);
if ( newBuf )
{
MORK_MEMCPY(newBuf, ioRunBlock, runSize);
this->ZoneZapRun(ev, ioRunBlock);
return newBuf;
}
}
else
return ioRunBlock; // old size is big enough
if ( ev->Good() ) // got this far without any error reported yet?
ev->OutOfMemoryError();
return (void*) 0; // indicate failed allocation
#else /*morkZone_CONFIG_ARENA*/
void* outBlock = 0;
mZone_Heap->Free(ev->AsMdbEnv(), ioRunBlock);
return outBlock;
#endif /*morkZone_CONFIG_ARENA*/
}
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
// { ===== begin nsIMdbHeap methods =====
/*virtual*/ mdb_err
morkZone::Alloc(nsIMdbEnv* mev, // allocate a piece of memory
mdb_size inSize, // requested size of new memory block
void** outBlock) // memory block of inSize bytes, or nil
{
mdb_err outErr = 0;
void* block = 0;
morkEnv* ev = morkEnv::FromMdbEnv(mev);
if ( ev )
{
block = this->ZoneNewRun(ev, inSize);
outErr = ev->AsErr();
}
else
outErr = 1;
if ( outBlock )
*outBlock = block;
return outErr;
}
/*virtual*/ mdb_err
morkZone::Free(nsIMdbEnv* mev, // free block allocated earlier by Alloc()
void* inBlock)
{
mdb_err outErr = 0;
if ( inBlock )
{
morkEnv* ev = morkEnv::FromMdbEnv(mev);
if ( ev )
{
this->ZoneZapRun(ev, inBlock);
outErr = ev->AsErr();
}
else
outErr = 1;
}
return outErr;
}
/*virtual*/ mdb_err
morkZone::HeapAddStrongRef(nsIMdbEnv* mev) // does nothing
{
MORK_USED_1(mev);
return 0;
}
/*virtual*/ mdb_err
morkZone::HeapCutStrongRef(nsIMdbEnv* mev) // does nothing
{
MORK_USED_1(mev);
return 0;
}
// } ===== end nsIMdbHeap methods =====

335
db/mork/src/morkZone.h Normal file
Просмотреть файл

@ -0,0 +1,335 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _MORKZONE_
#define _MORKZONE_ 1
#ifndef _MORK_
#include "mork.h"
#endif
#ifndef _MORKNODE_
#include "morkNode.h"
#endif
#ifndef _MORKDEQUE_
#include "morkDeque.h"
#endif
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
/*| CONFIG_DEBUG: do paranoid debug checks if defined.
|*/
#ifdef MORK_DEBUG
#define morkZone_CONFIG_DEBUG 1 /* debug paranoid if defined */
#endif /*MORK_DEBUG*/
/*| CONFIG_STATS: keep volume and usage statistics.
|*/
#define morkZone_CONFIG_VOL_STATS 1 /* count space used by zone instance */
/*| CONFIG_ARENA: if this is defined, then the morkZone class will alloc big
**| blocks from the zone's heap, and suballocate from these. If undefined,
**| then morkZone will just pass all calls through to the zone's heap.
|*/
#ifdef MORK_ENABLE_ZONE_ARENAS
#define morkZone_CONFIG_ARENA 1 /* be arena, if defined; otherwise no-op */
#endif /*MORK_ENABLE_ZONE_ARENAS*/
/*| CONFIG_ALIGN_8: if this is defined, then the morkZone class will give
**| blocks 8 byte alignment instead of only 4 byte alignment.
|*/
#ifdef MORK_CONFIG_ALIGN_8
#define morkZone_CONFIG_ALIGN_8 1 /* ifdef: align to 8 bytes, otherwise 4 */
#endif /*MORK_CONFIG_ALIGN_8*/
/*| CONFIG_PTR_SIZE_4: if this is defined, then the morkZone class will
**| assume sizeof(void*) == 4, so a tag slot for padding is needed.
|*/
#ifdef MORK_CONFIG_PTR_SIZE_4
#define morkZone_CONFIG_PTR_SIZE_4 1 /* ifdef: sizeof(void*) == 4 */
#endif /*MORK_CONFIG_PTR_SIZE_4*/
/*| morkZone_USE_TAG_SLOT: if this is defined, then define slot mRun_Tag
**| in order to achieve eight byte alignment after the mRun_Next slot.
|*/
#if defined(morkZone_CONFIG_ALIGN_8) && defined(morkZone_CONFIG_PTR_SIZE_4)
#define morkRun_USE_TAG_SLOT 1 /* need mRun_Tag slot inside morkRun */
#define morkHunk_USE_TAG_SLOT 1 /* need mHunk_Tag slot inside morkHunk */
#endif
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
#define morkRun_kTag ((mork_u4) 0x6D52754E ) /* ascii 'mRuN' */
/*| morkRun: structure used by morkZone for sized blocks
|*/
class morkRun {
protected: // member variable slots
#ifdef morkRun_USE_TAG_SLOT
mork_u4 mRun_Tag; // force 8 byte alignment after mRun_Next
#endif /* morkRun_USE_TAG_SLOT */
morkRun* mRun_Next;
public: // pointer interpretation of mRun_Next (when inside a list):
morkRun* RunNext() const { return mRun_Next; }
void RunSetNext(morkRun* ioNext) { mRun_Next = ioNext; }
public: // size interpretation of mRun_Next (when not inside a list):
mork_size RunSize() const { return (mork_size) ((mork_ip) mRun_Next); }
void RunSetSize(mork_size inSize)
{ mRun_Next = (morkRun*) ((mork_ip) inSize); }
public: // maintenance and testing of optional tag magic signature slot:
#ifdef morkRun_USE_TAG_SLOT
void RunInitTag() { mRun_Tag = morkRun_kTag; }
mork_bool RunGoodTag() { return ( mRun_Tag == morkRun_kTag ); }
#endif /* morkRun_USE_TAG_SLOT */
public: // conversion back and forth to inline block following run instance:
void* RunAsBlock() { return (((mork_u1*) this) + sizeof(morkRun)); }
static morkRun* BlockAsRun(void* ioBlock)
{ return (morkRun*) (((mork_u1*) ioBlock) - sizeof(morkRun)); }
public: // typing & errors
static void BadRunTagError(morkEnv* ev);
static void RunSizeAlignError(morkEnv* ev);
};
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
/*| morkOldRun: more space to record size when run is put into old free list
|*/
class morkOldRun : public morkRun {
protected: // need another size field when mRun_Next is used for linkage:
mdb_size mOldRun_Size;
public: // size getter/setter
mork_size OldSize() const { return mOldRun_Size; }
void OldSetSize(mork_size inSize) { mOldRun_Size = inSize; }
};
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
#define morkHunk_kTag ((mork_u4) 0x68556E4B ) /* ascii 'hUnK' */
/*| morkHunk: structure used by morkZone for heap allocations.
|*/
class morkHunk {
protected: // member variable slots
#ifdef morkHunk_USE_TAG_SLOT
mork_u4 mHunk_Tag; // force 8 byte alignment after mHunk_Next
#endif /* morkHunk_USE_TAG_SLOT */
morkHunk* mHunk_Next;
morkRun mHunk_Run;
public: // setters
void HunkSetNext(morkHunk* ioNext) { mHunk_Next = ioNext; }
public: // getters
morkHunk* HunkNext() const { return mHunk_Next; }
morkRun* HunkRun() { return &mHunk_Run; }
public: // maintenance and testing of optional tag magic signature slot:
#ifdef morkHunk_USE_TAG_SLOT
void HunkInitTag() { mHunk_Tag = morkHunk_kTag; }
mork_bool HunkGoodTag() { return ( mHunk_Tag == morkHunk_kTag ); }
#endif /* morkHunk_USE_TAG_SLOT */
public: // typing & errors
static void BadHunkTagWarning(morkEnv* ev);
};
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
/*| kNewHunkSize: the default size for a hunk, assuming we must allocate
**| a new one whenever the free hunk list does not already have. Note this
**| number should not be changed without also considering suitable changes
**| in the related kMaxHunkWaste and kMinHunkSize constants.
|*/
#define morkZone_kNewHunkSize ((mork_size) (64 * 1024)) /* 64K per hunk */
/*| kMaxFreeVolume: some number of bytes of free space in the free hunk list
**| over which we no longer want to add more free hunks to the list, for fear
**| of accumulating too much unused, fragmented free space. This should be a
**| small multiple of kNewHunkSize, say about two to four times as great, to
**| allow for no more free hunk space than fits in a handful of new hunks.
**| This strategy will let us usefully accumulate "some" free space in the
**| free hunk list, but without accumulating "too much" free space that way.
|*/
#define morkZone_kMaxFreeVolume (morkZone_kNewHunkSize * 3)
/*| kMaxHunkWaste: if a current request is larger than this, and we cannot
**| satisfy the request with the current hunk, then we just allocate the
**| block from the heap without changing the current hunk. Basically this
**| number represents the largest amount of memory we are willing to waste,
**| since a block request barely less than this can cause the current hunk
**| to be retired (with any unused space wasted) as well get a new hunk.
|*/
#define morkZone_kMaxHunkWaste ((mork_size) 4096) /* 1/16 kNewHunkSize */
/*| kRound*: the algorithm for rounding up allocation sizes for caching
**| in free lists works like the following. We add kRoundAdd to any size
**| requested, and then bitwise AND with kRoundMask, and this will give us
**| the smallest multiple of kRoundSize that is at least as large as the
**| requested size. Then if we rightshift this number by kRoundBits, we
**| will have the index into the mZone_FreeRuns array which will hold any
**| cache runs of that size. So 4 bits of shift gives us a granularity
**| of 16 bytes, so that free lists will hold successive runs that are
**| 16 bytes greater than the next smaller run size. If we have 256 free
**| lists of nonzero sized runs altogether, then the largest run that can
**| be cached is 4096, or 4K (since 4096 == 16 * 256). A larger run that
**| gets freed will go in to the free hunk list (or back to the heap).
|*/
#define morkZone_kRoundBits 4 /* bits to round-up size for free lists */
#define morkZone_kRoundSize (1 << morkZone_kRoundBits)
#define morkZone_kRoundAdd ((1 << morkZone_kRoundBits) - 1)
#define morkZone_kRoundMask (~ ((mork_ip) morkZone_kRoundAdd))
#define morkZone_kBuckets 256 /* number of distinct free lists */
/*| kMaxCachedRun: the largest run that will be stored inside a free
**| list of old zapped runs. A run larger than this cannot be put in
**| a free list, and must be allocated from the heap at need, and put
**| into the free hunk list when discarded.
|*/
#define morkZone_kMaxCachedRun (morkZone_kBuckets * morkZone_kRoundSize)
#define morkDerived_kZone /*i*/ 0x5A6E /* ascii 'Zn' */
/*| morkZone: a pooled memory allocator like an NSPR arena. The term 'zone'
**| is roughly synonymous with 'heap'. I avoid calling this class a "heap"
**| to avoid any confusion with nsIMdbHeap, and I avoid calling this class
**| an arean to avoid confusion with NSPR usage.
|*/
class morkZone : public morkNode, public nsIMdbHeap {
// public: // slots inherited from morkNode (meant to inform only)
// nsIMdbHeap* mNode_Heap;
// mork_base mNode_Base; // must equal morkBase_kNode
// mork_derived mNode_Derived; // depends on specific node subclass
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
// mork_able mNode_Mutable; // can this node be modified?
// mork_load mNode_Load; // is this node clean or dirty?
// mork_uses mNode_Uses; // refcount for strong refs
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
public: // state is public because the entire Mork system is private
nsIMdbHeap* mZone_Heap; // strong ref to heap allocating all space
mork_size mZone_HeapVolume; // total bytes allocated from heap
mork_size mZone_BlockVolume; // total bytes in all zone blocks
mork_size mZone_RunVolume; // total bytes in all zone runs
mork_size mZone_ChipVolume; // total bytes in all zone chips
mork_size mZone_FreeOldRunVolume; // total bytes in all used hunks
mork_count mZone_HunkCount; // total number of used hunks
mork_count mZone_FreeOldRunCount; // total free old runs
morkHunk* mZone_HunkList; // linked list of all used hunks
morkRun* mZone_FreeOldRunList; // linked list of free old runs
// note mZone_At is a byte pointer for single byte address arithmetic:
mork_u1* mZone_At; // current position in most recent hunk
mork_size mZone_AtSize; // number of bytes remaining in this hunk
// kBuckets+1 so indexes zero through kBuckets are all okay to use:
morkRun* mZone_FreeRuns[ morkZone_kBuckets + 1 ];
// Each piece of memory stored in list mZone_FreeRuns[ i ] has an
// allocation size equal to sizeof(morkRun) + (i * kRoundSize), so
// that callers can be given a piece of memory with (i * kRoundSize)
// bytes of writeable space while reserving the first sizeof(morkRun)
// bytes to keep track of size information for later re-use. Note
// that mZone_FreeRuns[ 0 ] is unused because no run will be zero
// bytes in size (and morkZone plans to complain about zero sizes).
protected: // zone utilities
mork_size zone_grow_at(morkEnv* ev, mork_size inNeededSize);
void* zone_new_chip(morkEnv* ev, mdb_size inSize); // alloc
morkHunk* zone_new_hunk(morkEnv* ev, mdb_size inRunSize); // alloc
// { ===== begin nsIMdbHeap methods =====
public:
virtual mdb_err Alloc(nsIMdbEnv* ev, // allocate a piece of memory
mdb_size inSize, // requested size of new memory block
void** outBlock); // memory block of inSize bytes, or nil
virtual mdb_err Free(nsIMdbEnv* ev, // free block allocated earlier by Alloc()
void* inBlock);
virtual mdb_err HeapAddStrongRef(nsIMdbEnv* ev); // does nothing
virtual mdb_err HeapCutStrongRef(nsIMdbEnv* ev); // does nothing
// } ===== end nsIMdbHeap methods =====
// { ===== begin morkNode interface =====
public: // morkNode virtual methods
virtual void CloseMorkNode(morkEnv* ev); // CloseZone() only if open
virtual ~morkZone(); // assert that CloseMap() executed earlier
public: // morkMap construction & destruction
morkZone(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioNodeHeap,
nsIMdbHeap* ioZoneHeap);
void CloseZone(morkEnv* ev); // called by CloseMorkNode()
public: // dynamic type identification
mork_bool IsZone() const
{ return IsNode() && mNode_Derived == morkDerived_kZone; }
// } ===== end morkNode methods =====
// { ===== begin morkZone methods =====
public: // chips do not know how big they are...
void* ZoneNewChip(morkEnv* ev, mdb_size inSize); // alloc
public: // ...but runs do indeed know how big they are
void* ZoneNewRun(morkEnv* ev, mdb_size inSize); // alloc
void ZoneZapRun(morkEnv* ev, void* ioRunBody); // free
void* ZoneGrowRun(morkEnv* ev, void* ioRunBody, mdb_size inSize); // realloc
// } ===== end morkZone methods =====
public: // typing & errors
static void NonZoneTypeError(morkEnv* ev);
static void NilZoneHeapError(morkEnv* ev);
static void BadZoneTagError(morkEnv* ev);
};
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
#endif /* _MORKZONE_ */