зеркало из https://github.com/mozilla/gecko-dev.git
incremental writing, memory leak fixed for davidmc
This commit is contained in:
Родитель
033a49841f
Коммит
3d0e42f707
|
@ -44,6 +44,10 @@ typedef mdb_u4 mdb_size; // unsigned physical media size
|
|||
typedef mdb_u4 mdb_fill; // unsigned logical content size
|
||||
typedef mdb_u4 mdb_more; // more available bytes for larger buffer
|
||||
|
||||
typedef mdb_u4 mdb_percent; // 0..100, with values >100 same as 100
|
||||
|
||||
typedef mdb_u1 mdb_priority; // 0..9, for a total of ten different values
|
||||
|
||||
// temporary substitute for NS_RESULT, for mdb.h standalone compilation:
|
||||
typedef mdb_u4 mdb_err; // equivalent to NS_RESULT
|
||||
|
||||
|
@ -311,6 +315,7 @@ class nsIMdbErrorHook;
|
|||
class nsIMdbCompare;
|
||||
class nsIMdbThumb;
|
||||
class nsIMdbFactory;
|
||||
class nsIMdbFile;
|
||||
class nsIMdbPort;
|
||||
class nsIMdbStore;
|
||||
class nsIMdbCursor;
|
||||
|
@ -544,6 +549,9 @@ public:
|
|||
virtual mdb_err GetWarningCount(mdb_count* outCount,
|
||||
mdb_bool* outShouldAbort) = 0;
|
||||
|
||||
virtual mdb_err GetEnvBeVerbose(mdb_bool* outBeVerbose) = 0;
|
||||
virtual mdb_err SetEnvBeVerbose(mdb_bool inBeVerbose) = 0;
|
||||
|
||||
virtual mdb_err GetDoTrace(mdb_bool* outDoTrace) = 0;
|
||||
virtual mdb_err SetDoTrace(mdb_bool inDoTrace) = 0;
|
||||
|
||||
|
@ -616,6 +624,26 @@ public:
|
|||
|
||||
// { ===== begin nsIMdbFactory methods =====
|
||||
|
||||
// { ----- begin file methods -----
|
||||
virtual mdb_err OpenOldFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, mdb_bool inFrozen, nsIMdbFile** acqFile) = 0;
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be open and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
|
||||
virtual mdb_err CreateNewFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, nsIMdbFile** acqFile) = 0;
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be created and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
// } ----- end file methods -----
|
||||
|
||||
// { ----- begin env methods -----
|
||||
virtual mdb_err MakeEnv(nsIMdbHeap* ioHeap, nsIMdbEnv** acqEnv) = 0; // acquire new env
|
||||
// ioHeap can be nil, causing a MakeHeap() style heap instance to be used
|
||||
|
@ -740,9 +768,9 @@ public:
|
|||
// { ===== begin nsIMdbFile methods =====
|
||||
|
||||
// { ----- begin pos methods -----
|
||||
virtual mdb_err Tell(nsIMdbEnv* ev, mdb_pos* outPos) const = 0;
|
||||
virtual mdb_err Tell(nsIMdbEnv* ev, mdb_pos* outPos) = 0;
|
||||
virtual mdb_err Seek(nsIMdbEnv* ev, mdb_pos inPos) = 0;
|
||||
virtual mdb_err Eof(nsIMdbEnv* ev, mdb_pos* outPos) const = 0;
|
||||
virtual mdb_err Eof(nsIMdbEnv* ev, mdb_pos* outPos) = 0;
|
||||
// } ----- end pos methods -----
|
||||
|
||||
// { ----- begin read methods -----
|
||||
|
@ -769,6 +797,34 @@ public:
|
|||
virtual mdb_err Thief(nsIMdbEnv* ev, nsIMdbFile** acqThief) = 0;
|
||||
// } ----- end replacement methods -----
|
||||
|
||||
// { ----- begin versioning methods -----
|
||||
virtual mdb_err BecomeTrunk(nsIMdbEnv* ev) = 0;
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
// file's content, typically by assuming the original file's identity.
|
||||
// This default implementation of BecomeTrunk() does nothing, and this
|
||||
// is appropriate behavior for files which are not branches, and is
|
||||
// also the right behavior for files returned from AcquireBud() which are
|
||||
// in fact the original file that has been truncated down to zero length.
|
||||
|
||||
virtual mdb_err AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
nsIMdbFile** acqBud) = 0; // acquired file for new version of content
|
||||
// AcquireBud() starts a new "branch" version of the file, empty of content,
|
||||
// so that a new version of the file can be written. This new file
|
||||
// can later be told to BecomeTrunk() the original file, so the branch
|
||||
// created by budding the file will replace the original file. Some
|
||||
// file subclasses might initially take the unsafe but expedient
|
||||
// approach of simply truncating this file down to zero length, and
|
||||
// then returning the same morkFile pointer as this, with an extra
|
||||
// reference count increment. Note that the caller of AcquireBud() is
|
||||
// expected to eventually call CutStrongRef() on the returned file
|
||||
// in order to release the strong reference. High quality versions
|
||||
// of morkFile subclasses will create entirely new files which later
|
||||
// are renamed to become the old file, so that better transactional
|
||||
// behavior is exhibited by the file, so crashes protect old files.
|
||||
// Note that AcquireBud() is an illegal operation on readonly files.
|
||||
// } ----- end versioning methods -----
|
||||
|
||||
// } ===== end nsIMdbFile methods =====
|
||||
};
|
||||
|
||||
|
@ -950,6 +1006,12 @@ public:
|
|||
const mdbOid* inOid, // hypothetical row oid
|
||||
nsIMdbRow** acqRow) = 0; // acquire specific row (or null)
|
||||
|
||||
// virtual mdb_err
|
||||
// GetPortRowCursor( // get cursor for all rows in specific scope
|
||||
// nsIMdbEnv* ev, // context
|
||||
// mdb_scope inRowScope, // row scope for row ids
|
||||
// nsIMdbPortRowCursor** acqCursor) = 0; // all such rows in the port
|
||||
|
||||
virtual mdb_err FindRow(nsIMdbEnv* ev, // 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)
|
||||
|
@ -1037,6 +1099,69 @@ public:
|
|||
nsIMdbPortTableCursor** acqCursor) = 0; // all such tables in the port
|
||||
// } ----- end table methods -----
|
||||
|
||||
|
||||
// { ----- begin commit methods -----
|
||||
|
||||
virtual mdb_err ShouldCompress( // store wastes at least inPercentWaste?
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_percent inPercentWaste, // 0..100 percent file size waste threshold
|
||||
mdb_percent* outActualWaste, // 0..100 percent of file actually wasted
|
||||
mdb_bool* outShould) = 0; // true when about inPercentWaste% is wasted
|
||||
// ShouldCompress() returns true if the store can determine that the file
|
||||
// will shrink by an estimated percentage of inPercentWaste% (or more) if
|
||||
// CompressCommit() is called, because that percentage of the file seems
|
||||
// to be recoverable free space. The granularity is only in terms of
|
||||
// percentage points, and any value over 100 is considered equal to 100.
|
||||
//
|
||||
// If a store only has an approximate idea how much space might be saved
|
||||
// during a compress, then a best guess should be made. For example, the
|
||||
// Mork implementation might keep track of how much file space began with
|
||||
// text content before the first updating transaction, and then consider
|
||||
// all content following the start of the first transaction as potentially
|
||||
// wasted space if it is all updates and not just new content. (This is
|
||||
// a safe assumption in the sense that behavior will stabilize on a low
|
||||
// estimate of wastage after a commit removes all transaction updates.)
|
||||
//
|
||||
// Some db formats might attempt to keep a very accurate reckoning of free
|
||||
// space size, so a very accurate determination can be made. But other db
|
||||
// formats might have difficulty determining size of free space, and might
|
||||
// require some lengthy calculation to answer. This is the reason for
|
||||
// passing in the percentage threshold of interest, so that such lengthy
|
||||
// computations can terminate early as soon as at least inPercentWaste is
|
||||
// found, so that the entire file need not be groveled when unnecessary.
|
||||
// However, we hope implementations will always favor fast but imprecise
|
||||
// heuristic answers instead of extremely slow but very precise answers.
|
||||
//
|
||||
// If the outActualWaste parameter is non-nil, it will be used to return
|
||||
// the actual estimated space wasted as a percentage of file size. (This
|
||||
// parameter is provided so callers need not call repeatedly with altered
|
||||
// inPercentWaste values to isolate the actual wastage figure.) Note the
|
||||
// actual wastage figure returned can exactly equal inPercentWaste even
|
||||
// when this grossly underestimates the real figure involved, if the db
|
||||
// finds it very expensive to determine the extent of wastage after it is
|
||||
// known to at least exceed inPercentWaste. Note we expect that whenever
|
||||
// outShould returns true, that outActualWaste returns >= inPercentWaste.
|
||||
//
|
||||
// The effect of different inPercentWaste values is not very uniform over
|
||||
// the permitted range. For example, 50 represents 50% wastage, or a file
|
||||
// that is about double what it should be ideally. But 99 represents 99%
|
||||
// wastage, or a file that is about ninety-nine times as big as it should
|
||||
// be ideally. In the smaller direction, 25 represents 25% wastage, or
|
||||
// a file that is only 33% larger than it should be ideally.
|
||||
//
|
||||
// Callers can determine what policy they want to use for considering when
|
||||
// a file holds too much wasted space, and express this as a percentage
|
||||
// of total file size to pass as in the inPercentWaste parameter. A zero
|
||||
// likely returns always trivially true, and 100 always trivially false.
|
||||
// The great majority of callers are expected to use values from 25 to 75,
|
||||
// since most plausible thresholds for compressing might fall between the
|
||||
// extremes of 133% of ideal size and 400% of ideal size. (Presumably the
|
||||
// larger a file gets, the more important the percentage waste involved, so
|
||||
// a sliding scale for compress thresholds might use smaller numbers for
|
||||
// much bigger file sizes.)
|
||||
|
||||
// } ----- end commit methods -----
|
||||
|
||||
// } ===== end nsIMdbPort methods =====
|
||||
};
|
||||
|
||||
|
@ -1208,6 +1333,7 @@ public:
|
|||
// 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.
|
||||
|
||||
// } ----- end commit methods -----
|
||||
|
||||
// } ===== end nsIMdbStore methods =====
|
||||
|
@ -1486,6 +1612,14 @@ public:
|
|||
// { ===== begin nsIMdbTable methods =====
|
||||
|
||||
// { ----- begin meta attribute methods -----
|
||||
virtual mdb_err SetTablePriority(nsIMdbEnv* ev, mdb_priority inPrio) = 0;
|
||||
virtual mdb_err GetTablePriority(nsIMdbEnv* ev, mdb_priority* outPrio) = 0;
|
||||
|
||||
virtual mdb_err GetTableBeVerbose(nsIMdbEnv* ev, mdb_bool* outBeVerbose) = 0;
|
||||
virtual mdb_err SetTableBeVerbose(nsIMdbEnv* ev, mdb_bool inBeVerbose) = 0;
|
||||
|
||||
virtual mdb_err GetTableIsUnique(nsIMdbEnv* ev, mdb_bool* outIsUnique) = 0;
|
||||
|
||||
virtual mdb_err GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind) = 0;
|
||||
virtual mdb_err GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope) = 0;
|
||||
|
||||
|
@ -1518,6 +1652,7 @@ public:
|
|||
// already given a different oid earlier.
|
||||
// } ----- end meta attribute methods -----
|
||||
|
||||
|
||||
// { ----- begin cursor methods -----
|
||||
virtual mdb_err GetTableRowCursor( // make a cursor, starting iteration at inRowPos
|
||||
nsIMdbEnv* ev, // context
|
||||
|
@ -1580,6 +1715,9 @@ public:
|
|||
virtual mdb_err CutRow( // make sure the row with inOid is not a member
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioRow) = 0; // row to remove from table
|
||||
|
||||
virtual mdb_err CutAllRows( // remove all rows from the table
|
||||
nsIMdbEnv* ev) = 0; // context
|
||||
// } ----- end row set methods -----
|
||||
|
||||
// { ----- begin searching methods -----
|
||||
|
|
|
@ -91,6 +91,8 @@ typedef mork_u4 mork_size; // unsigned physical media size
|
|||
typedef mork_u4 mork_fill; // unsigned logical content size
|
||||
typedef mork_u4 mork_more; // more available bytes for larger buffer
|
||||
|
||||
typedef mdb_u4 mork_percent; // 0..100, with values >100 same as 100
|
||||
|
||||
typedef mork_i4 mork_pos; // negative means "before first" (at zero pos)
|
||||
typedef mork_i4 mork_line; // negative means "before first line in file"
|
||||
|
||||
|
@ -98,12 +100,21 @@ typedef mork_u1 mork_usage; // 1-byte magic usage signature slot in object
|
|||
typedef mork_u1 mork_access; // 1-byte magic access signature slot in object
|
||||
|
||||
typedef mork_u1 mork_change; // add, cut, put, set, nil
|
||||
typedef mork_u1 mork_priority; // 0..9, for a total of ten different values
|
||||
|
||||
typedef mork_u1 mork_able; // on, off, asleep (clone IronDoc's fe_able)
|
||||
typedef mork_u1 mork_load; // dirty or clean (clone IronDoc's fe_load)
|
||||
// } %%%%% end specific-size integer scalar typedefs %%%%%
|
||||
|
||||
// { %%%%% begin constants for Mork scalar types %%%%%
|
||||
#define morkPriority_kHi ((mork_priority) 0) /* best priority */
|
||||
#define morkPriority_kMin ((mork_priority) 0) /* best priority is smallest */
|
||||
|
||||
#define morkPriority_kLo ((mork_priority) 9) /* worst priority */
|
||||
#define morkPriority_kMax ((mork_priority) 9) /* worst priority is biggest */
|
||||
|
||||
#define morkPriority_kCount 10 /* number of distinct priority values */
|
||||
|
||||
#define morkAble_kEnabled ((mork_able) 0x55) /* same as IronDoc constant */
|
||||
#define morkAble_kDisabled ((mork_able) 0xAA) /* same as IronDoc constant */
|
||||
#define morkAble_kAsleep ((mork_able) 0x5A) /* same as IronDoc constant */
|
||||
|
@ -188,6 +199,7 @@ class morkSpan;
|
|||
class morkStore;
|
||||
class morkStream;
|
||||
class morkTable;
|
||||
class morkTableChange;
|
||||
class morkTableRowCursor;
|
||||
class morkThumb;
|
||||
class morkWriter;
|
||||
|
|
|
@ -88,7 +88,7 @@ morkAtom::GetYarn(mdbYarn* outYarn) const
|
|||
mdb_size size = outYarn->mYarn_Size; // max dest size
|
||||
if ( fill > size ) // too much atom content?
|
||||
{
|
||||
outYarn->mYarn_More = size - fill; // extra atom bytes omitted
|
||||
outYarn->mYarn_More = fill - size; // extra atom bytes omitted
|
||||
fill = size; // copy no more bytes than size of yarn buffer
|
||||
}
|
||||
void* dest = outYarn->mYarn_Buf; // where bytes are going
|
||||
|
|
|
@ -60,6 +60,14 @@ public:
|
|||
|
||||
mork_bool IsBook() const { return this->IsWeeBook() || this->IsBigBook(); }
|
||||
|
||||
public: // clean vs dirty
|
||||
|
||||
void SetAtomClean() { mAtom_Change = morkChange_kNil; }
|
||||
void SetAtomDirty() { mAtom_Change = morkChange_kAdd; }
|
||||
|
||||
mork_bool IsAtomClean() const { return mAtom_Change == morkChange_kNil; }
|
||||
mork_bool IsAtomDirty() const { return mAtom_Change == morkChange_kAdd; }
|
||||
|
||||
public: // atom space scope if IsBook() is true, or else zero:
|
||||
|
||||
mork_scope GetBookAtomSpaceScope(morkEnv* ev) const;
|
||||
|
@ -79,8 +87,6 @@ public: // one-byte refcounting, freezing at maximum
|
|||
mork_bool IsCellUseForever() const
|
||||
{ return mAtom_CellUses == morkAtom_kForeverCellUses; }
|
||||
|
||||
void SetAtomDirty() { mAtom_Change = morkChange_kAdd; }
|
||||
|
||||
private: // warnings
|
||||
|
||||
static void CellUsesUnderflowWarning(morkEnv* ev);
|
||||
|
|
|
@ -96,6 +96,7 @@ morkAtomSpace::morkAtomSpace(morkEnv* ev, const morkUsage& inUsage,
|
|||
, mAtomSpace_AtomAids(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap)
|
||||
, mAtomSpace_AtomBodies(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap)
|
||||
{
|
||||
// the morkSpace base constructor handles any dirty propagation
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kAtomSpace;
|
||||
}
|
||||
|
@ -137,6 +138,9 @@ morkAtomSpace::NonAtomSpaceTypeError(morkEnv* ev)
|
|||
mork_num
|
||||
morkAtomSpace::CutAllAtoms(morkEnv* ev, morkPool* ioPool)
|
||||
{
|
||||
if ( this->IsAtomSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
|
||||
mork_num outSlots = mAtomSpace_AtomAids.mMap_Fill;
|
||||
morkBookAtom* a = 0; // old key atom in the map
|
||||
|
||||
|
@ -165,6 +169,13 @@ morkAtomSpace::MakeBookAtomCopyWithAid(morkEnv* ev,
|
|||
outAtom = pool->NewBookAtomCopy(ev, inAtom);
|
||||
if ( outAtom )
|
||||
{
|
||||
if ( mSpace_Store->mStore_CanDirty )
|
||||
{
|
||||
outAtom->SetAtomDirty();
|
||||
if ( this->IsAtomSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
}
|
||||
|
||||
outAtom->mBookAtom_Id = inAid;
|
||||
outAtom->mBookAtom_Space = this;
|
||||
mAtomSpace_AtomAids.AddAtom(ev, outAtom);
|
||||
|
@ -184,9 +195,10 @@ morkAtomSpace::MakeBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom)
|
|||
// make copy of inAtom and put it in both maps, using a new ID as needed.
|
||||
{
|
||||
morkBookAtom* outAtom = 0;
|
||||
if ( ev->Good() )
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( ev->Good() && store )
|
||||
{
|
||||
if ( mSpace_Store->mStore_CanAutoAssignAtomIdentity )
|
||||
if ( store->mStore_CanAutoAssignAtomIdentity )
|
||||
{
|
||||
morkPool* pool = this->GetSpaceStorePool();
|
||||
morkBookAtom* atom = pool->NewBookAtomCopy(ev, inAtom);
|
||||
|
@ -195,6 +207,13 @@ morkAtomSpace::MakeBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom)
|
|||
mork_aid id = this->MakeNewAtomId(ev, atom);
|
||||
if ( id )
|
||||
{
|
||||
if ( store->mStore_CanDirty )
|
||||
{
|
||||
atom->SetAtomDirty();
|
||||
if ( this->IsAtomSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
}
|
||||
|
||||
outAtom = atom;
|
||||
atom->mBookAtom_Space = this;
|
||||
mAtomSpace_AtomAids.AddAtom(ev, atom);
|
||||
|
|
|
@ -99,6 +99,13 @@ public: // state is public because the entire Mork system is private
|
|||
morkAtomAidMap mAtomSpace_AtomAids; // all atoms in space by ID
|
||||
morkAtomBodyMap mAtomSpace_AtomBodies; // all atoms in space by body
|
||||
|
||||
public: // more specific dirty methods for atom space:
|
||||
void SetAtomSpaceDirty() { this->SetNodeDirty(); }
|
||||
void SetAtomSpaceClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsAtomSpaceClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsAtomSpaceDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseAtomSpace() only if open
|
||||
|
|
|
@ -133,6 +133,11 @@ morkBuilder::morkBuilder(morkEnv* ev,
|
|||
, mBuilder_TableAtomScope( (mork_scope) 'v' )
|
||||
, mBuilder_TableKind( 0 )
|
||||
|
||||
, mBuilder_TablePriority( morkPriority_kLo )
|
||||
, mBuilder_TableIsUnique( morkBool_kFalse )
|
||||
, mBuilder_TableIsVerbose( morkBool_kFalse )
|
||||
, mBuilder_TablePadByte( 0 )
|
||||
|
||||
, mBuilder_RowForm( 0 )
|
||||
, mBuilder_RowRowScope( (mork_scope) 'r' )
|
||||
, mBuilder_RowAtomScope( (mork_scope) 'v' )
|
||||
|
@ -283,9 +288,21 @@ morkBuilder::OnPortEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
/*virtual*/ void
|
||||
morkBuilder::OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid)
|
||||
{
|
||||
MORK_USED_2(inPlace,inGid);
|
||||
MORK_USED_1(inPlace);
|
||||
// mParser_InGroup = morkBool_kTrue;
|
||||
ev->StubMethodOnlyError();
|
||||
mork_pos startPos = inPlace.mPlace_Pos;
|
||||
|
||||
morkStore* store = mBuilder_Store;
|
||||
if ( store )
|
||||
{
|
||||
if ( inGid >= store->mStore_CommitGroupIdentity )
|
||||
store->mStore_CommitGroupIdentity = inGid + 1;
|
||||
|
||||
if ( !store->mStore_FirstCommitGroupPos )
|
||||
store->mStore_FirstCommitGroupPos = startPos;
|
||||
else if ( !store->mStore_SecondCommitGroupPos )
|
||||
store->mStore_SecondCommitGroupPos = startPos;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
|
@ -297,9 +314,9 @@ morkBuilder::OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch)
|
|||
/*virtual*/ void
|
||||
morkBuilder::OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan)
|
||||
{
|
||||
MORK_USED_1(inSpan);
|
||||
MORK_USED_2(ev,inSpan);
|
||||
// mParser_InGroup = morkBool_kFalse;
|
||||
ev->StubMethodOnlyError();
|
||||
// ev->StubMethodOnlyError();
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
|
@ -335,24 +352,35 @@ morkBuilder::OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnNewTable(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange)
|
||||
const morkMid& inMid, mork_bool inCutAllRows)
|
||||
// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd
|
||||
// mp:TableItem ::= mp:Row | mp:MetaTable | OnTableGlitch
|
||||
// mp:MetaTable ::= OnNewMeta mp:MetaItem* mp:Row OnMetaEnd
|
||||
// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd
|
||||
// mp:MetaItem ::= mp:Cell | OnMetaGlitch
|
||||
{
|
||||
MORK_USED_2(inPlace,inChange);
|
||||
MORK_USED_1(inPlace);
|
||||
// mParser_InTable = morkBool_kTrue;
|
||||
mBuilder_TableForm = mBuilder_PortForm;
|
||||
mBuilder_TableRowScope = mBuilder_PortRowScope;
|
||||
mBuilder_TableAtomScope = mBuilder_PortAtomScope;
|
||||
mBuilder_TableKind = morkStore_kNoneToken;
|
||||
|
||||
mBuilder_TablePriority = morkPriority_kLo;
|
||||
mBuilder_TableIsUnique = morkBool_kFalse;
|
||||
mBuilder_TableIsVerbose = morkBool_kFalse;
|
||||
|
||||
morkTable* table = mBuilder_Store->MidToTable(ev, inMid);
|
||||
morkTable::SlotStrongTable(table, ev, &mBuilder_Table);
|
||||
if ( table && table->mTable_RowSpace )
|
||||
mBuilder_TableRowScope = table->mTable_RowSpace->mSpace_Scope;}
|
||||
if ( table )
|
||||
{
|
||||
if ( table->mTable_RowSpace )
|
||||
mBuilder_TableRowScope = table->mTable_RowSpace->mSpace_Scope;
|
||||
|
||||
if ( inCutAllRows )
|
||||
table->CutAllRows(ev);
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch)
|
||||
|
@ -368,6 +396,14 @@ morkBuilder::OnTableEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
// mParser_InTable = morkBool_kFalse;
|
||||
if ( mBuilder_Table )
|
||||
{
|
||||
mBuilder_Table->mTable_Priority = mBuilder_TablePriority;
|
||||
|
||||
if ( mBuilder_TableIsUnique )
|
||||
mBuilder_Table->SetTableUnique();
|
||||
|
||||
if ( mBuilder_TableIsVerbose )
|
||||
mBuilder_Table->SetTableVerbose();
|
||||
|
||||
morkTable::SlotStrongTable((morkTable*) 0, ev, &mBuilder_Table);
|
||||
}
|
||||
else
|
||||
|
@ -376,18 +412,26 @@ morkBuilder::OnTableEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
mBuilder_Row = 0;
|
||||
mBuilder_Cell = 0;
|
||||
|
||||
|
||||
mBuilder_TablePriority = morkPriority_kLo;
|
||||
mBuilder_TableIsUnique = morkBool_kFalse;
|
||||
mBuilder_TableIsVerbose = morkBool_kFalse;
|
||||
|
||||
if ( mBuilder_TableKind == morkStore_kNoneToken )
|
||||
ev->NewError("missing table kind");
|
||||
|
||||
mBuilder_CellAtomScope = mBuilder_RowAtomScope =
|
||||
mBuilder_TableAtomScope = mBuilder_PortAtomScope;
|
||||
|
||||
mBuilder_DoCutCell = morkBool_kFalse;
|
||||
mBuilder_DoCutRow = morkBool_kFalse;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnNewMeta(morkEnv* ev, const morkPlace& inPlace)
|
||||
// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd
|
||||
// mp:MetaItem ::= mp:Cell | OnMetaGlitch
|
||||
// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
|
||||
// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
|
||||
{
|
||||
|
@ -410,22 +454,28 @@ morkBuilder::OnMetaEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
// mParser_InMeta = morkBool_kFalse;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnMinusRow(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mBuilder_DoCutRow = morkBool_kTrue;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnNewRow(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange)
|
||||
const morkMid& inMid, mork_bool inCutAllCols)
|
||||
// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd
|
||||
// mp:TableItem ::= mp:Row | mp:MetaTable | OnTableGlitch
|
||||
// mp:MetaTable ::= OnNewMeta mp:MetaItem* mp:Row OnMetaEnd
|
||||
// mp:Row ::= OnNewRow mp:RowItem* OnRowEnd
|
||||
// mp:Row ::= OnMinusRow? OnNewRow mp:RowItem* OnRowEnd
|
||||
// mp:RowItem ::= mp:Cell | mp:Meta | OnRowGlitch
|
||||
// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
|
||||
// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
|
||||
{
|
||||
MORK_USED_2(inPlace,inChange);
|
||||
MORK_USED_1(inPlace);
|
||||
// mParser_InRow = morkBool_kTrue;
|
||||
if ( mBuilder_Table )
|
||||
{
|
||||
|
||||
mBuilder_CellForm = mBuilder_RowForm = mBuilder_TableForm;
|
||||
mBuilder_CellAtomScope = mBuilder_RowAtomScope = mBuilder_TableAtomScope;
|
||||
mBuilder_RowRowScope = mBuilder_TableRowScope;
|
||||
|
@ -441,28 +491,42 @@ morkBuilder::OnNewRow(morkEnv* ev, const morkPlace& inPlace,
|
|||
{
|
||||
mBuilder_Row = store->MidToRow(ev, inMid);
|
||||
}
|
||||
|
||||
morkRow* row = mBuilder_Row;
|
||||
if ( row && inCutAllCols )
|
||||
{
|
||||
row->CutAllColumns(ev);
|
||||
}
|
||||
|
||||
morkTable* table = mBuilder_Table;
|
||||
if ( table )
|
||||
{
|
||||
if ( row )
|
||||
{
|
||||
morkTable* table = mBuilder_Table;
|
||||
if ( mParser_InMeta )
|
||||
{
|
||||
if ( !table->mTable_MetaRow )
|
||||
morkRow* metaRow = table->mTable_MetaRow;
|
||||
if ( !metaRow )
|
||||
{
|
||||
table->mTable_MetaRow = row;
|
||||
table->mTable_MetaRowOid = row->mRow_Oid;
|
||||
row->AddTableUse(ev);
|
||||
row->AddRowGcUse(ev);
|
||||
}
|
||||
else
|
||||
else if ( metaRow != row ) // not identical?
|
||||
ev->NewError("duplicate table meta row");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mBuilder_DoCutRow )
|
||||
table->CutRow(ev, row);
|
||||
else
|
||||
table->AddRow(ev, row);
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilBuilderTableError(ev);
|
||||
}
|
||||
// else // it is now okay to have rows outside a table:
|
||||
// this->NilBuilderTableError(ev);
|
||||
|
||||
mBuilder_DoCutRow = morkBool_kFalse;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
|
@ -496,7 +560,7 @@ morkBuilder::FlushBuilderCells(morkEnv* ev)
|
|||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnRowEnd(morkEnv* ev, const morkSpan& inSpan)
|
||||
// mp:Row ::= OnNewRow mp:RowItem* OnRowEnd
|
||||
// mp:Row ::= OnMinusRow? OnNewRow mp:RowItem* OnRowEnd
|
||||
{
|
||||
MORK_USED_1(inSpan);
|
||||
// mParser_InRow = morkBool_kFalse;
|
||||
|
@ -509,6 +573,9 @@ morkBuilder::OnRowEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
|
||||
mBuilder_Row = 0;
|
||||
mBuilder_Cell = 0;
|
||||
|
||||
mBuilder_DoCutCell = morkBool_kFalse;
|
||||
mBuilder_DoCutRow = morkBool_kFalse;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
|
@ -589,20 +656,32 @@ morkBuilder::AddBuilderCell(morkEnv* ev,
|
|||
return outCell;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnMinusCell(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mBuilder_DoCutCell = morkBool_kTrue;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid* inMid, const morkBuf* inBuf, mork_change inChange)
|
||||
const morkMid* inMid, const morkBuf* inBuf)
|
||||
// Exactly one of inMid and inBuf is nil, and the other is non-nil.
|
||||
// When hex ID syntax is used for a column, then inMid is not nil, and
|
||||
// when a naked string names a column, then inBuf is not nil.
|
||||
|
||||
// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
|
||||
// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
|
||||
{
|
||||
MORK_USED_1(inPlace);
|
||||
// mParser_InCell = morkBool_kTrue;
|
||||
|
||||
mork_change cellChange = ( mBuilder_DoCutCell )?
|
||||
morkChange_kCut : morkChange_kAdd;
|
||||
|
||||
mBuilder_DoCutCell = morkBool_kFalse;
|
||||
|
||||
mBuilder_CellAtomScope = mBuilder_RowAtomScope;
|
||||
|
||||
mBuilder_Cell = 0; // nil until determined for a row
|
||||
|
@ -639,7 +718,7 @@ morkBuilder::OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
|||
|
||||
if ( mBuilder_Row && ev->Good() ) // this cell must be inside a row
|
||||
{
|
||||
// mBuilder_Cell = this->AddBuilderCell(ev, *cellMid, inChange);
|
||||
// mBuilder_Cell = this->AddBuilderCell(ev, *cellMid, cellChange);
|
||||
|
||||
if ( mBuilder_CellsVecFill >= morkBuilder_kCellsVecSize )
|
||||
this->FlushBuilderCells(ev);
|
||||
|
@ -647,9 +726,10 @@ morkBuilder::OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
|||
{
|
||||
if ( mBuilder_CellsVecFill < morkBuilder_kCellsVecSize )
|
||||
{
|
||||
mork_fill indx = mBuilder_CellsVecFill++;
|
||||
morkCell* cell = mBuilder_CellsVec + indx;
|
||||
cell->SetColumnAndChange(column, inChange);
|
||||
mork_fill ix = mBuilder_CellsVecFill++;
|
||||
morkCell* cell = mBuilder_CellsVec + ix;
|
||||
cell->SetColumnAndChange(column, cellChange);
|
||||
|
||||
cell->mCell_Atom = 0;
|
||||
mBuilder_Cell = cell;
|
||||
}
|
||||
|
@ -666,6 +746,8 @@ morkBuilder::OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
|||
{
|
||||
if ( column == morkStore_kKindColumn )
|
||||
mBuilder_MetaTokenSlot = &mBuilder_TableKind;
|
||||
else if ( column == morkStore_kStatusColumn )
|
||||
mBuilder_MetaTokenSlot = &mBuilder_TableStatus;
|
||||
else if ( column == morkStore_kRowScopeColumn )
|
||||
mBuilder_MetaTokenSlot = &mBuilder_TableRowScope;
|
||||
else if ( column == morkStore_kAtomScopeColumn )
|
||||
|
@ -715,7 +797,7 @@ morkBuilder::OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat)
|
|||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnCellEnd(morkEnv* ev, const morkSpan& inSpan)
|
||||
// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
|
||||
{
|
||||
MORK_USED_2(ev,inSpan);
|
||||
// mParser_InCell = morkBool_kFalse;
|
||||
|
@ -748,6 +830,49 @@ morkBuilder::OnValue(morkEnv* ev, const morkSpan& inSpan,
|
|||
{
|
||||
mork_token* metaSlot = mBuilder_MetaTokenSlot;
|
||||
if ( metaSlot )
|
||||
{
|
||||
if ( metaSlot == &mBuilder_TableStatus ) // table status?
|
||||
{
|
||||
if ( mParser_InTable && mBuilder_Table )
|
||||
{
|
||||
const char* body = (const char*) inBuf.mBuf_Body;
|
||||
mork_fill bufFill = inBuf.mBuf_Fill;
|
||||
if ( body && bufFill )
|
||||
{
|
||||
const char* bodyEnd = body + bufFill;
|
||||
while ( body < bodyEnd )
|
||||
{
|
||||
int c = *body++;
|
||||
switch ( c )
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
mBuilder_TablePriority = (mork_priority) ( c - '0' );
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'U':
|
||||
mBuilder_TableIsUnique = morkBool_kTrue;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
case 'V':
|
||||
mBuilder_TableIsVerbose = morkBool_kTrue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mork_token token = store->BufToToken(ev, &inBuf);
|
||||
if ( token )
|
||||
|
@ -761,6 +886,7 @@ morkBuilder::OnValue(morkEnv* ev, const morkSpan& inSpan,
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilBuilderCellError(ev);
|
||||
}
|
||||
|
@ -815,6 +941,15 @@ morkBuilder::OnValueMid(morkEnv* ev, const morkSpan& inSpan,
|
|||
else
|
||||
ev->NewWarning("mBuilder_TableKind not in table");
|
||||
}
|
||||
else if ( metaSlot == &mBuilder_TableStatus ) // table status?
|
||||
{
|
||||
if ( mParser_InTable && mBuilder_Table )
|
||||
{
|
||||
// $$ what here??
|
||||
}
|
||||
else
|
||||
ev->NewWarning("mBuilder_TableStatus not in table");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -854,7 +989,7 @@ morkBuilder::OnRowMid(morkEnv* ev, const morkSpan& inSpan,
|
|||
cell->SetAtom(ev, atom, pool);
|
||||
morkRow* row = store->OidToRow(ev, &rowOid);
|
||||
if ( row ) // found or created such a row?
|
||||
row->AddTableUse(ev);
|
||||
row->AddRowGcUse(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -892,7 +1027,7 @@ morkBuilder::OnTableMid(morkEnv* ev, const morkSpan& inSpan,
|
|||
morkTable* table = store->OidToTable(ev, &tableOid,
|
||||
/*optionalMetaRowOid*/ (mdbOid*) 0);
|
||||
if ( table ) // found or created such a table?
|
||||
table->AddCellUse(ev);
|
||||
table->AddTableGcUse(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,6 +139,13 @@ protected: // protected morkBuilder members
|
|||
mork_scope mBuilder_TableAtomScope; // table atom scope
|
||||
mork_kind mBuilder_TableKind; // table kind
|
||||
|
||||
mork_token mBuilder_TableStatus; // dummy: priority/unique/verbose
|
||||
|
||||
mork_priority mBuilder_TablePriority; // table priority
|
||||
mork_bool mBuilder_TableIsUnique; // table uniqueness
|
||||
mork_bool mBuilder_TableIsVerbose; // table verboseness
|
||||
mork_u1 mBuilder_TablePadByte; // for u4 alignment
|
||||
|
||||
// tokens that become set as the result of meta cells in meta rows:
|
||||
mork_cscode mBuilder_RowForm; // default row charset format
|
||||
mork_scope mBuilder_RowRowScope; // row scope per row metainfo
|
||||
|
@ -160,8 +167,8 @@ protected: // protected morkBuilder members
|
|||
// CutCell implies the current column should be cut from the row.
|
||||
mork_bool mBuilder_DoCutRow; // row with kCut change
|
||||
mork_bool mBuilder_DoCutCell; // cell with kCut change
|
||||
mork_u1 mBuilder_Pad1; // pad to u4 alignment
|
||||
mork_u1 mBuilder_Pad2; // pad to u4 alignment
|
||||
mork_u1 mBuilder_row_pad; // pad to u4 alignment
|
||||
mork_u1 mBuilder_cell_pad; // pad to u4 alignment
|
||||
|
||||
morkCell mBuilder_CellsVec[ morkBuilder_kCellsVecSize + 1 ];
|
||||
mork_fill mBuilder_CellsVecFill; // count used in CellsVec
|
||||
|
@ -243,7 +250,7 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange);
|
||||
const morkMid& inMid, mork_bool inCutAllRows);
|
||||
virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
|
@ -251,8 +258,9 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnMinusRow(morkEnv* ev);
|
||||
virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange);
|
||||
const morkMid& inMid, mork_bool inCutAllCols);
|
||||
virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
|
@ -265,8 +273,9 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
|
||||
virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
|
||||
virtual void OnMinusCell(morkEnv* ev);
|
||||
virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid* inMid, const morkBuf* inBuf, mork_change inChange);
|
||||
const morkMid* inMid, const morkBuf* inBuf);
|
||||
// Exactly one of inMid and inBuf is nil, and the other is non-nil.
|
||||
// When hex ID syntax is used for a column, then inMid is not nil, and
|
||||
// when a naked string names a column, then inBuf is not nil.
|
||||
|
|
|
@ -69,6 +69,13 @@ morkCell::AliasYarn(morkEnv* ev, mdbYarn* outYarn) const
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
morkCell::SetCellClean()
|
||||
{
|
||||
mork_column col = this->GetColumn();
|
||||
this->SetColumnAndChange(col, morkChange_kNil);
|
||||
}
|
||||
|
||||
void
|
||||
morkCell::SetCellDirty()
|
||||
{
|
||||
|
|
|
@ -61,7 +61,17 @@ public:
|
|||
mork_column GetColumn() const { return morkDelta_Column(mCell_Delta); }
|
||||
mork_change GetChange() const { return morkDelta_Change(mCell_Delta); }
|
||||
|
||||
void SetCellDirty();
|
||||
mork_bool IsCellClean() const { return GetChange() == morkChange_kNil; }
|
||||
mork_bool IsCellDirty() const { return GetChange() != morkChange_kNil; }
|
||||
|
||||
void SetCellClean(); // set change to kNil
|
||||
void SetCellDirty(); // set change to kAdd
|
||||
|
||||
void SetCellColumnDirty(mork_column inCol)
|
||||
{ this->SetColumnAndChange(inCol, morkChange_kAdd); }
|
||||
|
||||
void SetCellColumnClean(mork_column inCol)
|
||||
{ this->SetColumnAndChange(inCol, morkChange_kNil); }
|
||||
|
||||
void SetColumnAndChange(mork_column inCol, mork_change inChange)
|
||||
{ morkDelta_Init(mCell_Delta, inCol, inChange); }
|
||||
|
|
|
@ -25,6 +25,10 @@ which are used interchangeably with the name IronDoc in the sources.)
|
|||
* There are no warranties, no guarantees, no promises, and no remedies.
|
||||
*/
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
@ -33,6 +37,174 @@ which are used interchangeably with the name IronDoc in the sources.)
|
|||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
/*=============================================================================
|
||||
* morkNext: linked list node for very simple, singly-linked list
|
||||
*/
|
||||
|
||||
morkNext::morkNext() : mNext_Link( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
/*static*/ void*
|
||||
morkNext::MakeNewNext(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{
|
||||
void* next = 0;
|
||||
if ( &ioHeap )
|
||||
{
|
||||
ioHeap.Alloc(ev->AsMdbEnv(), inSize, (void**) &next);
|
||||
if ( !next )
|
||||
ev->OutOfMemoryError();
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void morkNext::ZapOldNext(morkEnv* ev, nsIMdbHeap* ioHeap)
|
||||
{
|
||||
if ( &ioHeap )
|
||||
{
|
||||
if ( this )
|
||||
ioHeap->Free(ev->AsMdbEnv(), this);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
/*=============================================================================
|
||||
* morkList: simple, singly-linked list
|
||||
*/
|
||||
|
||||
morkList::morkList() : mList_Head( 0 ), mList_Tail( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void morkList::CutAndZapAllListMembers(morkEnv* ev, nsIMdbHeap* ioHeap)
|
||||
// make empty list, zapping every member by calling ZapOldNext()
|
||||
{
|
||||
if ( ioHeap )
|
||||
{
|
||||
morkNext* next = 0;
|
||||
while ( (next = this->PopHead()) != 0 )
|
||||
next->ZapOldNext(ev, ioHeap);
|
||||
|
||||
mList_Head = 0;
|
||||
mList_Tail = 0;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
void morkList::CutAllListMembers()
|
||||
// just make list empty, dropping members without zapping
|
||||
{
|
||||
while ( this->PopHead() )
|
||||
/* empty */;
|
||||
|
||||
mList_Head = 0;
|
||||
mList_Tail = 0;
|
||||
}
|
||||
|
||||
morkNext* morkList::PopHead() // cut head of list
|
||||
{
|
||||
morkNext* outHead = mList_Head;
|
||||
if ( outHead ) // anything to cut from list?
|
||||
{
|
||||
morkNext* next = outHead->mNext_Link;
|
||||
mList_Head = next;
|
||||
if ( !next ) // cut the last member, so tail no longer exists?
|
||||
mList_Tail = 0;
|
||||
|
||||
outHead->mNext_Link = 0; // nil outgoing node link; unnecessary, but tidy
|
||||
}
|
||||
return outHead;
|
||||
}
|
||||
|
||||
|
||||
void morkList::PushHead(morkNext* ioLink) // add to head of list
|
||||
{
|
||||
morkNext* head = mList_Head; // old head of list
|
||||
morkNext* tail = mList_Tail; // old tail of list
|
||||
|
||||
MORK_ASSERT( (head && tail) || (!head && !tail));
|
||||
|
||||
ioLink->mNext_Link = head; // make old head follow the new link
|
||||
if ( !head ) // list was previously empty?
|
||||
mList_Tail = ioLink; // head is also tail for first member added
|
||||
|
||||
mList_Head = ioLink; // head of list is the new link
|
||||
}
|
||||
|
||||
void morkList::PushTail(morkNext* ioLink) // add to tail of list
|
||||
{
|
||||
morkNext* head = mList_Head; // old head of list
|
||||
morkNext* tail = mList_Tail; // old tail of list
|
||||
|
||||
MORK_ASSERT( (head && tail) || (!head && !tail));
|
||||
|
||||
ioLink->mNext_Link = tail; // make old tail follow the new link
|
||||
if ( !tail ) // list was previously empty?
|
||||
mList_Head = ioLink; // tail is also head for first member added
|
||||
|
||||
mList_Tail = ioLink; // tail of list is the new link
|
||||
}
|
||||
|
||||
/*=============================================================================
|
||||
* morkLink: linked list node embedded in objs to allow insertion in morkDeques
|
||||
*/
|
||||
|
||||
morkLink::morkLink() : mLink_Next( 0 ), mLink_Prev( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
/*static*/ void*
|
||||
morkLink::MakeNewLink(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{
|
||||
void* link = 0;
|
||||
if ( &ioHeap )
|
||||
{
|
||||
ioHeap.Alloc(ev->AsMdbEnv(), inSize, (void**) &link);
|
||||
if ( !link )
|
||||
ev->OutOfMemoryError();
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void morkLink::ZapOldLink(morkEnv* ev, nsIMdbHeap* ioHeap)
|
||||
{
|
||||
if ( &ioHeap )
|
||||
{
|
||||
if ( this )
|
||||
ioHeap->Free(ev->AsMdbEnv(), this);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
/*=============================================================================
|
||||
* morkDeque: doubly linked list modeled after VAX queue instructions
|
||||
*/
|
||||
|
||||
morkDeque::morkDeque()
|
||||
{
|
||||
mDeque_Head.SelfRefer();
|
||||
}
|
||||
|
||||
|
||||
/*| RemoveFirst:
|
||||
|*/
|
||||
morkLink*
|
||||
|
|
|
@ -32,6 +32,81 @@ which are used interchangeably with the name IronDoc in the sources.)
|
|||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
/*=============================================================================
|
||||
* morkNext: linked list node for very simple, singly-linked list
|
||||
*/
|
||||
|
||||
class morkNext /*d*/ {
|
||||
public:
|
||||
morkNext* mNext_Link;
|
||||
|
||||
public:
|
||||
morkNext(int inZero) : mNext_Link( 0 ) { }
|
||||
|
||||
morkNext(morkNext* ioLink) : mNext_Link( ioLink ) { }
|
||||
|
||||
morkNext(); // mNext_Link( 0 ), { }
|
||||
|
||||
public:
|
||||
morkNext* GetNextLink() const { return mNext_Link; }
|
||||
|
||||
public: // link memory management methods
|
||||
static void* MakeNewNext(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev);
|
||||
void ZapOldNext(morkEnv* ev, nsIMdbHeap* ioHeap);
|
||||
|
||||
public: // link memory management operators
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{ return morkNext::MakeNewNext(inSize, ioHeap, ev); }
|
||||
|
||||
void operator delete(void* ioAddress) // DO NOT CALL THIS, hope to crash:
|
||||
{ ((morkNext*) 0)->ZapOldNext((morkEnv*) 0, (nsIMdbHeap*) 0); } // boom
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkList: simple, singly-linked list
|
||||
*/
|
||||
|
||||
/*| morkList: a list of singly-linked members (instances of morkNext), where
|
||||
**| the number of list members might be so numerous that we must about cost
|
||||
**| for two pointer link slots per member (as happens with morkLink).
|
||||
**|
|
||||
**|| morkList is intended to support lists of changes in morkTable, where we
|
||||
**| are worried about the space cost of representing such changes. (Later we
|
||||
**| can use an array instead, when we get even more worried, to avoid cost
|
||||
**| of link slots at all, per member).
|
||||
**|
|
||||
**|| Do NOT create cycles in links using this list class, since we do not
|
||||
**| deal with them very nicely.
|
||||
|*/
|
||||
class morkList /*d*/ {
|
||||
public:
|
||||
morkNext* mList_Head; // first link in the list
|
||||
morkNext* mList_Tail; // last link in the list
|
||||
|
||||
public:
|
||||
morkNext* GetListHead() const { return mList_Head; }
|
||||
morkNext* GetListTail() const { return mList_Tail; }
|
||||
|
||||
mork_bool IsListEmpty() const { return ( mList_Head == 0 ); }
|
||||
|
||||
public:
|
||||
morkList(); // : mList_Head( 0 ), mList_Tail( 0 ) { }
|
||||
|
||||
void CutAndZapAllListMembers(morkEnv* ev, nsIMdbHeap* ioHeap);
|
||||
// make empty list, zapping every member by calling ZapOldNext()
|
||||
|
||||
void CutAllListMembers();
|
||||
// just make list empty, dropping members without zapping
|
||||
|
||||
public:
|
||||
morkNext* PopHead(); // cut head of list
|
||||
|
||||
// Note we don't support PopTail(), so use morkDeque if you need that.
|
||||
|
||||
void PushHead(morkNext* ioLink); // add to head of list
|
||||
void PushTail(morkNext* ioLink); // add to tail of list
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkLink: linked list node embedded in objs to allow insertion in morkDeques
|
||||
*/
|
||||
|
@ -41,6 +116,11 @@ public:
|
|||
morkLink* mLink_Next;
|
||||
morkLink* mLink_Prev;
|
||||
|
||||
public:
|
||||
morkLink(int inZero) : mLink_Next( 0 ), mLink_Prev( 0 ) { }
|
||||
|
||||
morkLink(); // mLink_Next( 0 ), mLink_Prev( 0 ) { }
|
||||
|
||||
public:
|
||||
morkLink* Next() const { return mLink_Next; }
|
||||
morkLink* Prev() const { return mLink_Prev; }
|
||||
|
@ -64,6 +144,17 @@ public:
|
|||
{
|
||||
(mLink_Prev->mLink_Next = mLink_Next)->mLink_Prev = mLink_Prev;
|
||||
}
|
||||
|
||||
public: // link memory management methods
|
||||
static void* MakeNewLink(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev);
|
||||
void ZapOldLink(morkEnv* ev, nsIMdbHeap* ioHeap);
|
||||
|
||||
public: // link memory management operators
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{ return morkLink::MakeNewLink(inSize, ioHeap, ev); }
|
||||
|
||||
void operator delete(void* ioAddress) // DO NOT CALL THIS, hope to crash:
|
||||
{ ((morkLink*) 0)->ZapOldLink((morkEnv*) 0, (nsIMdbHeap*) 0); } // boom
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
|
@ -75,7 +166,7 @@ public:
|
|||
morkLink mDeque_Head;
|
||||
|
||||
public: // construction
|
||||
morkDeque() { mDeque_Head.SelfRefer(); }
|
||||
morkDeque(); // { mDeque_Head.SelfRefer(); }
|
||||
|
||||
public:// methods
|
||||
morkLink* RemoveFirst();
|
||||
|
|
|
@ -86,6 +86,7 @@ morkEnv::morkEnv(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
|||
, mEnv_DoTrace( morkBool_kFalse )
|
||||
, mEnv_AutoClear( morkAble_kDisabled )
|
||||
, mEnv_ShouldAbort( morkBool_kFalse )
|
||||
, mEnv_BeVerbose( morkBool_kFalse )
|
||||
{
|
||||
MORK_ASSERT(ioSlotHeap && ioFactory );
|
||||
if ( ioSlotHeap )
|
||||
|
@ -124,6 +125,8 @@ morkEnv::morkEnv(morkEnv* ev, /*i*/
|
|||
|
||||
, mEnv_DoTrace( morkBool_kFalse )
|
||||
, mEnv_AutoClear( morkAble_kDisabled )
|
||||
, mEnv_ShouldAbort( morkBool_kFalse )
|
||||
, mEnv_BeVerbose( morkBool_kFalse )
|
||||
{
|
||||
// $$$ do we need to refcount the inSelfAsMdbEnv nsIMdbEnv??
|
||||
|
||||
|
@ -159,6 +162,8 @@ morkEnv::CloseEnv(morkEnv* ev) /*i*/ // called by CloseMorkNode();
|
|||
mEnv_SelfAsMdbEnv = 0;
|
||||
mEnv_ErrorHook = 0;
|
||||
|
||||
morkPool::SlotStrongPool((morkPool*) 0, ev, &mEnv_HandlePool);
|
||||
|
||||
// mEnv_Factory is NOT refcounted
|
||||
|
||||
this->MarkShut();
|
||||
|
@ -260,6 +265,40 @@ morkEnv::TokenAsHex(void* outBuf, mork_token inToken)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::StringToYarn(const char* inString, mdbYarn* outYarn)
|
||||
{
|
||||
if ( outYarn )
|
||||
{
|
||||
mdb_fill fill = ( inString )? (mdb_fill) MORK_STRLEN(inString) : 0;
|
||||
|
||||
if ( fill ) // have nonempty content?
|
||||
{
|
||||
mdb_size size = outYarn->mYarn_Size; // max dest size
|
||||
if ( fill > size ) // too much string content?
|
||||
{
|
||||
outYarn->mYarn_More = fill - size; // extra string bytes omitted
|
||||
fill = size; // copy no more bytes than size of yarn buffer
|
||||
}
|
||||
void* dest = outYarn->mYarn_Buf; // where bytes are going
|
||||
if ( !dest ) // nil destination address buffer?
|
||||
fill = 0; // we can't write any content at all
|
||||
|
||||
if ( fill ) // anything to copy?
|
||||
MORK_MEMCPY(dest, inString, fill); // copy fill bytes to yarn
|
||||
|
||||
outYarn->mYarn_Fill = fill; // tell yarn size of copied content
|
||||
}
|
||||
else // no content to put into the yarn
|
||||
{
|
||||
outYarn->mYarn_Fill = 0; // tell yarn that string has no bytes
|
||||
}
|
||||
outYarn->mYarn_Form = 0; // always update the form slot
|
||||
}
|
||||
else
|
||||
this->NilPointerError();
|
||||
}
|
||||
|
||||
char*
|
||||
morkEnv::CopyString(nsIMdbHeap* ioHeap, const char* inString)
|
||||
{
|
||||
|
@ -351,6 +390,12 @@ morkEnv::OutOfMemoryError()
|
|||
this->NewError("out of memory");
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::CantMakeWhenBadError()
|
||||
{
|
||||
this->NewError("can't make an object when ev->Bad()");
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::NilPointerError()
|
||||
{
|
||||
|
|
|
@ -93,7 +93,7 @@ public: // state is public because the entire Mork system is private
|
|||
mork_bool mEnv_DoTrace;
|
||||
mork_able mEnv_AutoClear;
|
||||
mork_bool mEnv_ShouldAbort;
|
||||
mork_bool mEnv_Pad;
|
||||
mork_bool mEnv_BeVerbose;
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
|
@ -129,6 +129,7 @@ public: // utility env methods
|
|||
|
||||
char* CopyString(nsIMdbHeap* ioHeap, const char* inString);
|
||||
void FreeString(nsIMdbHeap* ioHeap, char* ioString);
|
||||
void StringToYarn(const char* inString, mdbYarn* outYarn);
|
||||
|
||||
public: // other env methods
|
||||
|
||||
|
@ -157,6 +158,7 @@ public: // other env methods
|
|||
void StubMethodOnlyError();
|
||||
void OutOfMemoryError();
|
||||
void NilPointerError();
|
||||
void CantMakeWhenBadError();
|
||||
void NewNonEnvError();
|
||||
void NilEnvSlotError();
|
||||
|
||||
|
|
|
@ -36,6 +36,10 @@
|
|||
#include "morkFile.h"
|
||||
#endif
|
||||
|
||||
// #ifndef _ORKINFILE_
|
||||
// #include "orkinFile.h"
|
||||
// #endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
|
@ -65,7 +69,7 @@ morkFile::~morkFile() // assert CloseFile() executed earlier
|
|||
/*public non-poly*/
|
||||
morkFile::morkFile(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkNode(ev, inUsage, ioHeap)
|
||||
: morkObject(ev, inUsage, ioHeap, (morkHandle*) 0)
|
||||
, mFile_Frozen( 0 )
|
||||
, mFile_DoTrace( 0 )
|
||||
, mFile_IoOpen( 0 )
|
||||
|
@ -73,6 +77,7 @@ morkFile::morkFile(morkEnv* ev, const morkUsage& inUsage,
|
|||
|
||||
, mFile_SlotHeap( 0 )
|
||||
, mFile_Name( 0 )
|
||||
, mFile_Thief( 0 )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
|
@ -101,6 +106,10 @@ morkFile::CloseFile(morkEnv* ev) // called by CloseMorkNode();
|
|||
|
||||
if ( mFile_Name )
|
||||
this->SetFileName(ev, (const char*) 0);
|
||||
|
||||
nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mFile_SlotHeap);
|
||||
nsIMdbFile_SlotStrongFile((nsIMdbFile*) 0, ev, &mFile_Thief);
|
||||
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
|
@ -113,6 +122,28 @@ morkFile::CloseFile(morkEnv* ev) // called by CloseMorkNode();
|
|||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
nsIMdbFile*
|
||||
morkFile::AcquireFileHandle(morkEnv* ev)
|
||||
{
|
||||
nsIMdbFile* outFile = 0;
|
||||
|
||||
#ifdef MORK_CONFIG_USE_ORKINFILE
|
||||
orkinFile* f = (orkinFile*) mObject_Handle;
|
||||
if ( f ) // have an old handle?
|
||||
f->AddStrongRef(ev->AsMdbEnv());
|
||||
else // need new handle?
|
||||
{
|
||||
f = orkinFile::MakeFile(ev, this);
|
||||
mObject_Handle = f;
|
||||
}
|
||||
if ( f )
|
||||
outFile = f;
|
||||
#endif /*MORK_CONFIG_USE_ORKINFILE*/
|
||||
MORK_USED_1(ev);
|
||||
|
||||
return outFile;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkFile::BecomeTrunk(morkEnv* ev)
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
|
@ -158,6 +189,12 @@ morkFile::NewMissingIoError(morkEnv* ev) const
|
|||
ev->NewError("file missing io");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkFile::NonFileTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkFile");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkFile::NilSlotHeapError(morkEnv* ev)
|
||||
{
|
||||
|
@ -170,6 +207,12 @@ morkFile::NilFileNameError(morkEnv* ev)
|
|||
ev->NewError("nil mFile_Name");
|
||||
}
|
||||
|
||||
void
|
||||
morkFile::SetThief(morkEnv* ev, nsIMdbFile* ioThief)
|
||||
{
|
||||
nsIMdbFile_SlotStrongFile(ioThief, ev, &mFile_Thief);
|
||||
}
|
||||
|
||||
void
|
||||
morkFile::SetFileName(morkEnv* ev, const char* inName) // inName can be nil
|
||||
{
|
||||
|
@ -216,7 +259,8 @@ void
|
|||
morkFile::NewFileErrnoError(morkEnv* ev) const
|
||||
// call NewFileErrnoError() to convert std C errno into AB fault
|
||||
{
|
||||
ev->NewError("errno"); // maybe pass value of strerror() instead
|
||||
const char* errnoString = strerror(errno);
|
||||
ev->NewError(errnoString); // maybe pass value of strerror() instead
|
||||
}
|
||||
|
||||
// ````` ````` ````` ````` newlines ````` ````` ````` `````
|
||||
|
@ -347,6 +391,7 @@ morkStdioFile::CreateNewStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
|
|||
}
|
||||
|
||||
|
||||
|
||||
/*public virtual*/ void
|
||||
morkStdioFile::BecomeTrunk(morkEnv* ev)
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
|
@ -414,7 +459,15 @@ morkStdioFile::AcquireBud(morkEnv* ev, nsIMdbHeap* ioHeap)
|
|||
if ( ev->Good() && this->AddStrongRef(ev) )
|
||||
outFile = this;
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
{
|
||||
nsIMdbFile* outBud = 0;
|
||||
mFile_Thief->AcquireBud(ev->AsMdbEnv(), ioHeap, &outBud);
|
||||
if ( outBud )
|
||||
outBud->CutStrongRef(ev->AsMdbEnv()); // convert to morkFile later
|
||||
}
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -452,7 +505,10 @@ morkStdioFile::Length(morkEnv* ev) const
|
|||
}
|
||||
else this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Eof(ev->AsMdbEnv(), &outPos);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -475,7 +531,10 @@ morkStdioFile::Tell(morkEnv* ev) const
|
|||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Tell(ev->AsMdbEnv(), &outPos);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -499,7 +558,10 @@ morkStdioFile::Read(morkEnv* ev, void* outBuf, mork_size inSize)
|
|||
}
|
||||
else this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Read(ev->AsMdbEnv(), outBuf, inSize, &outCount);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -522,7 +584,10 @@ morkStdioFile::Seek(morkEnv* ev, mork_pos inPos)
|
|||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Seek(ev->AsMdbEnv(), inPos);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -539,12 +604,16 @@ morkStdioFile::Write(morkEnv* ev, const void* inBuf, mork_size inSize)
|
|||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( file )
|
||||
{
|
||||
if ( fwrite(inBuf, 1, inSize, file) >= 0 )
|
||||
fwrite(inBuf, 1, inSize, file);
|
||||
if ( !ferror(file) )
|
||||
outCount = inSize;
|
||||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Write(ev->AsMdbEnv(), inBuf, inSize, &outCount);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -562,7 +631,10 @@ morkStdioFile::Flush(morkEnv* ev)
|
|||
MORK_FILEFLUSH(file);
|
||||
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Flush(ev->AsMdbEnv());
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
}
|
||||
|
@ -575,9 +647,14 @@ morkStdioFile::new_stdio_file_fault(morkEnv* ev) const
|
|||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
|
||||
int copyErrno = errno; // facilitate seeing error in debugger
|
||||
|
||||
// bunch of stuff not ported here
|
||||
if ( !errno && file )
|
||||
errno = ferror(file);
|
||||
if ( !copyErrno && file )
|
||||
{
|
||||
copyErrno = ferror(file);
|
||||
errno = copyErrno;
|
||||
}
|
||||
|
||||
this->NewFileErrnoError(ev);
|
||||
}
|
||||
|
@ -714,4 +791,23 @@ morkStdioFile::CloseStdio(morkEnv* ev)
|
|||
}
|
||||
|
||||
|
||||
/*public virtual*/ void
|
||||
morkStdioFile::Steal(morkEnv* ev, nsIMdbFile* ioThief)
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
// file's content, typically by assuming the original file's identity.
|
||||
{
|
||||
if ( mStdioFile_File && this->FileActive() && this->FileIoOpen() )
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( MORK_FILECLOSE(file) < 0 )
|
||||
this->new_stdio_file_fault(ev);
|
||||
|
||||
mStdioFile_File = 0;
|
||||
}
|
||||
this->SetThief(ev, ioThief);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*=============================================================================
|
||||
|
@ -35,7 +39,25 @@
|
|||
|
||||
#define morkDerived_kFile /*i*/ 0x4669 /* ascii 'Fi' */
|
||||
|
||||
class morkFile /*d*/ : public morkNode { /* ````` simple file API ````` */
|
||||
class morkFile /*d*/ : public morkObject { /* ````` simple file API ````` */
|
||||
|
||||
// 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: // slots inherited from morkObject (meant to inform only)
|
||||
|
||||
// morkHandle* mObject_Handle; // weak ref to handle for this object
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
protected: // protected morkFile members (similar to public domain IronDoc)
|
||||
|
@ -49,6 +71,8 @@ protected: // protected morkFile members (similar to public domain IronDoc)
|
|||
char* mFile_Name; // can be nil if SetFileName() is never called
|
||||
// mFile_Name convention: managed with morkEnv::CopyString()/FreeString()
|
||||
|
||||
nsIMdbFile* mFile_Thief; // from a call to orkinFile::Steal()
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseFile() only if open
|
||||
|
@ -92,6 +116,17 @@ public: // public static standard file creation entry point
|
|||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // virtual morkFile methods
|
||||
|
||||
virtual void Steal(morkEnv* ev, nsIMdbFile* ioThief) = 0;
|
||||
// Steal: tell this file to close any associated i/o stream in the file
|
||||
// system, because the file ioThief intends to reopen the file in order
|
||||
// to provide the MDB implementation with more exotic file access than is
|
||||
// offered by the nsIMdbFile alone. Presumably the thief knows enough
|
||||
// from Path() in order to know which file to reopen. If Steal() is
|
||||
// successful, this file should probably delegate all future calls to
|
||||
// the nsIMdbFile interface down to the thief files, so that even after
|
||||
// the file has been stolen, it can still be read, written, or forcibly
|
||||
// closed (by a call to CloseMdbObject()).
|
||||
|
||||
virtual void BecomeTrunk(morkEnv* ev);
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
|
@ -127,6 +162,8 @@ public: // virtual morkFile methods
|
|||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // non-poly morkFile methods
|
||||
|
||||
nsIMdbFile* AcquireFileHandle(morkEnv* ev); // mObject_Handle
|
||||
|
||||
mork_bool FileFrozen() const { return mFile_Frozen == 'F'; }
|
||||
mork_bool FileDoTrace() const { return mFile_DoTrace == 'T'; }
|
||||
mork_bool FileIoOpen() const { return mFile_IoOpen == 'O'; }
|
||||
|
@ -146,9 +183,15 @@ public: // non-poly morkFile methods
|
|||
{ return ( this->IsOpenNode() && this->FileActive() ); }
|
||||
// call IsOpenAndActiveFile() before using a file
|
||||
|
||||
|
||||
nsIMdbFile* GetThief() const { return mFile_Thief; }
|
||||
void SetThief(morkEnv* ev, nsIMdbFile* ioThief); // ioThief can be nil
|
||||
|
||||
const char* GetFileNameString() const { return mFile_Name; }
|
||||
void SetFileName(morkEnv* ev, const char* inName); // inName can be nil
|
||||
static void NilSlotHeapError(morkEnv* ev);
|
||||
static void NilFileNameError(morkEnv* ev);
|
||||
static void NonFileTypeError(morkEnv* ev);
|
||||
|
||||
void NewMissingIoError(morkEnv* ev) const;
|
||||
|
||||
|
@ -220,6 +263,17 @@ public: // compatible with the morkFile::OpenOldFile() entry point
|
|||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // virtual ab_File methods
|
||||
|
||||
virtual void Steal(morkEnv* ev, nsIMdbFile* ioThief);
|
||||
// Steal: tell this file to close any associated i/o stream in the file
|
||||
// system, because the file ioThief intends to reopen the file in order
|
||||
// to provide the MDB implementation with more exotic file access than is
|
||||
// offered by the nsIMdbFile alone. Presumably the thief knows enough
|
||||
// from Path() in order to know which file to reopen. If Steal() is
|
||||
// successful, this file should probably delegate all future calls to
|
||||
// the nsIMdbFile interface down to the thief files, so that even after
|
||||
// the file has been stolen, it can still be read, written, or forcibly
|
||||
// closed (by a call to CloseMdbObject()).
|
||||
|
||||
virtual void BecomeTrunk(morkEnv* ev);
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
|
|
|
@ -63,6 +63,7 @@ morkHandle::~morkHandle() // assert CloseHandle() executed earlier
|
|||
MORK_ASSERT(mHandle_Face==0);
|
||||
MORK_ASSERT(mHandle_Object==0);
|
||||
MORK_ASSERT(mHandle_Magic==0);
|
||||
MORK_ASSERT(mHandle_Tag==morkHandle_kTag); // should still have correct tag
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
|
@ -90,6 +91,8 @@ morkHandle::morkHandle(morkEnv* ev, // note morkUsage is always morkUsage_kPool
|
|||
mNode_Derived = morkDerived_kHandle;
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->CantMakeWhenBadError();
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
|
|
@ -250,6 +250,8 @@ morkNode::morkNode(const morkUsage& inUsage, nsIMdbHeap* ioHeap)
|
|||
, mNode_Uses( 1 )
|
||||
, mNode_Refs( 1 )
|
||||
{
|
||||
if ( !ioHeap && mNode_Usage == morkUsage_kHeap )
|
||||
MORK_ASSERT(ioHeap);
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
|
@ -340,12 +342,31 @@ morkNode::CloseNode(morkEnv* ev) // called by CloseMorkNode();
|
|||
}
|
||||
|
||||
|
||||
extern void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbFile_SlotStrongFile(nsIMdbFile* self, morkEnv* ev, nsIMdbFile** ioSlot)
|
||||
// If *ioSlot is non-nil, that file is released by CutStrongRef() and
|
||||
// then zeroed out. Then if self is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we take
|
||||
// expression 'nsIMdbFile_SlotStrongFile(0, ev, &slot)'.
|
||||
{
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
nsIMdbFile* file = *ioSlot;
|
||||
if ( file )
|
||||
{
|
||||
*ioSlot = 0;
|
||||
file->CutStrongRef(menv);
|
||||
}
|
||||
if ( self && ev->Good() && (self->AddStrongRef(menv)==0) && ev->Good() )
|
||||
*ioSlot = self;
|
||||
}
|
||||
|
||||
void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbHeap_SlotStrongHeap(nsIMdbHeap* self, morkEnv* ev, nsIMdbHeap** ioSlot)
|
||||
// If *ioSlot is non-nil, that heap is released by CutStrongRef() and
|
||||
// then zeroed out. Then if this is non-nil, this is acquired by
|
||||
// then zeroed out. Then if self is non-nil, self is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then this is put into slot *ioSlot. Note self can be nil, so we
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we
|
||||
// permit expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'.
|
||||
{
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
|
|
|
@ -121,11 +121,11 @@ public: // inlines for weird mNode_Mutable and mNode_Load constants
|
|||
mork_bool IsMutable() const { return mNode_Mutable == morkAble_kEnabled; }
|
||||
mork_bool IsAsleep() const { return mNode_Mutable == morkAble_kAsleep; }
|
||||
|
||||
void SetClean() { mNode_Load = morkLoad_kClean; }
|
||||
void SetDirty() { mNode_Load = morkLoad_kDirty; }
|
||||
void SetNodeClean() { mNode_Load = morkLoad_kClean; }
|
||||
void SetNodeDirty() { mNode_Load = morkLoad_kDirty; }
|
||||
|
||||
mork_bool IsClean() const { return mNode_Load == morkLoad_kClean; }
|
||||
mork_bool IsDirty() const { return mNode_Load == morkLoad_kDirty; }
|
||||
mork_bool IsNodeClean() const { return mNode_Load == morkLoad_kClean; }
|
||||
mork_bool IsNodeDirty() const { return mNode_Load == morkLoad_kDirty; }
|
||||
|
||||
public: // morkNode memory management methods
|
||||
static void* MakeNew(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev);
|
||||
|
@ -264,10 +264,18 @@ public: // refcounting for typesafe subclass inline methods
|
|||
extern void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbHeap_SlotStrongHeap(nsIMdbHeap* self, morkEnv* ev, nsIMdbHeap** ioSlot);
|
||||
// If *ioSlot is non-nil, that heap is released by CutStrongRef() and
|
||||
// then zeroed out. Then if me is non-nil, this is acquired by
|
||||
// then zeroed out. Then if self is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then me is put into slot *ioSlot. Note me can be nil, so we take
|
||||
// expression 'nsIMdbHeap_SlotStrongNode(0, ev, &slot)'.
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we take
|
||||
// expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'.
|
||||
|
||||
extern void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbFile_SlotStrongFile(nsIMdbFile* self, morkEnv* ev, nsIMdbFile** ioSlot);
|
||||
// If *ioSlot is non-nil, that file is released by CutStrongRef() and
|
||||
// then zeroed out. Then if self is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we take
|
||||
// expression 'nsIMdbHeap_SlotStrongFile(0, ev, &slot)'.
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
|
|
@ -325,7 +325,11 @@ int morkParser::eat_comment(morkEnv* ev) // last char was '/'
|
|||
if ( c == '*' ) // maybe end of a comment, if next char is '/'?
|
||||
{
|
||||
if ( (c = s->Getc(ev)) == '/' ) // end of comment?
|
||||
{
|
||||
--depth; // depth of comments has decreased by one
|
||||
if ( !depth ) // comments all done?
|
||||
c = s->Getc(ev); // return the byte after end of comment
|
||||
}
|
||||
else if ( c != EOF ) // need to put the char back?
|
||||
s->Ungetc(c); // especially need to put back '*', 0xA, or 0xD
|
||||
}
|
||||
|
@ -543,8 +547,9 @@ morkParser::ReadCell(morkEnv* ev)
|
|||
|
||||
mParser_InCell = morkBool_kTrue;
|
||||
this->OnNewCell(ev, *mParser_CellSpan.AsPlace(),
|
||||
cellMid, cellBuf, mParser_CellChange);
|
||||
cellMid, cellBuf); // , mParser_CellChange
|
||||
|
||||
mParser_CellChange = morkChange_kNil;
|
||||
if ( (c = this->NextChar(ev)) != EOF && ev->Good() )
|
||||
{
|
||||
this->StartSpanOnLastByte(ev, &mParser_SlotSpan);
|
||||
|
@ -589,6 +594,7 @@ morkParser::ReadCell(morkEnv* ev)
|
|||
this->OnCellEnd(ev, mParser_CellSpan);
|
||||
}
|
||||
}
|
||||
mParser_CellChange = morkChange_kNil;
|
||||
|
||||
if ( c == EOF && ev->Good() )
|
||||
this->UnexpectedEofError(ev);
|
||||
|
@ -608,11 +614,18 @@ void morkParser::ReadRow(morkEnv* ev, int c)
|
|||
|
||||
if ( c == '[' )
|
||||
{
|
||||
mork_bool cutAllRowCols = morkBool_kFalse;
|
||||
|
||||
if ( ( c = this->NextChar(ev) ) == '-' )
|
||||
cutAllRowCols = morkBool_kTrue;
|
||||
else if ( ev->Good() && c != EOF )
|
||||
mParser_Stream->Ungetc(c);
|
||||
|
||||
if ( this->ReadMid(ev, &mParser_RowMid) )
|
||||
{
|
||||
mParser_InRow = morkBool_kTrue;
|
||||
this->OnNewRow(ev, *mParser_RowSpan.AsPlace(),
|
||||
mParser_RowMid, mParser_RowChange);
|
||||
mParser_RowMid, cutAllRowCols);
|
||||
|
||||
mParser_Change = mParser_RowChange = morkChange_kNil;
|
||||
|
||||
|
@ -628,17 +641,18 @@ void morkParser::ReadRow(morkEnv* ev, int c)
|
|||
this->ReadMeta(ev, ']');
|
||||
break;
|
||||
|
||||
case '+': // plus
|
||||
mParser_CellChange = morkChange_kAdd;
|
||||
break;
|
||||
// case '+': // plus
|
||||
// mParser_CellChange = morkChange_kAdd;
|
||||
// break;
|
||||
|
||||
case '-': // minus
|
||||
mParser_CellChange = morkChange_kCut;
|
||||
// mParser_CellChange = morkChange_kCut;
|
||||
this->OnMinusCell(ev);
|
||||
break;
|
||||
|
||||
case '!': // bang
|
||||
mParser_CellChange = morkChange_kSet;
|
||||
break;
|
||||
// case '!': // bang
|
||||
// mParser_CellChange = morkChange_kSet;
|
||||
// break;
|
||||
|
||||
default:
|
||||
ev->NewWarning("unexpected byte in row");
|
||||
|
@ -688,11 +702,19 @@ void morkParser::ReadTable(morkEnv* ev)
|
|||
if ( mParser_Change )
|
||||
mParser_TableChange = mParser_Change;
|
||||
|
||||
mork_bool cutAllTableRows = morkBool_kFalse;
|
||||
|
||||
int c = this->NextChar(ev);
|
||||
if ( c == '-' )
|
||||
cutAllTableRows = morkBool_kTrue;
|
||||
else if ( ev->Good() && c != EOF )
|
||||
mParser_Stream->Ungetc(c);
|
||||
|
||||
if ( ev->Good() && this->ReadMid(ev, &mParser_TableMid) )
|
||||
{
|
||||
mParser_InTable = morkBool_kTrue;
|
||||
this->OnNewTable(ev, *mParser_TableSpan.AsPlace(),
|
||||
mParser_TableMid, mParser_TableChange);
|
||||
mParser_TableMid, cutAllTableRows);
|
||||
|
||||
mParser_Change = mParser_TableChange = morkChange_kNil;
|
||||
|
||||
|
@ -715,17 +737,18 @@ void morkParser::ReadTable(morkEnv* ev)
|
|||
this->ReadMeta(ev, '}');
|
||||
break;
|
||||
|
||||
case '+': // plus
|
||||
mParser_RowChange = morkChange_kAdd;
|
||||
break;
|
||||
// case '+': // plus
|
||||
// mParser_RowChange = morkChange_kAdd;
|
||||
// break;
|
||||
|
||||
case '-': // minus
|
||||
mParser_RowChange = morkChange_kCut;
|
||||
// mParser_RowChange = morkChange_kCut;
|
||||
this->OnMinusRow(ev);
|
||||
break;
|
||||
|
||||
case '!': // bang
|
||||
mParser_RowChange = morkChange_kSet;
|
||||
break;
|
||||
// case '!': // bang
|
||||
// mParser_RowChange = morkChange_kSet;
|
||||
// break;
|
||||
|
||||
default:
|
||||
ev->NewWarning("unexpected byte in table");
|
||||
|
@ -809,6 +832,7 @@ morkParser::UnexpectedEofError(morkEnv* ev)
|
|||
ev->NewWarning("unexpected eof");
|
||||
}
|
||||
|
||||
|
||||
morkBuf* morkParser::ReadValue(morkEnv* ev)
|
||||
{
|
||||
morkBuf* outBuf = 0;
|
||||
|
@ -825,11 +849,17 @@ morkBuf* morkParser::ReadValue(morkEnv* ev)
|
|||
register int c;
|
||||
while ( (c = s->Getc(ev)) != EOF && c != ')' && ev->Good() )
|
||||
{
|
||||
if ( c == '\\' ) // "\" escapes the next char?
|
||||
if ( c == '\\' ) // next char is escaped by '\'?
|
||||
{
|
||||
if ( (c = s->Getc(ev)) == 0xA || c == 0xD ) // linebreak after \?
|
||||
{
|
||||
c = this->eat_line_break(ev, c);
|
||||
|
||||
if ( c == ')' || c == '\\' || c == '$' )
|
||||
{
|
||||
s->Ungetc(c); // just let while loop test read this again
|
||||
continue; // goto next iteration of while loop
|
||||
}
|
||||
}
|
||||
if ( c == EOF || ev->Bad() )
|
||||
break; // end while loop
|
||||
}
|
||||
|
@ -844,10 +874,10 @@ morkBuf* morkParser::ReadValue(morkEnv* ev)
|
|||
c = ev->HexToByte(first, second);
|
||||
}
|
||||
else
|
||||
break;
|
||||
break; // end while loop
|
||||
}
|
||||
else
|
||||
break;
|
||||
break; // end while loop
|
||||
}
|
||||
spool->Putc(ev, c);
|
||||
}
|
||||
|
@ -974,10 +1004,10 @@ morkParser::NonParserTypeError(morkEnv* ev)
|
|||
mork_bool morkParser::MatchPattern(morkEnv* ev, const char* inPattern)
|
||||
{
|
||||
// if an error occurs, we want original inPattern in the debugger:
|
||||
const char* pattern = inPattern; // mutable copy
|
||||
const char* pattern = inPattern; // mutable copy of pointer
|
||||
morkStream* s = mParser_Stream;
|
||||
register int c;
|
||||
while ( *inPattern && ev->Good() )
|
||||
while ( *pattern && ev->Good() )
|
||||
{
|
||||
char byte = *pattern++;
|
||||
if ( (c = s->Getc(ev)) != byte )
|
||||
|
@ -988,27 +1018,165 @@ mork_bool morkParser::MatchPattern(morkEnv* ev, const char* inPattern)
|
|||
return ev->Good();
|
||||
}
|
||||
|
||||
mork_bool morkParser::FindGroupEnd(morkEnv* ev)
|
||||
{
|
||||
mork_bool foundEnd = morkBool_kFalse;
|
||||
|
||||
// char gidBuf[ 64 ]; // to hold hex pattern we want
|
||||
// (void) ev->TokenAsHex(gidBuf, mParser_GroupId);
|
||||
|
||||
morkStream* s = mParser_Stream;
|
||||
register int c;
|
||||
|
||||
while ( (c = s->Getc(ev)) != EOF && ev->Good() && !foundEnd )
|
||||
{
|
||||
if ( c == '@' ) // maybe start of group ending?
|
||||
{
|
||||
this->EndSpanOnThisByte(ev, &mParser_GroupSpan);
|
||||
if ( (c = s->Getc(ev)) == '$' ) // '$' follows '@' ?
|
||||
{
|
||||
if ( (c = s->Getc(ev)) == '$' ) // '$' follows "@$" ?
|
||||
{
|
||||
if ( (c = s->Getc(ev)) == '}' )
|
||||
{
|
||||
foundEnd = this->ReadEndGroupId(ev);
|
||||
this->EndSpanOnThisByte(ev, &mParser_GroupSpan);
|
||||
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '}' after @$$");
|
||||
}
|
||||
}
|
||||
if ( !foundEnd && c == '@' )
|
||||
s->Ungetc(c);
|
||||
}
|
||||
}
|
||||
|
||||
return foundEnd && ev->Good();
|
||||
}
|
||||
|
||||
void morkParser::ReadGroup(morkEnv* ev)
|
||||
{
|
||||
int next = 0;
|
||||
mParser_GroupId = this->ReadHex(ev, &next);
|
||||
if ( next == '{' )
|
||||
{
|
||||
morkStream* s = mParser_Stream;
|
||||
register int c;
|
||||
if ( (c = s->Getc(ev)) == '@' )
|
||||
{
|
||||
this->StartSpanOnThisByte(ev, &mParser_GroupSpan);
|
||||
mork_pos startPos = mParser_GroupSpan.mSpan_Start.mPlace_Pos;
|
||||
|
||||
// if ( !store->mStore_FirstCommitGroupPos )
|
||||
// store->mStore_FirstCommitGroupPos = startPos;
|
||||
// else if ( !store->mStore_SecondCommitGroupPos )
|
||||
// store->mStore_SecondCommitGroupPos = startPos;
|
||||
|
||||
if ( this->FindGroupEnd(ev) )
|
||||
{
|
||||
s->Seek(ev, startPos);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->OnNewGroup(ev, mParser_GroupSpan.mSpan_Start,
|
||||
mParser_GroupId);
|
||||
|
||||
this->ReadContent(ev, /*inInsideGroup*/ morkBool_kTrue);
|
||||
|
||||
this->OnGroupCommitEnd(ev, mParser_GroupSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '@' after @$${id{");
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '{' after @$$id");
|
||||
|
||||
}
|
||||
|
||||
mork_bool morkParser::ReadAt(morkEnv* ev, mork_bool inInsideGroup)
|
||||
/* groups must be ignored until properly terminated */
|
||||
// zm:Group ::= zm:GroupStart zm:Content zm:GroupEnd /* transaction */
|
||||
// zm:GroupStart ::= zm:S? '@$${' zm:Id '{@' /* transaction id has own space */
|
||||
// zm:GroupStart ::= zm:S? '@$${' zm:Hex+ '{@' /* xaction id has own space */
|
||||
// zm:GroupEnd ::= zm:GroupCommit | zm:GroupAbort
|
||||
// zm:GroupCommit ::= zm:S? '@$$}' zm:Id '}@' /* id matches start id */
|
||||
// zm:GroupAbort ::= zm:S? '@$$}~~' zm:Id '}@' /* id matches start id */
|
||||
// zm:GroupCommit ::= zm:S? '@$$}' zm:Hex+ '}@' /* id matches start id */
|
||||
// zm:GroupAbort ::= zm:S? '@$$}~~}@' /* id matches start id */
|
||||
/* We must allow started transactions to be aborted in summary files. */
|
||||
/* Note '$$' will never occur unescaped in values we will see in Mork. */
|
||||
{
|
||||
if ( this->MatchPattern(ev, "$${") )
|
||||
if ( this->MatchPattern(ev, "$$") )
|
||||
{
|
||||
//morkMid cellMid = &mParser_CellMid;
|
||||
//if ( this->ReadMid(ev, cellMid) )
|
||||
//{
|
||||
// if ( this->MatchPattern(ev, "}@") )
|
||||
// {
|
||||
// }
|
||||
//}
|
||||
morkStream* s = mParser_Stream;
|
||||
register int c;
|
||||
int next = 0;
|
||||
if ( ((c = s->Getc(ev)) == '{' || c == '}') && ev->Good() )
|
||||
{
|
||||
if ( c == '{' ) // start of new group?
|
||||
{
|
||||
if ( !inInsideGroup )
|
||||
this->ReadGroup(ev);
|
||||
else
|
||||
ev->NewError("nested @$${ inside another group");
|
||||
}
|
||||
else // c == '}' // end of old group?
|
||||
{
|
||||
if ( inInsideGroup )
|
||||
{
|
||||
this->ReadEndGroupId(ev);
|
||||
mParser_GroupId = 0;
|
||||
}
|
||||
else
|
||||
ev->NewError("unmatched @$$} outside any group");
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '{' or '}' after @$$");
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
mork_bool morkParser::ReadEndGroupId(morkEnv* ev)
|
||||
{
|
||||
mork_bool outSawGroupId = morkBool_kFalse;
|
||||
morkStream* s = mParser_Stream;
|
||||
register int c;
|
||||
if ( (c = s->Getc(ev)) != EOF && ev->Good() )
|
||||
{
|
||||
if ( c == '~' ) // transaction is aborted?
|
||||
{
|
||||
this->MatchPattern(ev, "~}@"); // finish rest of pattern
|
||||
}
|
||||
else // push back byte and read expected trailing hex id
|
||||
{
|
||||
s->Ungetc(c);
|
||||
int next = 0;
|
||||
mork_gid endGroupId = this->ReadHex(ev, &next);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( endGroupId == mParser_GroupId ) // matches start?
|
||||
{
|
||||
if ( next == '}' ) // '}' after @$$}id ?
|
||||
{
|
||||
if ( (c = s->Getc(ev)) == '@' ) // '@' after @$$}id} ?
|
||||
{
|
||||
// looks good, so return with no error
|
||||
outSawGroupId = morkBool_kTrue;
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '@' after @$$}id}");
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '}' after @$$}id");
|
||||
}
|
||||
else
|
||||
ev->NewError("end group id mismatch");
|
||||
}
|
||||
}
|
||||
}
|
||||
return ( outSawGroupId && ev->Good() );
|
||||
}
|
||||
|
||||
|
||||
void morkParser::ReadDict(morkEnv* ev)
|
||||
// zm:Dict ::= zm:S? '<' zm:DictItem* zm:S? '>'
|
||||
|
@ -1062,6 +1230,21 @@ void morkParser::EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan)
|
|||
}
|
||||
}
|
||||
|
||||
void morkParser::EndSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan)
|
||||
{
|
||||
mork_pos here = mParser_Stream->Tell(ev);
|
||||
if ( here > 0 ) // positive?
|
||||
--here;
|
||||
else
|
||||
here = 0;
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->SetHerePos(here);
|
||||
ioSpan->SetEndWithEnd(mParser_PortSpan);
|
||||
}
|
||||
}
|
||||
|
||||
void morkParser::StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan)
|
||||
{
|
||||
mork_pos here = mParser_Stream->Tell(ev);
|
||||
|
@ -1078,12 +1261,20 @@ void morkParser::StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkParser::OnPortState(morkEnv* ev)
|
||||
void morkParser::StartSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan)
|
||||
{
|
||||
mParser_InPort = morkBool_kTrue;
|
||||
this->OnNewPort(ev, *mParser_PortSpan.AsPlace());
|
||||
mork_pos here = mParser_Stream->Tell(ev);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->SetHerePos(here);
|
||||
ioSpan->SetStartWithEnd(mParser_PortSpan);
|
||||
ioSpan->SetEndWithEnd(mParser_PortSpan);
|
||||
}
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkParser::ReadContent(morkEnv* ev, mork_bool inInsideGroup)
|
||||
{
|
||||
int c;
|
||||
while ( (c = this->NextChar(ev)) != EOF && ev->Good() )
|
||||
{
|
||||
|
@ -1102,34 +1293,48 @@ morkParser::OnPortState(morkEnv* ev)
|
|||
break;
|
||||
|
||||
case '@': // group
|
||||
this->ReadGroup(ev);
|
||||
break;
|
||||
return this->ReadAt(ev, inInsideGroup);
|
||||
// break;
|
||||
|
||||
case '+': // plus
|
||||
mParser_Change = morkChange_kAdd;
|
||||
break;
|
||||
// case '+': // plus
|
||||
// mParser_Change = morkChange_kAdd;
|
||||
// break;
|
||||
|
||||
case '-': // minus
|
||||
mParser_Change = morkChange_kCut;
|
||||
break;
|
||||
// case '-': // minus
|
||||
// mParser_Change = morkChange_kCut;
|
||||
// break;
|
||||
|
||||
case '!': // bang
|
||||
mParser_Change = morkChange_kSet;
|
||||
break;
|
||||
// case '!': // bang
|
||||
// mParser_Change = morkChange_kSet;
|
||||
// break;
|
||||
|
||||
default:
|
||||
ev->NewWarning("unexpected byte in OnPortState()");
|
||||
ev->NewWarning("unexpected byte in ReadContent()");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ev->Bad() )
|
||||
mParser_State = morkParser_kBrokenState;
|
||||
else if ( c == EOF )
|
||||
mParser_State = morkParser_kDoneState;
|
||||
|
||||
return ( ev->Good() && c != EOF );
|
||||
}
|
||||
|
||||
void
|
||||
morkParser::OnPortState(morkEnv* ev)
|
||||
{
|
||||
mParser_InPort = morkBool_kTrue;
|
||||
this->OnNewPort(ev, *mParser_PortSpan.AsPlace());
|
||||
|
||||
while ( this->ReadContent(ev, /*inInsideGroup*/ morkBool_kFalse) )
|
||||
/* empty */;
|
||||
|
||||
mParser_InPort = morkBool_kFalse;
|
||||
this->OnPortEnd(ev, mParser_PortSpan);
|
||||
|
||||
if ( ev->Bad() )
|
||||
mParser_State = morkParser_kBrokenState;
|
||||
else if ( c == EOF )
|
||||
mParser_State = morkParser_kDoneState;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -383,9 +383,9 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
// mp:MetaTable ::= OnNewMeta mp:MetaItem* mp:Row OnMetaEnd
|
||||
// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd
|
||||
// mp:MetaItem ::= mp:Cell | OnMetaGlitch
|
||||
// mp:Row ::= OnNewRow mp:RowItem* OnRowEnd
|
||||
// mp:Row ::= OnMinusRow? OnNewRow mp:RowItem* OnRowEnd
|
||||
// mp:RowItem ::= mp:Cell | mp:Meta | OnRowGlitch
|
||||
// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
|
||||
// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
|
||||
|
||||
|
@ -409,7 +409,7 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange) = 0;
|
||||
const morkMid& inMid, mork_bool inCutAllRows) = 0;
|
||||
virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
|
@ -417,8 +417,9 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnMinusRow(morkEnv* ev) = 0;
|
||||
virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange) = 0;
|
||||
const morkMid& inMid, mork_bool inCutAllCols) = 0;
|
||||
virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
|
@ -431,8 +432,9 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
|
||||
virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
|
||||
virtual void OnMinusCell(morkEnv* ev) = 0;
|
||||
virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid* inMid, const morkBuf* inBuf, mork_change inChange) = 0;
|
||||
const morkMid* inMid, const morkBuf* inBuf) = 0;
|
||||
// Exactly one of inMid and inBuf is nil, and the other is non-nil.
|
||||
// When hex ID syntax is used for a column, then inMid is not nil, and
|
||||
// when a naked string names a column, then inBuf is not nil.
|
||||
|
@ -476,7 +478,11 @@ protected: // protected parser helper methods
|
|||
void ReadTable(morkEnv* ev);
|
||||
void ReadTableMeta(morkEnv* ev);
|
||||
void ReadDict(morkEnv* ev);
|
||||
mork_bool ReadContent(morkEnv* ev, mork_bool inInsideGroup);
|
||||
void ReadGroup(morkEnv* ev);
|
||||
mork_bool ReadEndGroupId(morkEnv* ev);
|
||||
mork_bool ReadAt(morkEnv* ev, mork_bool inInsideGroup);
|
||||
mork_bool FindGroupEnd(morkEnv* ev);
|
||||
void ReadMeta(morkEnv* ev, int inEndMeta);
|
||||
void ReadAlias(morkEnv* ev);
|
||||
mork_id ReadHex(morkEnv* ev, int* outNextChar);
|
||||
|
@ -487,8 +493,11 @@ protected: // protected parser helper methods
|
|||
mork_bool MatchPattern(morkEnv* ev, const char* inPattern);
|
||||
|
||||
void EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
void EndSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
void StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
|
||||
void StartSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
|
||||
int eat_line_break(morkEnv* ev, int inLast);
|
||||
int eat_line_continue(morkEnv* ev); // last char was '\\'
|
||||
int eat_comment(morkEnv* ev); // last char was '/'
|
||||
|
|
|
@ -66,43 +66,102 @@
|
|||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// notifications regarding row changes:
|
||||
|
||||
void morkRow::NoteRowAddCol(morkEnv* ev, mork_column inColumn)
|
||||
{
|
||||
if ( !this->IsRowRewrite() )
|
||||
{
|
||||
mork_delta newDelta;
|
||||
morkDelta_Init(newDelta, inColumn, morkChange_kAdd);
|
||||
|
||||
if ( newDelta != mRow_Delta ) // not repeating existing data?
|
||||
{
|
||||
if ( this->HasRowDelta() ) // already have one change recorded?
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
else
|
||||
this->SetRowDelta(inColumn, morkChange_kAdd);
|
||||
}
|
||||
}
|
||||
else
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
void morkRow::NoteRowCutCol(morkEnv* ev, mork_column inColumn)
|
||||
{
|
||||
if ( !this->IsRowRewrite() )
|
||||
{
|
||||
mork_delta newDelta;
|
||||
morkDelta_Init(newDelta, inColumn, morkChange_kCut);
|
||||
|
||||
if ( newDelta != mRow_Delta ) // not repeating existing data?
|
||||
{
|
||||
if ( this->HasRowDelta() ) // already have one change recorded?
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
else
|
||||
this->SetRowDelta(inColumn, morkChange_kCut);
|
||||
}
|
||||
}
|
||||
else
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
void morkRow::NoteRowSetCol(morkEnv* ev, mork_column inColumn)
|
||||
{
|
||||
if ( !this->IsRowRewrite() )
|
||||
{
|
||||
if ( this->HasRowDelta() ) // already have one change recorded?
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
else
|
||||
this->SetRowDelta(inColumn, morkChange_kSet);
|
||||
}
|
||||
else
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
void morkRow::NoteRowSetAll(morkEnv* ev)
|
||||
{
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
mork_u2
|
||||
morkRow::AddTableUse(morkEnv* ev)
|
||||
morkRow::AddRowGcUse(morkEnv* ev)
|
||||
{
|
||||
if ( this->IsRow() )
|
||||
{
|
||||
if ( mRow_TableUses < morkRow_kMaxTableUses ) // not already maxed out?
|
||||
++mRow_TableUses;
|
||||
if ( mRow_GcUses < morkRow_kMaxGcUses ) // not already maxed out?
|
||||
++mRow_GcUses;
|
||||
}
|
||||
else
|
||||
this->NonRowTypeError(ev);
|
||||
|
||||
return mRow_TableUses;
|
||||
return mRow_GcUses;
|
||||
}
|
||||
|
||||
mork_u2
|
||||
morkRow::CutTableUse(morkEnv* ev)
|
||||
morkRow::CutRowGcUse(morkEnv* ev)
|
||||
{
|
||||
if ( this->IsRow() )
|
||||
{
|
||||
if ( mRow_TableUses ) // any outstanding uses to cut?
|
||||
if ( mRow_GcUses ) // any outstanding uses to cut?
|
||||
{
|
||||
if ( mRow_TableUses < morkRow_kMaxTableUses ) // not frozen at max?
|
||||
--mRow_TableUses;
|
||||
if ( mRow_GcUses < morkRow_kMaxGcUses ) // not frozen at max?
|
||||
--mRow_GcUses;
|
||||
}
|
||||
else
|
||||
this->TableUsesUnderflowWarning(ev);
|
||||
this->GcUsesUnderflowWarning(ev);
|
||||
}
|
||||
else
|
||||
this->NonRowTypeError(ev);
|
||||
|
||||
return mRow_TableUses;
|
||||
return mRow_GcUses;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRow::TableUsesUnderflowWarning(morkEnv* ev)
|
||||
morkRow::GcUsesUnderflowWarning(morkEnv* ev)
|
||||
{
|
||||
ev->NewWarning("mRow_TableUses underflow");
|
||||
ev->NewWarning("mRow_GcUses underflow");
|
||||
}
|
||||
|
||||
|
||||
|
@ -155,12 +214,19 @@ morkRow::InitRow(morkEnv* ev, const mdbOid* inOid, morkRowSpace* ioSpace,
|
|||
mRow_Length = (mork_u2) inLength;
|
||||
mRow_Seed = (mork_u2) (mork_ip) this; // "random" assignment
|
||||
|
||||
mRow_TableUses = 0;
|
||||
mRow_Load = morkLoad_kClean;
|
||||
mRow_GcUses = 0;
|
||||
mRow_Pad = 0;
|
||||
mRow_Flags = 0;
|
||||
mRow_Tag = morkRow_kTag;
|
||||
|
||||
if ( inLength )
|
||||
mRow_Cells = ioPool->NewCells(ev, inLength);
|
||||
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() ) // new row might dirty store
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
}
|
||||
else
|
||||
ioSpace->MinusOneRidError(ev);
|
||||
|
@ -333,6 +399,28 @@ morkRow::TakeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength,
|
|||
}
|
||||
}
|
||||
|
||||
mork_bool morkRow::MaybeDirtySpaceStoreAndRow()
|
||||
{
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
if ( rowSpace )
|
||||
{
|
||||
morkStore* store = rowSpace->mSpace_Store;
|
||||
if ( store && store->mStore_CanDirty )
|
||||
{
|
||||
store->SetStoreDirty();
|
||||
rowSpace->mSpace_CanDirty = morkBool_kTrue;
|
||||
}
|
||||
|
||||
if ( rowSpace->mSpace_CanDirty )
|
||||
{
|
||||
this->SetRowDirty();
|
||||
rowSpace->SetRowSpaceDirty();
|
||||
return morkBool_kTrue;
|
||||
}
|
||||
}
|
||||
return morkBool_kFalse;
|
||||
}
|
||||
|
||||
morkCell*
|
||||
morkRow::NewCell(morkEnv* ev, mdb_column inColumn,
|
||||
mork_pos* outPos, morkStore* ioStore)
|
||||
|
@ -341,10 +429,21 @@ morkRow::NewCell(morkEnv* ev, mdb_column inColumn,
|
|||
mork_size length = (mork_size) mRow_Length;
|
||||
*outPos = (mork_pos) length;
|
||||
morkPool* pool = ioStore->StorePool();
|
||||
|
||||
mork_bool canDirty = this->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
if ( pool->AddRowCells(ev, this, length + 1) )
|
||||
{
|
||||
morkCell* cell = mRow_Cells + length;
|
||||
cell->SetColumnAndChange(inColumn, morkChange_kAdd);
|
||||
// next line equivalent to inline morkCell::SetCellDirty():
|
||||
if ( canDirty )
|
||||
cell->SetCellColumnDirty(inColumn);
|
||||
else
|
||||
cell->SetCellColumnClean(inColumn);
|
||||
|
||||
if ( canDirty && !this->IsRowRewrite() )
|
||||
this->NoteRowAddCol(ev, inColumn);
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
@ -432,6 +531,11 @@ morkRow::EmptyAllCells(morkEnv* ev)
|
|||
morkStore* store = this->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkPool* pool = store->StorePool();
|
||||
morkCell* end = cells + mRow_Length;
|
||||
--cells; // prepare for preincrement:
|
||||
|
@ -480,6 +584,11 @@ morkRow::CutAllColumns(morkEnv* ev)
|
|||
morkStore* store = this->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
if ( rowSpace->mRowSpace_IndexCount ) // any indexes?
|
||||
this->cut_all_index_entries(ev);
|
||||
|
@ -497,6 +606,11 @@ morkRow::SetRow(morkEnv* ev, const morkRow* inSourceRow)
|
|||
morkStore* srcStore = inSourceRow->GetRowSpaceStore(ev);
|
||||
if ( store && srcStore )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
mork_count indexes = rowSpace->mRowSpace_IndexCount; // any indexes?
|
||||
|
||||
|
@ -518,9 +632,13 @@ morkRow::SetRow(morkEnv* ev, const morkRow* inSourceRow)
|
|||
{
|
||||
morkAtom* atom = src->mCell_Atom;
|
||||
mork_column dstCol = src->GetColumn();
|
||||
// Note we modify the mCell_Atom slot directly instead of using
|
||||
// morkCell::SetAtom(), because we know it starts equal to nil.
|
||||
|
||||
if ( sameStore ) // source and dest in same store?
|
||||
{
|
||||
dst->SetColumnAndChange(dstCol, morkChange_kAdd);
|
||||
// next line equivalent to inline morkCell::SetCellDirty():
|
||||
dst->SetCellColumnDirty(dstCol);
|
||||
dst->mCell_Atom = atom;
|
||||
if ( atom ) // another ref to non-nil atom?
|
||||
atom->AddCellUse(ev);
|
||||
|
@ -530,7 +648,8 @@ morkRow::SetRow(morkEnv* ev, const morkRow* inSourceRow)
|
|||
dstCol = store->CopyToken(ev, dstCol, srcStore);
|
||||
if ( dstCol )
|
||||
{
|
||||
dst->SetColumnAndChange(dstCol, morkChange_kAdd);
|
||||
// next line equivalent to inline morkCell::SetCellDirty():
|
||||
dst->SetCellColumnDirty(dstCol);
|
||||
atom = store->CopyAtom(ev, atom);
|
||||
dst->mCell_Atom = atom;
|
||||
if ( atom ) // another ref?
|
||||
|
@ -565,19 +684,23 @@ morkRow::AddRow(morkEnv* ev, const morkRow* inSourceRow)
|
|||
}
|
||||
|
||||
void
|
||||
morkRow::OnZeroTableUse(morkEnv* ev)
|
||||
// OnZeroTableUse() is called when CutTableUse() returns zero.
|
||||
morkRow::OnZeroRowGcUse(morkEnv* ev)
|
||||
// OnZeroRowGcUse() is called when CutRowGcUse() returns zero.
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
// ev->NewWarning("need to implement OnZeroTableUse");
|
||||
// ev->NewWarning("need to implement OnZeroRowGcUse");
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::DirtyAllRowContent(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
this->SetRowDirty();
|
||||
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkCell* cells = mRow_Cells;
|
||||
if ( cells )
|
||||
{
|
||||
|
@ -624,6 +747,9 @@ void morkRow::CutColumn(morkEnv* ev, mdb_column inColumn)
|
|||
morkStore* store = this->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() && !this->IsRowRewrite() )
|
||||
this->NoteRowCutCol(ev, inColumn);
|
||||
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
|
||||
rowSpace->FindMap(ev, inColumn) : (morkAtomRowMap*) 0;
|
||||
|
@ -664,25 +790,6 @@ void morkRow::CutColumn(morkEnv* ev, mdb_column inColumn)
|
|||
}
|
||||
}
|
||||
|
||||
// void morkRow::cut_cell_from_space_index(morkEnv* ev, morkCell* ioCell)
|
||||
// {
|
||||
// morkAtom* oldAtom = ioCell->mCell_Atom;
|
||||
// if ( oldAtom )
|
||||
// {
|
||||
// mork_column col = ioCell->GetColumn();
|
||||
// morkRowSpace* rowSpace = mRow_Space;
|
||||
// morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
|
||||
// rowSpace->FindMap(ev, col) : (morkAtomRowMap*) 0;
|
||||
//
|
||||
// if ( map ) // col is indexed by row space?
|
||||
// {
|
||||
// mork_aid oldAid = oldAtom->GetBookAtomAid();
|
||||
// if ( oldAid ) // cut old row attribute from row index in space?
|
||||
// map->CutAid(ev, oldAid);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
void morkRow::AddColumn(morkEnv* ev, mdb_column inColumn,
|
||||
const mdbYarn* inYarn, morkStore* ioStore)
|
||||
{
|
||||
|
@ -690,16 +797,16 @@ void morkRow::AddColumn(morkEnv* ev, mdb_column inColumn,
|
|||
{
|
||||
mork_pos pos = -1;
|
||||
morkCell* cell = this->GetCell(ev, inColumn, &pos);
|
||||
morkCell* oldCell = cell; // need to know later whether new
|
||||
if ( !cell ) // column does not yet exist?
|
||||
cell = this->NewCell(ev, inColumn, &pos, ioStore);
|
||||
else
|
||||
++mRow_Seed;
|
||||
|
||||
if ( cell )
|
||||
{
|
||||
// cell->SetYarn(ev, inYarn, ioStore);
|
||||
morkAtom* oldAtom = cell->mCell_Atom;
|
||||
|
||||
morkAtom* atom = ioStore->YarnToAtom(ev, inYarn);
|
||||
if ( atom )
|
||||
if ( atom && atom != oldAtom )
|
||||
{
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
|
||||
|
@ -707,7 +814,6 @@ void morkRow::AddColumn(morkEnv* ev, mdb_column inColumn,
|
|||
|
||||
if ( map ) // inColumn is indexed by row space?
|
||||
{
|
||||
morkAtom* oldAtom = cell->mCell_Atom;
|
||||
if ( oldAtom && oldAtom != atom ) // cut old cell from index?
|
||||
{
|
||||
mork_aid oldAid = oldAtom->GetBookAtomAid();
|
||||
|
@ -718,6 +824,13 @@ void morkRow::AddColumn(morkEnv* ev, mdb_column inColumn,
|
|||
|
||||
cell->SetAtom(ev, atom, ioStore->StorePool()); // refcounts atom
|
||||
|
||||
if ( oldCell ) // we changed a pre-existing cell in the row?
|
||||
{
|
||||
++mRow_Seed;
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() && !this->IsRowRewrite() )
|
||||
this->NoteRowAddCol(ev, inColumn);
|
||||
}
|
||||
|
||||
if ( map ) // inColumn is indexed by row space?
|
||||
{
|
||||
mork_aid newAid = atom->GetBookAtomAid();
|
||||
|
|
|
@ -23,18 +23,25 @@
|
|||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCELL_
|
||||
#include "morkCell.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class nsIMdbRow;
|
||||
class nsIMdbCell;
|
||||
#define morkDerived_kRow /*i*/ 0x5277 /* ascii 'Rw' */
|
||||
|
||||
#define morkRow_kMaxTableUses 0x0FFFF /* max for 16-bit unsigned int */
|
||||
#define morkRow_kMaxGcUses 0x0FF /* max for 8-bit unsigned int */
|
||||
#define morkRow_kMaxLength 0x0FFFF /* max for 16-bit unsigned int */
|
||||
#define morkRow_kMinusOneRid ((mork_rid) -1)
|
||||
|
||||
#define morkRow_kTag 'r' /* magic signature for mRow_Tag */
|
||||
|
||||
#define morkRow_kNotedBit ((mork_u1) (1 << 0)) /* space has change notes */
|
||||
#define morkRow_kRewriteBit ((mork_u1) (1 << 1)) /* must rewrite all cells */
|
||||
#define morkRow_kDirtyBit ((mork_u1) (1 << 2)) /* row has been changed */
|
||||
|
||||
class morkRow { // row of cells
|
||||
|
||||
|
@ -44,13 +51,57 @@ public: // state is public because the entire Mork system is private
|
|||
morkCell* mRow_Cells;
|
||||
mdbOid mRow_Oid;
|
||||
|
||||
mork_delta mRow_Delta; // space to note a single column change
|
||||
|
||||
mork_u2 mRow_Length; // physical count of cells in mRow_Cells
|
||||
mork_u2 mRow_Seed; // count changes in mRow_Cells structure
|
||||
|
||||
mork_u2 mRow_TableUses; // persistent references from tables
|
||||
mork_load mRow_Load; // is this row clean or dirty?
|
||||
mork_u1 mRow_GcUses; // persistent references from tables
|
||||
mork_u1 mRow_Pad; // for u1 alignment
|
||||
mork_u1 mRow_Flags; // one-byte flags slot
|
||||
mork_u1 mRow_Tag; // one-byte tag (need u4 alignment pad)
|
||||
|
||||
public: // interpreting mRow_Delta
|
||||
|
||||
mork_bool HasRowDelta() const { return ( mRow_Delta != 0 ); }
|
||||
|
||||
void ClearRowDelta() { mRow_Delta = 0; }
|
||||
|
||||
void SetRowDelta(mork_column inCol, mork_change inChange)
|
||||
{ morkDelta_Init(mRow_Delta, inCol, inChange); }
|
||||
|
||||
mork_column GetDeltaColumn() const { return morkDelta_Column(mRow_Delta); }
|
||||
mork_change GetDeltaChange() const { return morkDelta_Change(mRow_Delta); }
|
||||
|
||||
public: // noting row changes
|
||||
|
||||
void NoteRowSetAll(morkEnv* ev);
|
||||
void NoteRowSetCol(morkEnv* ev, mork_column inCol);
|
||||
void NoteRowAddCol(morkEnv* ev, mork_column inCol);
|
||||
void NoteRowCutCol(morkEnv* ev, mork_column inCol);
|
||||
|
||||
public: // flags bit twiddling
|
||||
|
||||
void SetRowNoted() { mRow_Flags |= morkRow_kNotedBit; }
|
||||
void SetRowRewrite() { mRow_Flags |= morkRow_kRewriteBit; }
|
||||
void SetRowDirty() { mRow_Flags |= morkRow_kDirtyBit; }
|
||||
|
||||
void ClearRowNoted() { mRow_Flags &= (mork_u1) ~morkRow_kNotedBit; }
|
||||
void ClearRowRewrite() { mRow_Flags &= (mork_u1) ~morkRow_kRewriteBit; }
|
||||
void SetRowClean() { mRow_Flags = 0; mRow_Delta = 0; }
|
||||
|
||||
mork_bool IsRowNoted() const
|
||||
{ return ( mRow_Flags & morkRow_kNotedBit ) != 0; }
|
||||
|
||||
mork_bool IsRowRewrite() const
|
||||
{ return ( mRow_Flags & morkRow_kRewriteBit ) != 0; }
|
||||
|
||||
mork_bool IsRowClean() const
|
||||
{ return ( mRow_Flags & morkRow_kDirtyBit ) == 0; }
|
||||
|
||||
mork_bool IsRowDirty() const
|
||||
{ return ( mRow_Flags & morkRow_kDirtyBit ) != 0; }
|
||||
|
||||
public: // other row methods
|
||||
morkRow( ) { }
|
||||
morkRow(const mdbOid* inOid) :mRow_Oid(*inOid) { }
|
||||
|
@ -63,14 +114,11 @@ public: // other row methods
|
|||
nsIMdbCell* AcquireCellHandle(morkEnv* ev, morkCell* ioCell,
|
||||
mdb_column inColumn, mork_pos inPos);
|
||||
|
||||
mork_u2 AddTableUse(morkEnv* ev);
|
||||
mork_u2 CutTableUse(morkEnv* ev);
|
||||
mork_u2 AddRowGcUse(morkEnv* ev);
|
||||
mork_u2 CutRowGcUse(morkEnv* ev);
|
||||
|
||||
void SetRowClean() { mRow_Load = morkLoad_kClean; }
|
||||
void SetRowDirty() { mRow_Load = morkLoad_kDirty; }
|
||||
|
||||
mork_bool IsRowClean() const { return mRow_Load == morkLoad_kClean; }
|
||||
mork_bool IsRowDirty() const { return mRow_Load == morkLoad_kDirty; }
|
||||
mork_bool MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
public: // internal row methods
|
||||
|
||||
|
@ -129,8 +177,8 @@ public: // external row methods
|
|||
void SetRow(morkEnv* ev, const morkRow* inSourceRow);
|
||||
void CutAllColumns(morkEnv* ev);
|
||||
|
||||
void OnZeroTableUse(morkEnv* ev);
|
||||
// OnZeroTableUse() is called when CutTableUse() returns zero.
|
||||
void OnZeroRowGcUse(morkEnv* ev);
|
||||
// OnZeroRowGcUse() is called when CutRowGcUse() returns zero.
|
||||
|
||||
public: // dynamic typing
|
||||
|
||||
|
@ -167,7 +215,7 @@ public: // errors
|
|||
static void NilCellsError(morkEnv* ev);
|
||||
static void NonRowTypeError(morkEnv* ev);
|
||||
static void NonRowTypeWarning(morkEnv* ev);
|
||||
static void TableUsesUnderflowWarning(morkEnv* ev);
|
||||
static void GcUsesUnderflowWarning(morkEnv* ev);
|
||||
|
||||
private: // copying is not allowed
|
||||
morkRow(const morkRow& other);
|
||||
|
|
|
@ -82,6 +82,15 @@ public: // other map methods
|
|||
// GetRow() returns the row equal to ioRow, or else nil
|
||||
|
||||
// note the rows are owned elsewhere, usuall by morkRowSpace
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakRowMap(morkMap* me,
|
||||
morkEnv* ev, morkRowMap** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongRowMap(morkMap* me,
|
||||
morkEnv* ev, morkRowMap** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
class morkRowMapIter: public morkMapIter{ // typesafe wrapper class
|
||||
|
|
|
@ -122,6 +122,8 @@ morkRowSpace::morkRowSpace(morkEnv* ev,
|
|||
if ( ioSlotHeap )
|
||||
{
|
||||
mNode_Derived = morkDerived_kRowSpace;
|
||||
|
||||
// the morkSpace base constructor handles any dirty propagation
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
@ -207,6 +209,9 @@ morkRowSpace::MinusOneRidError(morkEnv* ev)
|
|||
mork_num
|
||||
morkRowSpace::CutAllRows(morkEnv* ev, morkPool* ioPool)
|
||||
{
|
||||
if ( this->IsRowSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
|
||||
mork_num outSlots = mRowSpace_Rows.mMap_Fill;
|
||||
morkRow* r = 0; // old key row in the map
|
||||
|
||||
|
@ -268,13 +273,14 @@ morkRowSpace::NewTableWithTid(morkEnv* ev, mork_tid inTid,
|
|||
const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
|
||||
{
|
||||
morkTable* outTable = 0;
|
||||
morkStore* store = mSpace_Store;
|
||||
|
||||
if ( inTableKind )
|
||||
if ( inTableKind && store )
|
||||
{
|
||||
mdb_bool mustBeUnique = morkBool_kFalse;
|
||||
nsIMdbHeap* heap = mSpace_Store->mPort_Heap;
|
||||
nsIMdbHeap* heap = store->mPort_Heap;
|
||||
morkTable* table = new(*heap, ev)
|
||||
morkTable(ev, morkUsage::kHeap, heap, mSpace_Store, heap, this,
|
||||
morkTable(ev, morkUsage::kHeap, heap, store, heap, this,
|
||||
inOptionalMetaRowOid, inTid, inTableKind, mustBeUnique);
|
||||
if ( table )
|
||||
{
|
||||
|
@ -284,11 +290,17 @@ morkRowSpace::NewTableWithTid(morkEnv* ev, mork_tid inTid,
|
|||
if ( mRowSpace_NextTableId <= inTid )
|
||||
mRowSpace_NextTableId = inTid + 1;
|
||||
}
|
||||
table->CutStrongRef(ev);
|
||||
table->CutStrongRef(ev); // always cut ref; AddTable() adds its own
|
||||
|
||||
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
|
||||
this->MaybeDirtyStoreAndSpace(); // morkTable does already
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ( store )
|
||||
this->ZeroKindError(ev);
|
||||
else
|
||||
this->NilSpaceStoreError(ev);
|
||||
|
||||
return outTable;
|
||||
}
|
||||
|
@ -299,8 +311,9 @@ morkRowSpace::NewTable(morkEnv* ev, mork_kind inTableKind,
|
|||
const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
|
||||
{
|
||||
morkTable* outTable = 0;
|
||||
morkStore* store = mSpace_Store;
|
||||
|
||||
if ( inTableKind )
|
||||
if ( inTableKind && store )
|
||||
{
|
||||
if ( inMustBeUnique ) // need to look for existing table first?
|
||||
outTable = this->FindTableByKind(ev, inTableKind);
|
||||
|
@ -320,12 +333,17 @@ morkRowSpace::NewTable(morkEnv* ev, mork_kind inTableKind,
|
|||
outTable = table;
|
||||
else
|
||||
table->CutStrongRef(ev);
|
||||
|
||||
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
|
||||
this->MaybeDirtyStoreAndSpace(); // morkTable does already
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ( store )
|
||||
this->ZeroKindError(ev);
|
||||
else
|
||||
this->NilSpaceStoreError(ev);
|
||||
|
||||
return outTable;
|
||||
}
|
||||
|
@ -514,6 +532,9 @@ 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);
|
||||
|
@ -530,8 +551,14 @@ morkRowSpace::NewRowWithOid(morkEnv* ev, const mdbOid* inOid)
|
|||
}
|
||||
else
|
||||
pool->ZapRow(ev, row);
|
||||
|
||||
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
|
||||
this->MaybeDirtyStoreAndSpace(); // InitRow() does already
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilSpaceStoreError(ev);
|
||||
}
|
||||
return outRow;
|
||||
}
|
||||
|
||||
|
@ -543,6 +570,9 @@ morkRowSpace::NewRow(morkEnv* ev)
|
|||
{
|
||||
mork_rid id = this->MakeNewRowId(ev);
|
||||
if ( id )
|
||||
{
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( store )
|
||||
{
|
||||
mdbOid oid;
|
||||
oid.mOid_Scope = mSpace_Scope;
|
||||
|
@ -557,12 +587,19 @@ morkRowSpace::NewRow(morkEnv* ev)
|
|||
outRow = row;
|
||||
else
|
||||
pool->ZapRow(ev, row);
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -47,6 +47,10 @@
|
|||
#include "morkArray.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kRowSpace /*i*/ 0x7253 /* ascii 'rS' */
|
||||
|
@ -98,6 +102,15 @@ public: // state is public because the entire Mork system is private
|
|||
// every nonzero slot in IndexCache is a strong ref to a morkAtomRowMap:
|
||||
morkAtomRowMap* mRowSpace_IndexCache[ morkRowSpace_kPrimeCacheSize ];
|
||||
|
||||
morkDeque mRowSpace_TablesByPriority[ morkPriority_kCount ];
|
||||
|
||||
public: // more specific dirty methods for row space:
|
||||
void SetRowSpaceDirty() { this->SetNodeDirty(); }
|
||||
void SetRowSpaceClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsRowSpaceClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsRowSpaceDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseRowSpace() only if open
|
||||
|
|
|
@ -91,12 +91,18 @@ morkSpace::morkSpace(morkEnv* ev,
|
|||
, mSpace_Scope( inScope )
|
||||
, mSpace_DoAutoIDs( morkBool_kFalse )
|
||||
, mSpace_HaveDoneAutoIDs( morkBool_kFalse )
|
||||
, mSpace_CanDirty( morkBool_kFalse ) // only when store can be dirtied
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioStore && ioSlotHeap )
|
||||
{
|
||||
morkStore::SlotWeakStore(ioStore, ev, &mSpace_Store);
|
||||
|
||||
mSpace_CanDirty = ioStore->mStore_CanDirty;
|
||||
if ( mSpace_CanDirty ) // this new space dirties the store?
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kSpace;
|
||||
}
|
||||
|
@ -132,10 +138,34 @@ morkSpace::NonAsciiSpaceScopeName(morkEnv* ev)
|
|||
ev->NewError("mSpace_Scope > 0x7F");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkSpace::NilSpaceStoreError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mSpace_Store");
|
||||
}
|
||||
|
||||
morkPool* morkSpace::GetSpaceStorePool() const
|
||||
{
|
||||
return &mSpace_Store->mStore_Pool;
|
||||
}
|
||||
|
||||
mork_bool morkSpace::MaybeDirtyStoreAndSpace()
|
||||
{
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( store && store->mStore_CanDirty )
|
||||
{
|
||||
store->SetStoreDirty();
|
||||
mSpace_CanDirty = morkBool_kTrue;
|
||||
}
|
||||
|
||||
if ( mSpace_CanDirty )
|
||||
{
|
||||
this->SetSpaceDirty();
|
||||
return morkBool_kTrue;
|
||||
}
|
||||
|
||||
return morkBool_kFalse;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
|
|
@ -62,7 +62,15 @@ public: // state is public because the entire Mork system is private
|
|||
|
||||
mork_bool mSpace_DoAutoIDs; // whether db should assign member IDs
|
||||
mork_bool mSpace_HaveDoneAutoIDs; // whether actually auto assigned IDs
|
||||
mork_u1 mSpace_Pad[ 2 ]; // pad to u4 alignment
|
||||
mork_bool mSpace_CanDirty; // changes imply the store becomes dirty?
|
||||
mork_u1 mSpace_Pad; // pad to u4 alignment
|
||||
|
||||
public: // more specific dirty methods for space:
|
||||
void SetSpaceDirty() { this->SetNodeDirty(); }
|
||||
void SetSpaceClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsSpaceClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsSpaceDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
|
@ -84,7 +92,10 @@ public: // dynamic type identification
|
|||
|
||||
public: // other space methods
|
||||
|
||||
mork_bool MaybeDirtyStoreAndSpace();
|
||||
|
||||
static void NonAsciiSpaceScopeName(morkEnv* ev);
|
||||
static void NilSpaceStoreError(morkEnv* ev);
|
||||
|
||||
morkPool* GetSpaceStorePool() const;
|
||||
|
||||
|
|
|
@ -222,9 +222,15 @@ morkStore::morkStore(morkEnv* ev, const morkUsage& inUsage,
|
|||
, mStore_AtomSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
|
||||
, mStore_Pool(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
|
||||
|
||||
, mStore_CommitGroupIdentity( 0 )
|
||||
|
||||
, mStore_FirstCommitGroupPos( 0 )
|
||||
, mStore_SecondCommitGroupPos( 0 )
|
||||
|
||||
// disable auto-assignment of atom IDs until someone knows it is okay:
|
||||
, mStore_CanAutoAssignAtomIdentity( morkBool_kFalse )
|
||||
|
||||
, mStore_CanDirty( morkBool_kFalse ) // not until the store is open
|
||||
, mStore_CanWriteIncremental( morkBool_kTrue ) // always with few exceptions
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
|
@ -271,6 +277,82 @@ morkStore::CloseStore(morkEnv* ev) // called by CloseMorkNode();
|
|||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
mork_percent morkStore::PercentOfStoreWasted(morkEnv* ev)
|
||||
{
|
||||
mork_percent outPercent = 0;
|
||||
morkFile* 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 = file->Length(ev); // 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)
|
||||
{
|
||||
|
@ -386,6 +468,8 @@ morkAtomSpace* morkStore::LazyGetGroundAtomSpace(morkEnv* ev)
|
|||
|
||||
if ( space ) // successful space creation?
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
|
||||
mStore_GroundAtomSpace = space; // transfer strong ref to this slot
|
||||
mStore_AtomSpaces.AddAtomSpace(ev, space);
|
||||
}
|
||||
|
@ -404,6 +488,8 @@ morkAtomSpace* morkStore::LazyGetGroundColumnSpace(morkEnv* ev)
|
|||
|
||||
if ( space ) // successful space creation?
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
|
||||
mStore_GroundColumnSpace = space; // transfer strong ref to this slot
|
||||
mStore_AtomSpaces.AddAtomSpace(ev, space);
|
||||
}
|
||||
|
@ -423,6 +509,7 @@ morkStream* morkStore::LazyGetInStream(morkEnv* ev)
|
|||
morkStore_kStreamBufSize, /*frozen*/ morkBool_kTrue);
|
||||
if ( stream )
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
mStore_InStream = stream; // transfer strong ref to this slot
|
||||
}
|
||||
}
|
||||
|
@ -444,6 +531,7 @@ morkStream* morkStore::LazyGetOutStream(morkEnv* ev)
|
|||
morkStore_kStreamBufSize, /*frozen*/ morkBool_kFalse);
|
||||
if ( stream )
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
mStore_InStream = stream; // transfer strong ref to this slot
|
||||
}
|
||||
}
|
||||
|
@ -494,6 +582,8 @@ morkStore::LazyGetRowSpace(morkEnv* ev, mdb_scope inRowScope)
|
|||
|
||||
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
|
||||
|
@ -521,6 +611,8 @@ morkStore::LazyGetAtomSpace(morkEnv* ev, mdb_scope inAtomScope)
|
|||
|
||||
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
|
||||
|
@ -622,8 +714,11 @@ morkStore::YarnToAtom(morkEnv* ev, const mdbYarn* inYarn)
|
|||
morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
|
||||
outAtom = map->GetAtom(ev, keyAtom);
|
||||
if ( !outAtom )
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
outAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
|
||||
}
|
||||
}
|
||||
else if ( ev->Good() )
|
||||
{
|
||||
morkBuf buf(inYarn->mYarn_Buf, inYarn->mYarn_Fill);
|
||||
|
@ -666,6 +761,7 @@ morkStore::MidToOid(morkEnv* ev, const morkMid& inMid, mdbOid* outOid)
|
|||
outOid->mOid_Scope = bookAtom->mBookAtom_Id;
|
||||
else
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
|
||||
if ( bookAtom )
|
||||
{
|
||||
|
@ -856,6 +952,7 @@ morkStore::AddAlias(morkEnv* ev, const morkMid& inMid, mork_cscode inForm)
|
|||
}
|
||||
else
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
keyAtom->mBookAtom_Id = oid->mOid_Id;
|
||||
outAtom = atomSpace->MakeBookAtomCopyWithAid(ev,
|
||||
*keyAtom, (mork_aid) oid->mOid_Id);
|
||||
|
@ -936,6 +1033,7 @@ morkStore::BufToToken(morkEnv* ev, const morkBuf* inBuf)
|
|||
outToken = bookAtom->mBookAtom_Id;
|
||||
else
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
bookAtom = space->MakeBookAtomCopy(ev, *keyAtom);
|
||||
if ( bookAtom )
|
||||
{
|
||||
|
@ -977,6 +1075,7 @@ morkStore::StringToToken(morkEnv* ev, const char* inTokenName)
|
|||
outToken = bookAtom->mBookAtom_Id;
|
||||
else
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
|
||||
if ( bookAtom )
|
||||
{
|
||||
|
@ -1061,7 +1160,7 @@ morkStore::GetTableKind(morkEnv* ev, mdb_scope inRowScope,
|
|||
if ( outTableCount )
|
||||
*outTableCount = outTable->GetRowCount();
|
||||
if ( outMustBeUnique )
|
||||
*outMustBeUnique = outTable->mTable_MustBeUnique;
|
||||
*outMustBeUnique = outTable->IsTableUnique();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,6 +127,7 @@ public: // typesafe refcounting inlines calling inherited morkNode methods
|
|||
#define morkStore_kRowScopeColumn ((mork_column) 'r')
|
||||
#define morkStore_kMetaScope ((mork_scope) 'm')
|
||||
#define morkStore_kKindColumn ((mork_column) 'k')
|
||||
#define morkStore_kStatusColumn ((mork_column) 's')
|
||||
|
||||
/*| morkStore:
|
||||
|*/
|
||||
|
@ -168,13 +169,66 @@ public: // state is public because the entire Mork system is private
|
|||
// we alloc a max size book atom to reuse space for atom map key searches:
|
||||
morkMaxBookAtom mStore_BookAtom; // staging area for atom map searches
|
||||
|
||||
// GroupIdentity should be one more than largest seen in a parsed db file:
|
||||
mork_gid mStore_CommitGroupIdentity; // transaction ID number
|
||||
|
||||
// group positions are used to help compute PercentOfStoreWasted():
|
||||
mork_pos mStore_FirstCommitGroupPos; // start of first group
|
||||
mork_pos mStore_SecondCommitGroupPos; // start of second group
|
||||
// If the first commit group is very near the start of the file (say less
|
||||
// than 512 bytes), then we might assume the file started nearly empty and
|
||||
// that most of the first group is not wasted. In that case, the pos of
|
||||
// the second commit group might make a better estimate of the start of
|
||||
// transaction space that might represent wasted file space. That's why
|
||||
// we support fields for both first and second commit group positions.
|
||||
//
|
||||
// We assume that a zero in either group pos means that the slot has not
|
||||
// yet been given a valid value, since the file will always start with a
|
||||
// tag, and a commit group cannot actually start at position zero.
|
||||
//
|
||||
// Either or both the first or second commit group positions might be
|
||||
// supplied by either morkWriter (while committing) or morkBuilder (while
|
||||
// parsing), since either reading or writing the file might encounter the
|
||||
// first transaction groups which came into existence either in the past
|
||||
// or in the very recent present.
|
||||
|
||||
mork_bool mStore_CanAutoAssignAtomIdentity;
|
||||
mork_u1 mStore_Pad[ 3 ]; // for u4 alignment
|
||||
mork_bool mStore_CanDirty; // changes imply the store becomes dirty?
|
||||
mork_u1 mStore_CanWriteIncremental; // compress not required?
|
||||
mork_u1 mStore_Pad; // for u4 alignment
|
||||
|
||||
public: // coping with any changes to store token slots above:
|
||||
// mStore_CanDirty should be FALSE when parsing a file while building the
|
||||
// content going into the store, because such data structure modifications
|
||||
// are actuallly in sync with the file. So content read from a file must
|
||||
// be clean with respect to the file. After a file is finished parsing,
|
||||
// the mStore_CanDirty slot should become TRUE, so that any additional
|
||||
// changes at runtime cause structures to be marked dirty with respect to
|
||||
// the file which must later be updated with changes during a commit.
|
||||
//
|
||||
// It might also make sense to set mStore_CanDirty to FALSE while a commit
|
||||
// is in progress, lest some internal transformations make more content
|
||||
// appear dirty when it should not. So anyone modifying content during a
|
||||
// commit should think about the intended significance regarding dirty.
|
||||
|
||||
// void SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom,
|
||||
// const mdbOid* inOid);
|
||||
public: // more specific dirty methods for store:
|
||||
void SetStoreDirty() { this->SetNodeDirty(); }
|
||||
void SetStoreClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsStoreClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsStoreDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
public: // setting dirty based on CanDirty:
|
||||
|
||||
void MaybeDirtyStore()
|
||||
{ if ( mStore_CanDirty ) this->SetStoreDirty(); }
|
||||
|
||||
public: // space waste analysis
|
||||
|
||||
mork_percent PercentOfStoreWasted(morkEnv* ev);
|
||||
|
||||
public: // setting store and all subspaces canDirty:
|
||||
|
||||
void SetStoreAndAllSpacesCanDirty(morkEnv* ev, mork_bool inCanDirty);
|
||||
|
||||
public: // building an atom inside mStore_BookAtom from a char* string
|
||||
|
||||
|
|
|
@ -92,6 +92,8 @@ morkStream::morkStream(morkEnv* ev, const morkUsage& inUsage,
|
|||
if ( ioContentFile->FileFrozen() ) // forced to be readonly?
|
||||
inFrozen = morkBool_kTrue; // override the input value
|
||||
|
||||
mork_pos fileEnd = ioContentFile->Length(ev);
|
||||
|
||||
morkFile::SlotStrongFile(ioContentFile, ev, &mStream_ContentFile);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
|
@ -355,6 +357,22 @@ morkStream::PutLineBreak(morkEnv* ev)
|
|||
// public: // virtual morkFile methods
|
||||
|
||||
|
||||
/*public virtual*/ void
|
||||
morkStream::Steal(morkEnv* ev, nsIMdbFile* ioThief)
|
||||
// Steal: tell this file to close any associated i/o stream in the file
|
||||
// system, because the file ioThief intends to reopen the file in order
|
||||
// to provide the MDB implementation with more exotic file access than is
|
||||
// offered by the nsIMdbFile alone. Presumably the thief knows enough
|
||||
// from Path() in order to know which file to reopen. If Steal() is
|
||||
// successful, this file should probably delegate all future calls to
|
||||
// the nsIMdbFile interface down to the thief files, so that even after
|
||||
// the file has been stolen, it can still be read, written, or forcibly
|
||||
// closed (by a call to CloseMdbObject()).
|
||||
{
|
||||
MORK_USED_1(ioThief);
|
||||
ev->StubMethodOnlyError();
|
||||
}
|
||||
|
||||
/*public virtual*/ void
|
||||
morkStream::BecomeTrunk(morkEnv* ev)
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
|
|
|
@ -116,6 +116,17 @@ public: // typing
|
|||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // virtual morkFile methods
|
||||
|
||||
virtual void Steal(morkEnv* ev, nsIMdbFile* ioThief);
|
||||
// Steal: tell this file to close any associated i/o stream in the file
|
||||
// system, because the file ioThief intends to reopen the file in order
|
||||
// to provide the MDB implementation with more exotic file access than is
|
||||
// offered by the nsIMdbFile alone. Presumably the thief knows enough
|
||||
// from Path() in order to know which file to reopen. If Steal() is
|
||||
// successful, this file should probably delegate all future calls to
|
||||
// the nsIMdbFile interface down to the thief files, so that even after
|
||||
// the file has been stolen, it can still be read, written, or forcibly
|
||||
// closed (by a call to CloseMdbObject()).
|
||||
|
||||
virtual void BecomeTrunk(morkEnv* ev);
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
|
|
|
@ -99,22 +99,35 @@ morkTable::morkTable(morkEnv* ev, /*i*/
|
|||
, mTable_RowSpace( 0 )
|
||||
, mTable_MetaRow( 0 )
|
||||
|
||||
, mTable_RowMap(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap,
|
||||
morkTable_kStartRowMapSlotCount)
|
||||
, mTable_RowMap( 0 )
|
||||
// , mTable_RowMap(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap,
|
||||
// morkTable_kStartRowMapSlotCount)
|
||||
, mTable_RowArray(ev, morkUsage::kMember, (nsIMdbHeap*) 0,
|
||||
morkTable_kStartRowArraySize, ioSlotHeap)
|
||||
|
||||
, mTable_ChangeList()
|
||||
, mTable_ChangesCount( 0 )
|
||||
, mTable_ChangesMax( 3 ) // any very small number greater than zero
|
||||
|
||||
, mTable_Id( inTid )
|
||||
, mTable_Kind( inKind )
|
||||
, mTable_MustBeUnique( inMustBeUnique )
|
||||
, mTable_CellUses( 0 )
|
||||
|
||||
, mTable_Flags( 0 )
|
||||
, mTable_Priority( morkPriority_kLo ) // NOT high priority
|
||||
, mTable_GcUses( 0 )
|
||||
, mTable_Pad( 0 )
|
||||
{
|
||||
this->mLink_Next = 0;
|
||||
this->mLink_Prev = 0;
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioStore && ioSlotHeap && ioRowSpace )
|
||||
{
|
||||
if ( inKind )
|
||||
{
|
||||
if ( inMustBeUnique )
|
||||
this->SetTableUnique();
|
||||
morkStore::SlotWeakStore(ioStore, ev, &mTable_Store);
|
||||
morkRowSpace::SlotWeakRowSpace(ioRowSpace, ev, &mTable_RowSpace);
|
||||
if ( inOptionalMetaRowOid )
|
||||
|
@ -125,8 +138,14 @@ morkTable::morkTable(morkEnv* ev, /*i*/
|
|||
mTable_MetaRowOid.mOid_Id = morkRow_kMinusOneRid;
|
||||
}
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndTable() )
|
||||
this->SetTableRewrite(); // everything is dirty
|
||||
|
||||
mNode_Derived = morkDerived_kTable;
|
||||
}
|
||||
this->MaybeDirtySpaceStoreAndTable(); // new table might dirty store
|
||||
}
|
||||
else
|
||||
ioRowSpace->ZeroKindError(ev);
|
||||
}
|
||||
|
@ -142,7 +161,8 @@ morkTable::CloseTable(morkEnv* ev) /*i*/ // called by CloseMorkNode();
|
|||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mTable_RowMap.CloseMorkNode(ev);
|
||||
morkRowMap::SlotStrongRowMap((morkRowMap*) 0, ev, &mTable_RowMap);
|
||||
// mTable_RowMap.CloseMorkNode(ev);
|
||||
mTable_RowArray.CloseMorkNode(ev);
|
||||
morkStore::SlotWeakStore((morkStore*) 0, ev, &mTable_Store);
|
||||
morkRowSpace::SlotWeakRowSpace((morkRowSpace*) 0,
|
||||
|
@ -160,33 +180,106 @@ morkTable::CloseTable(morkEnv* ev) /*i*/ // called by CloseMorkNode();
|
|||
// ````` ````` ````` ````` `````
|
||||
|
||||
mork_u2
|
||||
morkTable::AddCellUse(morkEnv* ev)
|
||||
morkTable::AddTableGcUse(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
if ( mTable_CellUses < morkTable_kMaxCellUses ) // not already maxed out?
|
||||
++mTable_CellUses;
|
||||
if ( mTable_GcUses < morkTable_kMaxTableGcUses ) // not already maxed out?
|
||||
++mTable_GcUses;
|
||||
|
||||
return mTable_CellUses;
|
||||
return mTable_GcUses;
|
||||
}
|
||||
|
||||
mork_u2
|
||||
morkTable::CutCellUse(morkEnv* ev)
|
||||
morkTable::CutTableGcUse(morkEnv* ev)
|
||||
{
|
||||
if ( mTable_CellUses ) // any outstanding uses to cut?
|
||||
if ( mTable_GcUses ) // any outstanding uses to cut?
|
||||
{
|
||||
if ( mTable_CellUses < morkTable_kMaxCellUses ) // not frozen at max?
|
||||
--mTable_CellUses;
|
||||
if ( mTable_GcUses < morkTable_kMaxTableGcUses ) // not frozen at max?
|
||||
--mTable_GcUses;
|
||||
}
|
||||
else
|
||||
this->CellUsesUnderflowWarning(ev);
|
||||
this->TableGcUsesUnderflowWarning(ev);
|
||||
|
||||
return mTable_CellUses;
|
||||
return mTable_GcUses;
|
||||
}
|
||||
|
||||
// table dirty handling more complex thatn morkNode::SetNodeDirty() etc.
|
||||
|
||||
void morkTable::SetTableClean(morkEnv* ev)
|
||||
{
|
||||
nsIMdbHeap* heap = mTable_Store->mPort_Heap;
|
||||
mTable_ChangeList.CutAndZapAllListMembers(ev, heap); // forget changes
|
||||
mTable_ChangesCount = 0;
|
||||
|
||||
mTable_Flags = 0;
|
||||
this->SetNodeClean();
|
||||
}
|
||||
|
||||
// notifications regarding table changes:
|
||||
|
||||
void morkTable::NoteTableMoveRow(morkEnv* ev, morkRow* ioRow, mork_pos inPos)
|
||||
{
|
||||
nsIMdbHeap* heap = mTable_Store->mPort_Heap;
|
||||
if ( this->IsTableRewrite() || this->HasChangeOverflow() )
|
||||
this->NoteTableSetAll(ev);
|
||||
else
|
||||
{
|
||||
morkTableChange* tableChange = new(*heap, ev)
|
||||
morkTableChange(ev, ioRow, inPos);
|
||||
if ( tableChange )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mTable_ChangeList.PushTail(tableChange);
|
||||
++mTable_ChangesCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
tableChange->ZapOldNext(ev, heap);
|
||||
this->SetTableRewrite(); // just plan to write all table rows
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void morkTable::note_row_change(morkEnv* ev, mork_change inChange,
|
||||
morkRow* ioRow)
|
||||
{
|
||||
if ( this->IsTableRewrite() || this->HasChangeOverflow() )
|
||||
this->NoteTableSetAll(ev);
|
||||
else
|
||||
{
|
||||
nsIMdbHeap* heap = mTable_Store->mPort_Heap;
|
||||
morkTableChange* tableChange = new(*heap, ev)
|
||||
morkTableChange(ev, inChange, ioRow);
|
||||
if ( tableChange )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mTable_ChangeList.PushTail(tableChange);
|
||||
++mTable_ChangesCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
tableChange->ZapOldNext(ev, heap);
|
||||
this->NoteTableSetAll(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void morkTable::NoteTableSetAll(morkEnv* ev)
|
||||
{
|
||||
nsIMdbHeap* heap = mTable_Store->mPort_Heap;
|
||||
mTable_ChangeList.CutAndZapAllListMembers(ev, heap); // forget changes
|
||||
mTable_ChangesCount = 0;
|
||||
this->SetTableRewrite();
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkTable::CellUsesUnderflowWarning(morkEnv* ev)
|
||||
morkTable::TableGcUsesUnderflowWarning(morkEnv* ev)
|
||||
{
|
||||
ev->NewWarning("mTable_CellUses underflow");
|
||||
ev->NewWarning("mTable_GcUses underflow");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
|
@ -207,6 +300,38 @@ morkTable::NilRowSpaceError(morkEnv* ev)
|
|||
ev->NewError("nil mTable_RowSpace");
|
||||
}
|
||||
|
||||
mork_bool morkTable::MaybeDirtySpaceStoreAndTable()
|
||||
{
|
||||
morkRowSpace* rowSpace = mTable_RowSpace;
|
||||
if ( rowSpace )
|
||||
{
|
||||
morkStore* store = rowSpace->mSpace_Store;
|
||||
if ( store && store->mStore_CanDirty )
|
||||
{
|
||||
store->SetStoreDirty();
|
||||
rowSpace->mSpace_CanDirty = morkBool_kTrue;
|
||||
}
|
||||
|
||||
if ( rowSpace->mSpace_CanDirty ) // first time being dirtied?
|
||||
{
|
||||
if ( this->IsTableClean() )
|
||||
{
|
||||
mork_count rowCount = this->GetRowCount();
|
||||
mork_count oneThird = rowCount / 4; // one third of rows
|
||||
if ( oneThird > 0x07FFF ) // more than half max u2?
|
||||
oneThird = 0x07FFF;
|
||||
|
||||
mTable_ChangesMax = (mork_u2) oneThird;
|
||||
}
|
||||
this->SetTableDirty();
|
||||
rowSpace->SetRowSpaceDirty();
|
||||
|
||||
return morkBool_kTrue;
|
||||
}
|
||||
}
|
||||
return morkBool_kFalse;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkTable::GetMetaRow(morkEnv* ev, const mdbOid* inOptionalMetaRowOid)
|
||||
{
|
||||
|
@ -228,7 +353,13 @@ morkTable::GetMetaRow(morkEnv* ev, const mdbOid* inOptionalMetaRowOid)
|
|||
}
|
||||
mTable_MetaRow = outRow;
|
||||
if ( outRow ) // need to note another use of this row?
|
||||
outRow->AddTableUse(ev);
|
||||
{
|
||||
outRow->AddRowGcUse(ev);
|
||||
|
||||
this->SetTableNewMeta();
|
||||
if ( this->IsTableClean() ) // catch dirty status of meta row?
|
||||
this->MaybeDirtySpaceStoreAndTable();
|
||||
}
|
||||
}
|
||||
|
||||
return outRow;
|
||||
|
@ -285,26 +416,88 @@ morkTable::ArrayHasOid(morkEnv* ev, const mdbOid* inOid)
|
|||
mork_bool
|
||||
morkTable::MapHasOid(morkEnv* ev, const mdbOid* inOid)
|
||||
{
|
||||
return ( mTable_RowMap.GetOid(ev, inOid) != 0 );
|
||||
if ( mTable_RowMap )
|
||||
return ( mTable_RowMap->GetOid(ev, inOid) != 0 );
|
||||
else
|
||||
return ( ArrayHasOid(ev, inOid) >= 0 );
|
||||
}
|
||||
|
||||
void morkTable::build_row_map(morkEnv* ev)
|
||||
{
|
||||
morkRowMap* map = mTable_RowMap;
|
||||
if ( !map )
|
||||
{
|
||||
mork_count count = mTable_RowArray.mArray_Fill + 3;
|
||||
nsIMdbHeap* heap = mTable_Store->mPort_Heap;
|
||||
map = new(*heap, ev) morkRowMap(ev, morkUsage::kHeap, heap, heap, count);
|
||||
if ( map )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mTable_RowMap = map; // put strong ref here
|
||||
mork_count count = mTable_RowArray.mArray_Fill;
|
||||
mork_pos pos = -1;
|
||||
while ( ++pos < count )
|
||||
{
|
||||
morkRow* row = (morkRow*) mTable_RowArray.At(pos);
|
||||
if ( row && row->IsRow() )
|
||||
map->AddRow(ev, row);
|
||||
else
|
||||
row->NonRowTypeError(ev);
|
||||
}
|
||||
}
|
||||
else
|
||||
map->CutStrongRef(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
morkRow* morkTable::find_member_row(morkEnv* ev, morkRow* ioRow)
|
||||
{
|
||||
if ( mTable_RowMap )
|
||||
return mTable_RowMap->GetRow(ev, ioRow);
|
||||
else
|
||||
{
|
||||
mork_count count = mTable_RowArray.mArray_Fill;
|
||||
mork_pos pos = -1;
|
||||
while ( ++pos < count )
|
||||
{
|
||||
morkRow* row = (morkRow*) mTable_RowArray.At(pos);
|
||||
if ( row == ioRow )
|
||||
return row;
|
||||
}
|
||||
}
|
||||
return (morkRow*) 0;
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkTable::AddRow(morkEnv* ev, morkRow* ioRow)
|
||||
{
|
||||
morkRow* row = mTable_RowMap.GetRow(ev, ioRow);
|
||||
morkRow* row = this->find_member_row(ev, ioRow);
|
||||
if ( !row && ev->Good() )
|
||||
{
|
||||
mork_bool canDirty = ( this->IsTableClean() )?
|
||||
this->MaybeDirtySpaceStoreAndTable() : morkBool_kTrue;
|
||||
|
||||
mork_pos pos = mTable_RowArray.AppendSlot(ev, ioRow);
|
||||
if ( ev->Good() && pos >= 0 )
|
||||
{
|
||||
ioRow->AddTableUse(ev);
|
||||
if ( mTable_RowMap.AddRow(ev, ioRow) )
|
||||
ioRow->AddRowGcUse(ev);
|
||||
if ( mTable_RowMap )
|
||||
{
|
||||
if ( mTable_RowMap->AddRow(ev, ioRow) )
|
||||
{
|
||||
// okay, anything else?
|
||||
}
|
||||
else
|
||||
mTable_RowArray.CutSlot(ev, pos);
|
||||
}
|
||||
else if ( mTable_RowArray.mArray_Fill >= morkTable_kMakeRowMapThreshold )
|
||||
this->build_row_map(ev);
|
||||
|
||||
if ( canDirty && ev->Good() )
|
||||
this->NoteTableAddRow(ev, ioRow);
|
||||
}
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
@ -312,9 +505,12 @@ morkTable::AddRow(morkEnv* ev, morkRow* ioRow)
|
|||
mork_bool
|
||||
morkTable::CutRow(morkEnv* ev, morkRow* ioRow)
|
||||
{
|
||||
morkRow* row = mTable_RowMap.GetRow(ev, ioRow);
|
||||
morkRow* row = this->find_member_row(ev, ioRow);
|
||||
if ( row )
|
||||
{
|
||||
mork_bool canDirty = ( this->IsTableClean() )?
|
||||
this->MaybeDirtySpaceStoreAndTable() : morkBool_kTrue;
|
||||
|
||||
mork_count count = mTable_RowArray.mArray_Fill;
|
||||
morkRow** rowSlots = (morkRow**) mTable_RowArray.mArray_Slots;
|
||||
if ( rowSlots ) // array has vector as expected?
|
||||
|
@ -338,9 +534,50 @@ morkTable::CutRow(morkEnv* ev, morkRow* ioRow)
|
|||
else
|
||||
mTable_RowArray.NilSlotsAddressError(ev);
|
||||
|
||||
mTable_RowMap.CutRow(ev, ioRow);
|
||||
if ( ioRow->CutTableUse(ev) == 0 )
|
||||
ioRow->OnZeroTableUse(ev);
|
||||
if ( mTable_RowMap )
|
||||
mTable_RowMap->CutRow(ev, ioRow);
|
||||
|
||||
if ( canDirty )
|
||||
this->NoteTableCutRow(ev, ioRow);
|
||||
|
||||
if ( ioRow->CutRowGcUse(ev) == 0 )
|
||||
ioRow->OnZeroRowGcUse(ev);
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
|
||||
mork_bool
|
||||
morkTable::CutAllRows(morkEnv* ev)
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndTable() )
|
||||
{
|
||||
this->SetTableRewrite(); // everything is dirty
|
||||
this->NoteTableSetAll(ev);
|
||||
}
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mTable_RowArray.CutAllSlots(ev);
|
||||
if ( mTable_RowMap )
|
||||
{
|
||||
morkRowMapIter i(ev, mTable_RowMap);
|
||||
mork_change* c = 0;
|
||||
morkRow* r = 0;
|
||||
|
||||
for ( c = i.FirstRow(ev, &r); c; c = i.NextRow(ev, &r) )
|
||||
{
|
||||
if ( r )
|
||||
{
|
||||
if ( r->CutRowGcUse(ev) == 0 )
|
||||
r->OnZeroRowGcUse(ev);
|
||||
|
||||
i.CutHereRow(ev, (morkRow**) 0);
|
||||
}
|
||||
else
|
||||
ev->NewWarning("nil row in table map");
|
||||
}
|
||||
}
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
@ -367,6 +604,65 @@ morkTable::NewTableRowCursor(morkEnv* ev, mork_pos inRowPos)
|
|||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
morkTableChange::morkTableChange(morkEnv* ev, mork_change inChange,
|
||||
morkRow* ioRow)
|
||||
// use this constructor for inChange == morkChange_kAdd or morkChange_kCut
|
||||
: morkNext()
|
||||
, mTableChange_Row( ioRow )
|
||||
, mTableChange_Pos( morkTableChange_kNone )
|
||||
{
|
||||
if ( ioRow )
|
||||
{
|
||||
if ( ioRow->IsRow() )
|
||||
{
|
||||
if ( inChange == morkChange_kAdd )
|
||||
mTableChange_Pos = morkTableChange_kAdd;
|
||||
else if ( inChange == morkChange_kCut )
|
||||
mTableChange_Pos = morkTableChange_kCut;
|
||||
else
|
||||
this->UnknownChangeError(ev);
|
||||
}
|
||||
else
|
||||
ioRow->NonRowTypeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
morkTableChange::morkTableChange(morkEnv* ev, morkRow* ioRow, mork_pos inPos)
|
||||
// use this constructor when the row is moved
|
||||
: morkNext()
|
||||
, mTableChange_Row( ioRow )
|
||||
, mTableChange_Pos( inPos )
|
||||
{
|
||||
if ( ioRow )
|
||||
{
|
||||
if ( ioRow->IsRow() )
|
||||
{
|
||||
if ( inPos < 0 )
|
||||
this->NegativeMovePosError(ev);
|
||||
}
|
||||
else
|
||||
ioRow->NonRowTypeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
void morkTableChange::UnknownChangeError(morkEnv* ev) const
|
||||
// morkChange_kAdd or morkChange_kCut
|
||||
{
|
||||
ev->NewError("mTableChange_Pos neither kAdd nor kCut");
|
||||
}
|
||||
|
||||
void morkTableChange::NegativeMovePosError(morkEnv* ev) const
|
||||
// move must be non-neg position
|
||||
{
|
||||
ev->NewError("negative mTableChange_Pos for row move");
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
morkTableMap::~morkTableMap()
|
||||
{
|
||||
|
@ -380,5 +676,4 @@ morkTableMap::morkTableMap(morkEnv* ev, const morkUsage& inUsage,
|
|||
mNode_Derived = morkDerived_kTableMap;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
@ -48,12 +52,36 @@
|
|||
class nsIMdbTable;
|
||||
#define morkDerived_kTable /*i*/ 0x5462 /* ascii 'Tb' */
|
||||
|
||||
#define morkTable_kStartRowArraySize 11 /* modest starting size for array */
|
||||
/*| kStartRowArraySize: starting physical size of array for mTable_RowArray.
|
||||
**| We want this number very small, so that a table containing exactly one
|
||||
**| row member will not pay too significantly in space overhead. But we want
|
||||
**| a number bigger than one, so there is some space for growth.
|
||||
|*/
|
||||
#define morkTable_kStartRowArraySize 3 /* modest starting size for array */
|
||||
|
||||
#define morkTable_kStartRowMapSlotCount 128
|
||||
#define morkTable_kMaxCellUses 0x0FFFF /* max for 16-bit unsigned int */
|
||||
/*| kMakeRowMapThreshold: this is the number of rows in a table which causes
|
||||
**| a hash table (mTable_RowMap) to be lazily created for faster member row
|
||||
**| identification, during such operations as cuts and adds. This number must
|
||||
**| be small enough that linear searches are not bad for member counts less
|
||||
**| than this; but this number must also be large enough that creating a hash
|
||||
**| table does not increase the per-row space overhead by a big percentage.
|
||||
**| For speed, numbers on the order of ten to twenty are all fine; for space,
|
||||
**| I believe a number as small as ten will have too much space overhead.
|
||||
|*/
|
||||
#define morkTable_kMakeRowMapThreshold 17 /* when to build mTable_RowMap */
|
||||
|
||||
class morkTable : public morkObject {
|
||||
#define morkTable_kStartRowMapSlotCount 13
|
||||
#define morkTable_kMaxTableGcUses 0x0FF /* max for 8-bit unsigned int */
|
||||
|
||||
#define morkTable_kUniqueBit ((mork_u1) (1 << 0))
|
||||
#define morkTable_kVerboseBit ((mork_u1) (1 << 1))
|
||||
#define morkTable_kNotedBit ((mork_u1) (1 << 2)) /* space has change notes */
|
||||
#define morkTable_kRewriteBit ((mork_u1) (1 << 3)) /* must rewrite all rows */
|
||||
#define morkTable_kNewMetaBit ((mork_u1) (1 << 4)) /* new table meta row */
|
||||
|
||||
class morkTable : public morkObject, public morkLink {
|
||||
|
||||
// NOTE the morkLink base is for morkRowSpace::mRowSpace_TablesByPriority
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
@ -74,7 +102,6 @@ class morkTable : public morkObject {
|
|||
public: // state is public because the entire Mork system is private
|
||||
|
||||
morkStore* mTable_Store; // weak ref to port
|
||||
// mork_seed mTable_Seed; // use TableSeed() instead
|
||||
|
||||
// mTable_RowSpace->mSpace_Scope is row scope
|
||||
morkRowSpace* mTable_RowSpace; // weak ref to containing space
|
||||
|
@ -82,15 +109,65 @@ public: // state is public because the entire Mork system is private
|
|||
morkRow* mTable_MetaRow; // table's actual meta row
|
||||
mdbOid mTable_MetaRowOid; // oid for meta row
|
||||
|
||||
morkRowMap mTable_RowMap; // hash table of all members
|
||||
morkRowMap* mTable_RowMap; // (strong ref) hash table of all members
|
||||
morkArray mTable_RowArray; // array of morkRow pointers
|
||||
|
||||
morkList mTable_ChangeList; // list of table changes
|
||||
mork_u2 mTable_ChangesCount; // length of changes list
|
||||
mork_u2 mTable_ChangesMax; // max list length before rewrite
|
||||
|
||||
mork_tid mTable_Id;
|
||||
mork_kind mTable_Kind;
|
||||
|
||||
mork_bool mTable_MustBeUnique;
|
||||
mork_u1 mTable_Pad; // padding for u4 alignment
|
||||
mork_u2 mTable_CellUses; // persistent references from cells
|
||||
mork_u1 mTable_Flags; // bit flags
|
||||
mork_priority mTable_Priority; // 0..9, any other value equals 9
|
||||
mork_u1 mTable_GcUses; // persistent references from cells
|
||||
mork_u1 mTable_Pad; // for u4 alignment
|
||||
|
||||
public: // flags bit twiddling
|
||||
|
||||
void SetTableUnique() { mTable_Flags |= morkTable_kUniqueBit; }
|
||||
void SetTableVerbose() { mTable_Flags |= morkTable_kVerboseBit; }
|
||||
void SetTableNoted() { mTable_Flags |= morkTable_kNotedBit; }
|
||||
void SetTableRewrite() { mTable_Flags |= morkTable_kRewriteBit; }
|
||||
void SetTableNewMeta() { mTable_Flags |= morkTable_kNewMetaBit; }
|
||||
|
||||
void ClearTableUnique() { mTable_Flags &= (mork_u1) ~morkTable_kUniqueBit; }
|
||||
void ClearTableVerbose() { mTable_Flags &= (mork_u1) ~morkTable_kVerboseBit; }
|
||||
void ClearTableNoted() { mTable_Flags &= (mork_u1) ~morkTable_kNotedBit; }
|
||||
void ClearTableRewrite() { mTable_Flags &= (mork_u1) ~morkTable_kRewriteBit; }
|
||||
void ClearTableNewMeta() { mTable_Flags &= (mork_u1) ~morkTable_kNewMetaBit; }
|
||||
|
||||
mork_bool IsTableUnique() const
|
||||
{ return ( mTable_Flags & morkTable_kUniqueBit ) != 0; }
|
||||
|
||||
mork_bool IsTableVerbose() const
|
||||
{ return ( mTable_Flags & morkTable_kVerboseBit ) != 0; }
|
||||
|
||||
mork_bool IsTableNoted() const
|
||||
{ return ( mTable_Flags & morkTable_kNotedBit ) != 0; }
|
||||
|
||||
mork_bool IsTableRewrite() const
|
||||
{ return ( mTable_Flags & morkTable_kRewriteBit ) != 0; }
|
||||
|
||||
mork_bool IsTableNewMeta() const
|
||||
{ return ( mTable_Flags & morkTable_kNewMetaBit ) != 0; }
|
||||
|
||||
public: // table dirty handling more complex than morkNode::SetNodeDirty() etc.
|
||||
|
||||
void SetTableDirty() { this->SetNodeDirty(); }
|
||||
void SetTableClean(morkEnv* ev);
|
||||
|
||||
mork_bool IsTableClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsTableDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
public: // morkNode memory management operators
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{ return morkNode::MakeNew(inSize, ioHeap, ev); }
|
||||
|
||||
void operator delete(void* ioAddress)
|
||||
{ morkNode::OnDeleteAssert(ioAddress); }
|
||||
// do NOT call delete on morkNode instances. Call ZapOld() instead.
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
|
@ -121,14 +198,37 @@ public: // errors
|
|||
static void NilRowSpaceError(morkEnv* ev);
|
||||
|
||||
public: // warnings
|
||||
static void CellUsesUnderflowWarning(morkEnv* ev);
|
||||
static void TableGcUsesUnderflowWarning(morkEnv* ev);
|
||||
|
||||
public: // noting table changes
|
||||
|
||||
mork_bool HasChangeOverflow() const
|
||||
{ return mTable_ChangesCount >= mTable_ChangesMax; }
|
||||
|
||||
void NoteTableSetAll(morkEnv* ev);
|
||||
void NoteTableMoveRow(morkEnv* ev, morkRow* ioRow, mork_pos inPos);
|
||||
|
||||
void note_row_change(morkEnv* ev, mork_change inChange, morkRow* ioRow);
|
||||
|
||||
void NoteTableAddRow(morkEnv* ev, morkRow* ioRow)
|
||||
{ this->note_row_change(ev, morkChange_kAdd, ioRow); }
|
||||
|
||||
void NoteTableCutRow(morkEnv* ev, morkRow* ioRow)
|
||||
{ this->note_row_change(ev, morkChange_kCut, ioRow); }
|
||||
|
||||
protected: // internal row map methods
|
||||
|
||||
morkRow* find_member_row(morkEnv* ev, morkRow* ioRow);
|
||||
void build_row_map(morkEnv* ev);
|
||||
|
||||
public: // other table methods
|
||||
|
||||
mork_bool MaybeDirtySpaceStoreAndTable();
|
||||
|
||||
morkRow* GetMetaRow(morkEnv* ev, const mdbOid* inOptionalMetaRowOid);
|
||||
|
||||
mork_u2 AddCellUse(morkEnv* ev);
|
||||
mork_u2 CutCellUse(morkEnv* ev);
|
||||
mork_u2 AddTableGcUse(morkEnv* ev);
|
||||
mork_u2 CutTableGcUse(morkEnv* ev);
|
||||
|
||||
// void DirtyAllTableContent(morkEnv* ev);
|
||||
|
||||
|
@ -146,6 +246,7 @@ public: // other table methods
|
|||
mork_bool MapHasOid(morkEnv* ev, const mdbOid* inOid);
|
||||
mork_bool AddRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good()
|
||||
mork_bool CutRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good()
|
||||
mork_bool CutAllRows(morkEnv* ev); // returns ev->Good()
|
||||
|
||||
morkTableRowCursor* NewTableRowCursor(morkEnv* ev, mork_pos inRowPos);
|
||||
|
||||
|
@ -161,6 +262,48 @@ public: // typesafe refcounting inlines calling inherited morkNode methods
|
|||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// use negative values for kCut and kAdd, to keep non-neg move pos distinct:
|
||||
#define morkTableChange_kCut ((mork_pos) -1) /* shows row was cut */
|
||||
#define morkTableChange_kAdd ((mork_pos) -2) /* shows row was added */
|
||||
#define morkTableChange_kNone ((mork_pos) -3) /* unknown change */
|
||||
|
||||
class morkTableChange : public morkNext {
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
morkRow* mTableChange_Row; // the row in the change
|
||||
|
||||
mork_pos mTableChange_Pos; // kAdd, kCut, or non-neg for row move
|
||||
|
||||
public:
|
||||
morkTableChange(morkEnv* ev, mork_change inChange, morkRow* ioRow);
|
||||
// use this constructor for inChange == morkChange_kAdd or morkChange_kCut
|
||||
|
||||
morkTableChange(morkEnv* ev, morkRow* ioRow, mork_pos inPos);
|
||||
// use this constructor when the row is moved
|
||||
|
||||
public:
|
||||
void UnknownChangeError(morkEnv* ev) const; // morkChange_kAdd or morkChange_kCut
|
||||
void NegativeMovePosError(morkEnv* ev) const; // move must be non-neg position
|
||||
|
||||
public:
|
||||
|
||||
mork_bool IsAddRowTableChange() const
|
||||
{ return ( mTableChange_Pos == morkTableChange_kAdd ); }
|
||||
|
||||
mork_bool IsCutRowTableChange() const
|
||||
{ return ( mTableChange_Pos == morkTableChange_kCut ); }
|
||||
|
||||
mork_bool IsMoveRowTableChange() const
|
||||
{ return ( mTableChange_Pos >= 0 ); }
|
||||
|
||||
public:
|
||||
|
||||
mork_pos GetMovePos() const { return mTableChange_Pos; }
|
||||
// GetMovePos() assumes that IsMoveRowTableChange() is true.
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kTableMap /*i*/ 0x744D /* ascii 'tM' */
|
||||
|
||||
/*| morkTableMap: maps mork_token -> morkTable
|
||||
|
@ -214,6 +357,7 @@ public:
|
|||
HereTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
|
||||
{ return this->Here(ev, outTid, outTable); }
|
||||
|
||||
// cutting while iterating hash map might dirty the parent table:
|
||||
mork_change*
|
||||
CutHereTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
|
||||
{ return this->CutHere(ev, outTid, outTable); }
|
||||
|
|
|
@ -241,6 +241,45 @@ morkThumb::Make_OpenFileStore(morkEnv* ev, nsIMdbHeap* ioHeap,
|
|||
}
|
||||
|
||||
|
||||
/*static*/ morkThumb*
|
||||
morkThumb::Make_LargeCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore)
|
||||
{
|
||||
morkThumb* outThumb = 0;
|
||||
if ( ioHeap && ioStore )
|
||||
{
|
||||
morkFile* file = ioStore->mStore_File;
|
||||
if ( file )
|
||||
{
|
||||
outThumb = new(*ioHeap, ev)
|
||||
morkThumb(ev, morkUsage::kHeap, ioHeap, ioHeap,
|
||||
morkThumb_kMagic_LargeCommit);
|
||||
|
||||
if ( outThumb )
|
||||
{
|
||||
morkWriter* writer = new(*ioHeap, ev)
|
||||
morkWriter(ev, morkUsage::kHeap, ioHeap, ioStore, file, ioHeap);
|
||||
if ( writer )
|
||||
{
|
||||
writer->mWriter_CommitGroupIdentity =
|
||||
++ioStore->mStore_CommitGroupIdentity;
|
||||
writer->mWriter_NeedDirtyAll = morkBool_kFalse;
|
||||
outThumb->mThumb_DoCollect = morkBool_kFalse;
|
||||
morkStore::SlotStrongStore(ioStore, ev, &outThumb->mThumb_Store);
|
||||
morkFile::SlotStrongFile(file, ev, &outThumb->mThumb_File);
|
||||
morkWriter::SlotStrongWriter(writer, ev, &outThumb->mThumb_Writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ioStore->NilStoreFileError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return outThumb;
|
||||
}
|
||||
|
||||
/*static*/ morkThumb*
|
||||
morkThumb::Make_CompressCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore, mork_bool inDoCollect)
|
||||
|
@ -266,6 +305,10 @@ morkThumb::Make_CompressCommit(morkEnv* ev,
|
|||
morkStore::SlotStrongStore(ioStore, ev, &outThumb->mThumb_Store);
|
||||
morkFile::SlotStrongFile(file, ev, &outThumb->mThumb_File);
|
||||
morkWriter::SlotStrongWriter(writer, ev, &outThumb->mThumb_Writer);
|
||||
|
||||
// cope with fact that parsed transaction groups are going away:
|
||||
ioStore->mStore_FirstCommitGroupPos = 0;
|
||||
ioStore->mStore_SecondCommitGroupPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -406,15 +449,15 @@ void morkThumb::DoMore_ImportContent(morkEnv* ev)
|
|||
|
||||
void morkThumb::DoMore_LargeCommit(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
this->DoMore_Commit(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_SessionCommit(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
this->DoMore_Commit(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_CompressCommit(morkEnv* ev)
|
||||
void morkThumb::DoMore_Commit(morkEnv* ev)
|
||||
{
|
||||
morkWriter* writer = mThumb_Writer;
|
||||
if ( writer )
|
||||
|
@ -433,6 +476,11 @@ void morkThumb::DoMore_CompressCommit(morkEnv* ev)
|
|||
}
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_CompressCommit(morkEnv* ev)
|
||||
{
|
||||
this->DoMore_Commit(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_SearchManyColumns(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
|
|
|
@ -128,6 +128,7 @@ public: // 'do more' methods
|
|||
void DoMore_LargeCommit(morkEnv* ev);
|
||||
void DoMore_SessionCommit(morkEnv* ev);
|
||||
void DoMore_CompressCommit(morkEnv* ev);
|
||||
void DoMore_Commit(morkEnv* ev);
|
||||
void DoMore_SearchManyColumns(morkEnv* ev);
|
||||
void DoMore_NewSortColumn(morkEnv* ev);
|
||||
void DoMore_NewSortColumnWithCompare(morkEnv* ev);
|
||||
|
@ -150,6 +151,9 @@ public: // assorted thumb constructors
|
|||
static morkThumb* Make_CompressCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore, mork_bool inDoCollect);
|
||||
|
||||
static morkThumb* Make_LargeCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore);
|
||||
|
||||
// { ===== begin non-poly methods imitating nsIMdbThumb =====
|
||||
void GetProgress(morkEnv* ev, mdb_count* outTotal,
|
||||
mdb_count* outCurrent, mdb_bool* outDone, mdb_bool* outBroken);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -103,6 +103,8 @@
|
|||
#define morkWriter_kRowCellDepth 4 /* */
|
||||
#define morkWriter_kRowCellValueDepth 6 /* */
|
||||
|
||||
#define morkWriter_kGroupBufSize 64 /* */
|
||||
|
||||
// v=1.1 retired on 23-Mar-99 (for metainfo one char column names)
|
||||
// v=1.2 retired on 20-Apr-99 (for ":c" suffix on table kind hex refs)
|
||||
// v=1.3 retired on 20-Apr-99 (for 1CE:m instead of ill-formed 1CE:^6D)
|
||||
|
@ -129,6 +131,13 @@ public: // state is public because the entire Mork system is private
|
|||
morkStream* mWriter_Stream; // strong ref to stream on bud file
|
||||
nsIMdbHeap* mWriter_SlotHeap; // strong ref to slot heap
|
||||
|
||||
// GroupIdentity should be based on mStore_CommitGroupIdentity:
|
||||
mork_gid mWriter_CommitGroupIdentity; // transaction ID number
|
||||
|
||||
// GroupBuf holds a hex version of mWriter_CommitGroupIdentity:
|
||||
char mWriter_GroupBuf[ morkWriter_kGroupBufSize ];
|
||||
mork_fill mWriter_GroupBufFill; // actual bytes in GroupBuf
|
||||
|
||||
mork_count mWriter_TotalCount; // count of all things to be written
|
||||
mork_count mWriter_DoneCount; // count of things already written
|
||||
|
||||
|
@ -149,11 +158,18 @@ public: // state is public because the entire Mork system is private
|
|||
mork_scope mWriter_DictAtomScope; // current atom scope
|
||||
|
||||
mork_bool mWriter_NeedDirtyAll; // need to call DirtyAll()
|
||||
mork_u1 mWriter_Phase; // status of writing process
|
||||
mork_bool mWriter_Incremental; // opposite of mWriter_NeedDirtyAll
|
||||
mork_bool mWriter_DidStartDict; // true when a dict has been started
|
||||
mork_bool mWriter_DidEndDict; // true when a dict has been ended
|
||||
|
||||
mork_bool mWriter_SuppressDirtyRowNewline; // for table meta rows
|
||||
mork_bool mWriter_DidStartGroup; // true when a group has been started
|
||||
mork_bool mWriter_DidEndGroup; // true when a group has been ended
|
||||
mork_u1 mWriter_Phase; // status of writing process
|
||||
|
||||
mork_bool mWriter_BeVerbose; // driven by env and table verbose settings:
|
||||
// mWriter_BeVerbose equals ( ev->mEnv_BeVerbose || table->IsTableVerbose() )
|
||||
|
||||
mork_u1 mWriter_Pad[ 3 ]; // for u4 alignment
|
||||
|
||||
mork_pos mWriter_TableRowArrayPos; // index into mTable_RowArray
|
||||
|
@ -202,9 +218,11 @@ public: // typing & errors
|
|||
static void NilWriterStoreError(morkEnv* ev);
|
||||
static void NilWriterBudError(morkEnv* ev);
|
||||
static void NilWriterStreamError(morkEnv* ev);
|
||||
static void NilWriterFileError(morkEnv* ev);
|
||||
static void UnsupportedPhaseError(morkEnv* ev);
|
||||
|
||||
public: // utitlities
|
||||
void ChangeRowForm(morkEnv* ev, mork_cscode inNewForm);
|
||||
void ChangeDictForm(morkEnv* ev, mork_cscode inNewForm);
|
||||
void ChangeDictAtomScope(morkEnv* ev, mork_scope inScope);
|
||||
|
||||
|
@ -228,6 +246,10 @@ public: // inlines
|
|||
mWriter_LineSize = mWriter_Stream->PutIndent(ev, inDepth);
|
||||
}
|
||||
|
||||
public: // delayed construction
|
||||
|
||||
void MakeWriterStream(morkEnv* ev); // give writer a suitable stream
|
||||
|
||||
public: // iterative/asynchronous writing
|
||||
|
||||
mork_bool WriteMore(morkEnv* ev); // call until IsWritingDone() is true
|
||||
|
@ -247,6 +269,12 @@ public: // marking all content dirty
|
|||
// written only at need (because of being dirty). Note the method can
|
||||
// stop early when any error happens, since this will abort any commit.
|
||||
|
||||
public: // group commit transactions
|
||||
|
||||
mork_bool StartGroup(morkEnv* ev);
|
||||
mork_bool CommitGroup(morkEnv* ev);
|
||||
mork_bool AbortGroup(morkEnv* ev);
|
||||
|
||||
public: // phase methods
|
||||
mork_bool OnNothingDone(morkEnv* ev);
|
||||
mork_bool OnDirtyAllDone(morkEnv* ev);
|
||||
|
@ -275,6 +303,12 @@ public: // writing node content second pass
|
|||
mork_bool PutTable(morkEnv* ev, morkTable* ioTable);
|
||||
mork_bool PutRow(morkEnv* ev, morkRow* ioRow);
|
||||
mork_bool PutRowCells(morkEnv* ev, morkRow* ioRow);
|
||||
mork_bool PutVerboseRowCells(morkEnv* ev, morkRow* ioRow);
|
||||
|
||||
mork_bool PutCell(morkEnv* ev, morkCell* ioCell, mork_bool inWithVal);
|
||||
mork_bool PutVerboseCell(morkEnv* ev, morkCell* ioCell, mork_bool inWithVal);
|
||||
|
||||
mork_bool PutTableChange(morkEnv* ev, const morkTableChange* inChange);
|
||||
|
||||
public: // other writer methods
|
||||
|
||||
|
|
|
@ -299,6 +299,8 @@ orkinCell::SetBlob(nsIMdbEnv* mev,
|
|||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -317,6 +319,8 @@ orkinCell::ClearBlob( // make empty (so content has zero length)
|
|||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -363,7 +367,11 @@ orkinCell::SetYarn(nsIMdbEnv* mev,
|
|||
{
|
||||
morkStore* store = row->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
cell->SetYarn(ev, inYarn, store);
|
||||
if ( row->IsRowClean() && store->mStore_CanDirty )
|
||||
row->MaybeDirtySpaceStoreAndRow();
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
@ -429,8 +437,11 @@ orkinCell::SetColumn(nsIMdbEnv* mev, mdb_column inColumn)
|
|||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
morkCellObject* cellObj;
|
||||
cellObj = (morkCellObject*) mHandle_Object;
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
morkCellObject* cellObj = (morkCellObject*) mHandle_Object;
|
||||
MORK_USED_1(cellObj);
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -518,6 +529,7 @@ orkinCell::GetRow(nsIMdbEnv* mev, // parent row for this cell
|
|||
*acqRow = outRow;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinCell::GetPort(nsIMdbEnv* mev, // port containing cell
|
||||
nsIMdbPort** acqPort)
|
||||
|
@ -623,8 +635,11 @@ orkinCell::SetChildRow( // access table of specific attribute
|
|||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
morkCellObject* cellObj;
|
||||
cellObj = (morkCellObject*) mHandle_Object;
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
morkCellObject* cellObj = (morkCellObject*) mHandle_Object;
|
||||
MORK_USED_1(cellObj);
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -668,8 +683,11 @@ orkinCell::SetChildTable( // access table of specific attribute
|
|||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
morkCellObject* cellObj;
|
||||
cellObj = (morkCellObject*) mHandle_Object;
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
morkCellObject* cellObj = (morkCellObject*) mHandle_Object;
|
||||
MORK_USED_1(cellObj);
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
|
|
@ -247,6 +247,33 @@ orkinEnv::GetWarningCount(mdb_count* outCount,
|
|||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinEnv::GetEnvBeVerbose(mdb_bool* outBeVerbose)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mork_bool beVerbose = morkBool_kFalse;
|
||||
morkEnv* ev = this->CanUseEnv(/*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
beVerbose = ev->mEnv_BeVerbose;
|
||||
}
|
||||
if ( outBeVerbose )
|
||||
*outBeVerbose = beVerbose;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinEnv::SetEnvBeVerbose(mdb_bool inBeVerbose)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = this->CanUseEnv(/*inMutable*/ morkBool_kTrue, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
ev->mEnv_BeVerbose = inBeVerbose;
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinEnv::GetDoTrace(mdb_bool* outDoTrace)
|
||||
{
|
||||
|
|
|
@ -138,6 +138,9 @@ public:
|
|||
virtual mdb_err GetWarningCount(mdb_count* outCount,
|
||||
mdb_bool* outShouldAbort);
|
||||
|
||||
virtual mdb_err GetEnvBeVerbose(mdb_bool* outBeVerbose);
|
||||
virtual mdb_err SetEnvBeVerbose(mdb_bool inBeVerbose);
|
||||
|
||||
virtual mdb_err GetDoTrace(mdb_bool* outDoTrace);
|
||||
virtual mdb_err SetDoTrace(mdb_bool inDoTrace);
|
||||
|
||||
|
|
|
@ -274,6 +274,78 @@ orkinFactory::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen)
|
|||
|
||||
// { ===== begin nsIMdbFactory methods =====
|
||||
|
||||
// { ----- begin file methods -----
|
||||
/*virtual*/ mdb_err
|
||||
orkinFactory::OpenOldFile(nsIMdbEnv* mev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, mork_bool inFrozen, nsIMdbFile** acqFile)
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be open and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbFile* outFile = 0;
|
||||
morkEnv* ev = this->CanUseFactory(mev,
|
||||
/*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkFactory* factory = (morkFactory*) this->mHandle_Object;
|
||||
if ( !ioHeap )
|
||||
ioHeap = &factory->mFactory_Heap;
|
||||
|
||||
morkFile* file = morkFile::OpenOldFile(ev, ioHeap, inFilePath, inFrozen);
|
||||
if ( file )
|
||||
{
|
||||
outFile = file->AcquireFileHandle(ev);
|
||||
file->CutStrongRef(ev);
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqFile )
|
||||
*acqFile = outFile;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinFactory::CreateNewFile(nsIMdbEnv* mev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, nsIMdbFile** acqFile)
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be created and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbFile* outFile = 0;
|
||||
morkEnv* ev = this->CanUseFactory(mev,
|
||||
/*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkFactory* factory = (morkFactory*) this->mHandle_Object;
|
||||
if ( !ioHeap )
|
||||
ioHeap = &factory->mFactory_Heap;
|
||||
|
||||
morkFile* file = morkFile::CreateNewFile(ev, ioHeap, inFilePath);
|
||||
if ( file )
|
||||
{
|
||||
outFile = file->AcquireFileHandle(ev);
|
||||
file->CutStrongRef(ev);
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqFile )
|
||||
*acqFile = outFile;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end file methods -----
|
||||
|
||||
// { ----- begin env methods -----
|
||||
/*virtual*/ mdb_err
|
||||
orkinFactory::MakeEnv(nsIMdbHeap* ioHeap, nsIMdbEnv** acqEnv)
|
||||
|
@ -451,6 +523,9 @@ orkinFactory::ThumbToOpenPort( // redeeming a completed thumb from OpenFilePort(
|
|||
if ( store )
|
||||
{
|
||||
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
|
||||
store->mStore_CanDirty = morkBool_kTrue;
|
||||
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
|
||||
|
||||
outPort = orkinStore::MakeStore(ev, store);
|
||||
}
|
||||
}
|
||||
|
@ -595,6 +670,9 @@ orkinFactory::ThumbToOpenStore( // redeem completed thumb from OpenFileStore()
|
|||
if ( store )
|
||||
{
|
||||
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
|
||||
store->mStore_CanDirty = morkBool_kTrue;
|
||||
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
|
||||
|
||||
outStore = orkinStore::MakeStore(ev, store);
|
||||
}
|
||||
}
|
||||
|
@ -635,6 +713,9 @@ orkinFactory::CreateNewFileStore( // create a new db with minimal content
|
|||
if ( store )
|
||||
{
|
||||
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
|
||||
store->mStore_CanDirty = morkBool_kTrue;
|
||||
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
|
||||
|
||||
if ( store->CreateStoreFile(ev, inFilePath, inOpenPolicy) )
|
||||
outStore = orkinStore::MakeStore(ev, store);
|
||||
|
||||
|
|
|
@ -140,6 +140,26 @@ public:
|
|||
|
||||
// { ===== begin nsIMdbFactory methods =====
|
||||
|
||||
// { ----- begin file methods -----
|
||||
virtual mdb_err OpenOldFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, mdb_bool inFrozen, nsIMdbFile** acqFile);
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be open and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
|
||||
virtual mdb_err CreateNewFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, nsIMdbFile** acqFile);
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be created and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
// } ----- end file methods -----
|
||||
|
||||
// { ----- begin env methods -----
|
||||
virtual mdb_err MakeEnv(nsIMdbHeap* ioHeap, nsIMdbEnv** acqEnv); // new env
|
||||
// ioHeap can be nil, causing a MakeHeap() style heap instance to be used
|
||||
|
|
|
@ -377,6 +377,8 @@ orkinRow::BecomeContent(nsIMdbEnv* mev,
|
|||
&outErr, &row);
|
||||
if ( ev )
|
||||
{
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
|
|
@ -68,6 +68,10 @@
|
|||
#include "morkThumb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKFILE_
|
||||
#include "morkFile.h"
|
||||
#endif
|
||||
|
||||
#ifndef _ORKINTHUMB_
|
||||
#include "orkinThumb.h"
|
||||
#endif
|
||||
|
@ -566,7 +570,7 @@ orkinStore::GetRowRefCount( // get number of tables that contain a row
|
|||
morkStore* store = (morkStore*) mHandle_Object;
|
||||
morkRow* row = store->GetRow(ev, inOid);
|
||||
if ( row && ev->Good() )
|
||||
count = row->mRow_TableUses;
|
||||
count = row->mRow_GcUses;
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -758,6 +762,35 @@ orkinStore::GetPortTableCursor( // get cursor for all tables of specific type
|
|||
}
|
||||
// } ----- end table methods -----
|
||||
|
||||
// { ----- begin commit methods -----
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinStore::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 = ((morkStore*) mHandle_Object)->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 =====
|
||||
|
||||
// { ===== begin nsIMdbStore methods =====
|
||||
|
@ -809,7 +842,7 @@ orkinStore::NewTableWithOid( // make one new table of specific type
|
|||
{
|
||||
table->mTable_Kind = inTableKind;
|
||||
if ( inMustBeUnique )
|
||||
table->mTable_MustBeUnique = inMustBeUnique;
|
||||
table->SetTableUnique();
|
||||
outTable = table->AcquireTableHandle(ev);
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
|
@ -1030,10 +1063,24 @@ orkinStore::LargeCommit( // save important changes if at all possible
|
|||
{
|
||||
morkStore* store = (morkStore*) mHandle_Object;
|
||||
nsIMdbHeap* heap = store->mPort_Heap;
|
||||
|
||||
morkThumb* thumb = 0;
|
||||
morkFile* file = store->mStore_File;
|
||||
if ( file && file->Length(ev) > 128 && store->mStore_CanWriteIncremental )
|
||||
{
|
||||
thumb = morkThumb::Make_LargeCommit(ev, heap, store);
|
||||
}
|
||||
else
|
||||
{
|
||||
mork_bool doCollect = morkBool_kFalse;
|
||||
morkThumb* thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
|
||||
thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
|
||||
}
|
||||
|
||||
if ( thumb )
|
||||
{
|
||||
outThumb = orkinThumb::MakeThumb(ev, thumb);
|
||||
thumb->CutStrongRef(ev);
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -1058,11 +1105,24 @@ orkinStore::SessionCommit( // save all changes if large commits delayed
|
|||
{
|
||||
morkStore* store = (morkStore*) mHandle_Object;
|
||||
nsIMdbHeap* heap = store->mPort_Heap;
|
||||
mork_bool doCollect = morkBool_kFalse;
|
||||
morkThumb* thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
|
||||
if ( thumb )
|
||||
outThumb = orkinThumb::MakeThumb(ev, thumb);
|
||||
|
||||
morkThumb* thumb = 0;
|
||||
morkFile* file = store->mStore_File;
|
||||
if ( file && file->Length(ev) > 128 && store->mStore_CanWriteIncremental )
|
||||
{
|
||||
thumb = morkThumb::Make_LargeCommit(ev, heap, store);
|
||||
}
|
||||
else
|
||||
{
|
||||
mork_bool doCollect = morkBool_kFalse;
|
||||
thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
|
||||
}
|
||||
|
||||
if ( thumb )
|
||||
{
|
||||
outThumb = orkinThumb::MakeThumb(ev, thumb);
|
||||
thumb->CutStrongRef(ev);
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqThumb )
|
||||
|
@ -1078,7 +1138,6 @@ orkinStore::CompressCommit( // commit and make db smaller if possible
|
|||
// 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.
|
||||
// } ----- end commit methods -----
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbThumb* outThumb = 0;
|
||||
|
@ -1090,7 +1149,11 @@ orkinStore::CompressCommit( // commit and make db smaller if possible
|
|||
mork_bool doCollect = morkBool_kFalse;
|
||||
morkThumb* thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
|
||||
if ( thumb )
|
||||
{
|
||||
outThumb = orkinThumb::MakeThumb(ev, thumb);
|
||||
thumb->CutStrongRef(ev);
|
||||
store->mStore_CanWriteIncremental = morkBool_kTrue;
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -1099,6 +1162,8 @@ orkinStore::CompressCommit( // commit and make db smaller if possible
|
|||
return outErr;
|
||||
}
|
||||
|
||||
// } ----- end commit methods -----
|
||||
|
||||
// } ===== end nsIMdbStore methods =====
|
||||
|
||||
|
||||
|
|
|
@ -302,6 +302,69 @@ public: // type identification
|
|||
nsIMdbPortTableCursor** acqCursor); // all such tables in the port
|
||||
// } ----- end table methods -----
|
||||
|
||||
|
||||
// { ----- begin commit methods -----
|
||||
|
||||
virtual mdb_err ShouldCompress( // store wastes at least inPercentWaste?
|
||||
nsIMdbEnv* ev, // 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
|
||||
// ShouldCompress() returns true if the store can determine that the file
|
||||
// will shrink by an estimated percentage of inPercentWaste% (or more) if
|
||||
// CompressCommit() is called, because that percentage of the file seems
|
||||
// to be recoverable free space. The granularity is only in terms of
|
||||
// percentage points, and any value over 100 is considered equal to 100.
|
||||
//
|
||||
// If a store only has an approximate idea how much space might be saved
|
||||
// during a compress, then a best guess should be made. For example, the
|
||||
// Mork implementation might keep track of how much file space began with
|
||||
// text content before the first updating transaction, and then consider
|
||||
// all content following the start of the first transaction as potentially
|
||||
// wasted space if it is all updates and not just new content. (This is
|
||||
// a safe assumption in the sense that behavior will stabilize on a low
|
||||
// estimate of wastage after a commit removes all transaction updates.)
|
||||
//
|
||||
// Some db formats might attempt to keep a very accurate reckoning of free
|
||||
// space size, so a very accurate determination can be made. But other db
|
||||
// formats might have difficulty determining size of free space, and might
|
||||
// require some lengthy calculation to answer. This is the reason for
|
||||
// passing in the percentage threshold of interest, so that such lengthy
|
||||
// computations can terminate early as soon as at least inPercentWaste is
|
||||
// found, so that the entire file need not be groveled when unnecessary.
|
||||
// However, we hope implementations will always favor fast but imprecise
|
||||
// heuristic answers instead of extremely slow but very precise answers.
|
||||
//
|
||||
// If the outActualWaste parameter is non-nil, it will be used to return
|
||||
// the actual estimated space wasted as a percentage of file size. (This
|
||||
// parameter is provided so callers need not call repeatedly with altered
|
||||
// inPercentWaste values to isolate the actual wastage figure.) Note the
|
||||
// actual wastage figure returned can exactly equal inPercentWaste even
|
||||
// when this grossly underestimates the real figure involved, if the db
|
||||
// finds it very expensive to determine the extent of wastage after it is
|
||||
// known to at least exceed inPercentWaste. Note we expect that whenever
|
||||
// outShould returns true, that outActualWaste returns >= inPercentWaste.
|
||||
//
|
||||
// The effect of different inPercentWaste values is not very uniform over
|
||||
// the permitted range. For example, 50 represents 50% wastage, or a file
|
||||
// that is about double what it should be ideally. But 99 represents 99%
|
||||
// wastage, or a file that is about ninety-nine times as big as it should
|
||||
// be ideally. In the smaller direction, 25 represents 25% wastage, or
|
||||
// a file that is only 33% larger than it should be ideally.
|
||||
//
|
||||
// Callers can determine what policy they want to use for considering when
|
||||
// a file holds too much wasted space, and express this as a percentage
|
||||
// of total file size to pass as in the inPercentWaste parameter. A zero
|
||||
// likely returns always trivially true, and 100 always trivially false.
|
||||
// The great majority of callers are expected to use values from 25 to 75,
|
||||
// since most plausible thresholds for compressing might fall between the
|
||||
// extremes of 133% of ideal size and 400% of ideal size. (Presumably the
|
||||
// larger a file gets, the more important the percentage waste involved, so
|
||||
// a sliding scale for compress thresholds might use smaller numbers for
|
||||
// much bigger file sizes.)
|
||||
|
||||
// } ----- end commit methods -----
|
||||
|
||||
// } ===== end nsIMdbPort methods =====
|
||||
|
||||
// { ===== begin nsIMdbStore methods =====
|
||||
|
|
|
@ -315,8 +315,11 @@ orkinTable::BecomeContent(nsIMdbEnv* mev,
|
|||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table;
|
||||
table = (morkTable*) mHandle_Object;
|
||||
// remember table->MaybeDirtySpaceStoreAndTable();
|
||||
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
MORK_USED_1(table);
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -347,6 +350,99 @@ orkinTable::DropActivity( // tell collection usage no longer expected
|
|||
// { ===== begin nsIMdbTable methods =====
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::SetTablePriority(nsIMdbEnv* mev, mdb_priority inPrio)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
if ( inPrio > morkPriority_kMax )
|
||||
inPrio = morkPriority_kMax;
|
||||
|
||||
table->mTable_Priority = inPrio;
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::GetTablePriority(nsIMdbEnv* mev, mdb_priority* outPrio)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mork_priority prio = 0;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
prio = table->mTable_Priority;
|
||||
if ( prio > morkPriority_kMax )
|
||||
{
|
||||
prio = morkPriority_kMax;
|
||||
table->mTable_Priority = prio;
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outPrio )
|
||||
*outPrio = prio;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable:: GetTableBeVerbose(nsIMdbEnv* mev, mdb_bool* outBeVerbose)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_bool beVerbose = morkBool_kFalse;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
beVerbose = table->IsTableVerbose();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outBeVerbose )
|
||||
*outBeVerbose = beVerbose;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::SetTableBeVerbose(nsIMdbEnv* mev, mdb_bool inBeVerbose)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
if ( inBeVerbose )
|
||||
table->SetTableVerbose();
|
||||
else
|
||||
table->ClearTableVerbose();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::GetTableIsUnique(nsIMdbEnv* mev, mdb_bool* outIsUnique)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_bool isUnique = morkBool_kFalse;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
isUnique = table->IsTableUnique();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outIsUnique )
|
||||
*outIsUnique = isUnique;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::GetTableKind(nsIMdbEnv* mev, mdb_kind* outTableKind)
|
||||
{
|
||||
|
@ -731,6 +827,20 @@ orkinTable::CutRow( // make sure the row with inOid is not a member
|
|||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::CutAllRows( // remove all rows from the table
|
||||
nsIMdbEnv* mev) // context
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
((morkTable*) mHandle_Object)->CutAllRows(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end row set methods -----
|
||||
|
||||
// { ----- begin searching methods -----
|
||||
|
@ -1021,6 +1131,8 @@ orkinTable::MoveOid( // change position of row in unsorted table
|
|||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
// remember table->MaybeDirtySpaceStoreAndTable();
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -1043,6 +1155,8 @@ orkinTable::MoveRow( // change position of row in unsorted table
|
|||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
// remember table->MaybeDirtySpaceStoreAndTable();
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
|
|
@ -165,6 +165,14 @@ public: // type identification
|
|||
// { ===== begin nsIMdbTable methods =====
|
||||
|
||||
// { ----- begin meta attribute methods -----
|
||||
virtual mdb_err SetTablePriority(nsIMdbEnv* ev, mdb_priority inPrio);
|
||||
virtual mdb_err GetTablePriority(nsIMdbEnv* ev, mdb_priority* outPrio);
|
||||
|
||||
virtual mdb_err GetTableBeVerbose(nsIMdbEnv* ev, mdb_bool* outBeVerbose);
|
||||
virtual mdb_err SetTableBeVerbose(nsIMdbEnv* ev, mdb_bool inBeVerbose);
|
||||
|
||||
virtual mdb_err GetTableIsUnique(nsIMdbEnv* ev, mdb_bool* outIsUnique);
|
||||
|
||||
virtual mdb_err GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind);
|
||||
virtual mdb_err GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope);
|
||||
|
||||
|
@ -260,6 +268,9 @@ public: // type identification
|
|||
virtual mdb_err CutRow( // make sure the row with inOid is not a member
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioRow); // row to remove from table
|
||||
|
||||
virtual mdb_err CutAllRows( // remove all rows from the table
|
||||
nsIMdbEnv* ev); // context
|
||||
// } ----- end row set methods -----
|
||||
|
||||
// { ----- begin searching methods -----
|
||||
|
|
|
@ -44,6 +44,10 @@ typedef mdb_u4 mdb_size; // unsigned physical media size
|
|||
typedef mdb_u4 mdb_fill; // unsigned logical content size
|
||||
typedef mdb_u4 mdb_more; // more available bytes for larger buffer
|
||||
|
||||
typedef mdb_u4 mdb_percent; // 0..100, with values >100 same as 100
|
||||
|
||||
typedef mdb_u1 mdb_priority; // 0..9, for a total of ten different values
|
||||
|
||||
// temporary substitute for NS_RESULT, for mdb.h standalone compilation:
|
||||
typedef mdb_u4 mdb_err; // equivalent to NS_RESULT
|
||||
|
||||
|
@ -311,6 +315,7 @@ class nsIMdbErrorHook;
|
|||
class nsIMdbCompare;
|
||||
class nsIMdbThumb;
|
||||
class nsIMdbFactory;
|
||||
class nsIMdbFile;
|
||||
class nsIMdbPort;
|
||||
class nsIMdbStore;
|
||||
class nsIMdbCursor;
|
||||
|
@ -544,6 +549,9 @@ public:
|
|||
virtual mdb_err GetWarningCount(mdb_count* outCount,
|
||||
mdb_bool* outShouldAbort) = 0;
|
||||
|
||||
virtual mdb_err GetEnvBeVerbose(mdb_bool* outBeVerbose) = 0;
|
||||
virtual mdb_err SetEnvBeVerbose(mdb_bool inBeVerbose) = 0;
|
||||
|
||||
virtual mdb_err GetDoTrace(mdb_bool* outDoTrace) = 0;
|
||||
virtual mdb_err SetDoTrace(mdb_bool inDoTrace) = 0;
|
||||
|
||||
|
@ -616,6 +624,26 @@ public:
|
|||
|
||||
// { ===== begin nsIMdbFactory methods =====
|
||||
|
||||
// { ----- begin file methods -----
|
||||
virtual mdb_err OpenOldFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, mdb_bool inFrozen, nsIMdbFile** acqFile) = 0;
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be open and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
|
||||
virtual mdb_err CreateNewFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, nsIMdbFile** acqFile) = 0;
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be created and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
// } ----- end file methods -----
|
||||
|
||||
// { ----- begin env methods -----
|
||||
virtual mdb_err MakeEnv(nsIMdbHeap* ioHeap, nsIMdbEnv** acqEnv) = 0; // acquire new env
|
||||
// ioHeap can be nil, causing a MakeHeap() style heap instance to be used
|
||||
|
@ -740,9 +768,9 @@ public:
|
|||
// { ===== begin nsIMdbFile methods =====
|
||||
|
||||
// { ----- begin pos methods -----
|
||||
virtual mdb_err Tell(nsIMdbEnv* ev, mdb_pos* outPos) const = 0;
|
||||
virtual mdb_err Tell(nsIMdbEnv* ev, mdb_pos* outPos) = 0;
|
||||
virtual mdb_err Seek(nsIMdbEnv* ev, mdb_pos inPos) = 0;
|
||||
virtual mdb_err Eof(nsIMdbEnv* ev, mdb_pos* outPos) const = 0;
|
||||
virtual mdb_err Eof(nsIMdbEnv* ev, mdb_pos* outPos) = 0;
|
||||
// } ----- end pos methods -----
|
||||
|
||||
// { ----- begin read methods -----
|
||||
|
@ -769,6 +797,34 @@ public:
|
|||
virtual mdb_err Thief(nsIMdbEnv* ev, nsIMdbFile** acqThief) = 0;
|
||||
// } ----- end replacement methods -----
|
||||
|
||||
// { ----- begin versioning methods -----
|
||||
virtual mdb_err BecomeTrunk(nsIMdbEnv* ev) = 0;
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
// file's content, typically by assuming the original file's identity.
|
||||
// This default implementation of BecomeTrunk() does nothing, and this
|
||||
// is appropriate behavior for files which are not branches, and is
|
||||
// also the right behavior for files returned from AcquireBud() which are
|
||||
// in fact the original file that has been truncated down to zero length.
|
||||
|
||||
virtual mdb_err AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
nsIMdbFile** acqBud) = 0; // acquired file for new version of content
|
||||
// AcquireBud() starts a new "branch" version of the file, empty of content,
|
||||
// so that a new version of the file can be written. This new file
|
||||
// can later be told to BecomeTrunk() the original file, so the branch
|
||||
// created by budding the file will replace the original file. Some
|
||||
// file subclasses might initially take the unsafe but expedient
|
||||
// approach of simply truncating this file down to zero length, and
|
||||
// then returning the same morkFile pointer as this, with an extra
|
||||
// reference count increment. Note that the caller of AcquireBud() is
|
||||
// expected to eventually call CutStrongRef() on the returned file
|
||||
// in order to release the strong reference. High quality versions
|
||||
// of morkFile subclasses will create entirely new files which later
|
||||
// are renamed to become the old file, so that better transactional
|
||||
// behavior is exhibited by the file, so crashes protect old files.
|
||||
// Note that AcquireBud() is an illegal operation on readonly files.
|
||||
// } ----- end versioning methods -----
|
||||
|
||||
// } ===== end nsIMdbFile methods =====
|
||||
};
|
||||
|
||||
|
@ -950,6 +1006,12 @@ public:
|
|||
const mdbOid* inOid, // hypothetical row oid
|
||||
nsIMdbRow** acqRow) = 0; // acquire specific row (or null)
|
||||
|
||||
// virtual mdb_err
|
||||
// GetPortRowCursor( // get cursor for all rows in specific scope
|
||||
// nsIMdbEnv* ev, // context
|
||||
// mdb_scope inRowScope, // row scope for row ids
|
||||
// nsIMdbPortRowCursor** acqCursor) = 0; // all such rows in the port
|
||||
|
||||
virtual mdb_err FindRow(nsIMdbEnv* ev, // 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)
|
||||
|
@ -1037,6 +1099,69 @@ public:
|
|||
nsIMdbPortTableCursor** acqCursor) = 0; // all such tables in the port
|
||||
// } ----- end table methods -----
|
||||
|
||||
|
||||
// { ----- begin commit methods -----
|
||||
|
||||
virtual mdb_err ShouldCompress( // store wastes at least inPercentWaste?
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_percent inPercentWaste, // 0..100 percent file size waste threshold
|
||||
mdb_percent* outActualWaste, // 0..100 percent of file actually wasted
|
||||
mdb_bool* outShould) = 0; // true when about inPercentWaste% is wasted
|
||||
// ShouldCompress() returns true if the store can determine that the file
|
||||
// will shrink by an estimated percentage of inPercentWaste% (or more) if
|
||||
// CompressCommit() is called, because that percentage of the file seems
|
||||
// to be recoverable free space. The granularity is only in terms of
|
||||
// percentage points, and any value over 100 is considered equal to 100.
|
||||
//
|
||||
// If a store only has an approximate idea how much space might be saved
|
||||
// during a compress, then a best guess should be made. For example, the
|
||||
// Mork implementation might keep track of how much file space began with
|
||||
// text content before the first updating transaction, and then consider
|
||||
// all content following the start of the first transaction as potentially
|
||||
// wasted space if it is all updates and not just new content. (This is
|
||||
// a safe assumption in the sense that behavior will stabilize on a low
|
||||
// estimate of wastage after a commit removes all transaction updates.)
|
||||
//
|
||||
// Some db formats might attempt to keep a very accurate reckoning of free
|
||||
// space size, so a very accurate determination can be made. But other db
|
||||
// formats might have difficulty determining size of free space, and might
|
||||
// require some lengthy calculation to answer. This is the reason for
|
||||
// passing in the percentage threshold of interest, so that such lengthy
|
||||
// computations can terminate early as soon as at least inPercentWaste is
|
||||
// found, so that the entire file need not be groveled when unnecessary.
|
||||
// However, we hope implementations will always favor fast but imprecise
|
||||
// heuristic answers instead of extremely slow but very precise answers.
|
||||
//
|
||||
// If the outActualWaste parameter is non-nil, it will be used to return
|
||||
// the actual estimated space wasted as a percentage of file size. (This
|
||||
// parameter is provided so callers need not call repeatedly with altered
|
||||
// inPercentWaste values to isolate the actual wastage figure.) Note the
|
||||
// actual wastage figure returned can exactly equal inPercentWaste even
|
||||
// when this grossly underestimates the real figure involved, if the db
|
||||
// finds it very expensive to determine the extent of wastage after it is
|
||||
// known to at least exceed inPercentWaste. Note we expect that whenever
|
||||
// outShould returns true, that outActualWaste returns >= inPercentWaste.
|
||||
//
|
||||
// The effect of different inPercentWaste values is not very uniform over
|
||||
// the permitted range. For example, 50 represents 50% wastage, or a file
|
||||
// that is about double what it should be ideally. But 99 represents 99%
|
||||
// wastage, or a file that is about ninety-nine times as big as it should
|
||||
// be ideally. In the smaller direction, 25 represents 25% wastage, or
|
||||
// a file that is only 33% larger than it should be ideally.
|
||||
//
|
||||
// Callers can determine what policy they want to use for considering when
|
||||
// a file holds too much wasted space, and express this as a percentage
|
||||
// of total file size to pass as in the inPercentWaste parameter. A zero
|
||||
// likely returns always trivially true, and 100 always trivially false.
|
||||
// The great majority of callers are expected to use values from 25 to 75,
|
||||
// since most plausible thresholds for compressing might fall between the
|
||||
// extremes of 133% of ideal size and 400% of ideal size. (Presumably the
|
||||
// larger a file gets, the more important the percentage waste involved, so
|
||||
// a sliding scale for compress thresholds might use smaller numbers for
|
||||
// much bigger file sizes.)
|
||||
|
||||
// } ----- end commit methods -----
|
||||
|
||||
// } ===== end nsIMdbPort methods =====
|
||||
};
|
||||
|
||||
|
@ -1208,6 +1333,7 @@ public:
|
|||
// 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.
|
||||
|
||||
// } ----- end commit methods -----
|
||||
|
||||
// } ===== end nsIMdbStore methods =====
|
||||
|
@ -1486,6 +1612,14 @@ public:
|
|||
// { ===== begin nsIMdbTable methods =====
|
||||
|
||||
// { ----- begin meta attribute methods -----
|
||||
virtual mdb_err SetTablePriority(nsIMdbEnv* ev, mdb_priority inPrio) = 0;
|
||||
virtual mdb_err GetTablePriority(nsIMdbEnv* ev, mdb_priority* outPrio) = 0;
|
||||
|
||||
virtual mdb_err GetTableBeVerbose(nsIMdbEnv* ev, mdb_bool* outBeVerbose) = 0;
|
||||
virtual mdb_err SetTableBeVerbose(nsIMdbEnv* ev, mdb_bool inBeVerbose) = 0;
|
||||
|
||||
virtual mdb_err GetTableIsUnique(nsIMdbEnv* ev, mdb_bool* outIsUnique) = 0;
|
||||
|
||||
virtual mdb_err GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind) = 0;
|
||||
virtual mdb_err GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope) = 0;
|
||||
|
||||
|
@ -1518,6 +1652,7 @@ public:
|
|||
// already given a different oid earlier.
|
||||
// } ----- end meta attribute methods -----
|
||||
|
||||
|
||||
// { ----- begin cursor methods -----
|
||||
virtual mdb_err GetTableRowCursor( // make a cursor, starting iteration at inRowPos
|
||||
nsIMdbEnv* ev, // context
|
||||
|
@ -1580,6 +1715,9 @@ public:
|
|||
virtual mdb_err CutRow( // make sure the row with inOid is not a member
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioRow) = 0; // row to remove from table
|
||||
|
||||
virtual mdb_err CutAllRows( // remove all rows from the table
|
||||
nsIMdbEnv* ev) = 0; // context
|
||||
// } ----- end row set methods -----
|
||||
|
||||
// { ----- begin searching methods -----
|
||||
|
|
|
@ -91,6 +91,8 @@ typedef mork_u4 mork_size; // unsigned physical media size
|
|||
typedef mork_u4 mork_fill; // unsigned logical content size
|
||||
typedef mork_u4 mork_more; // more available bytes for larger buffer
|
||||
|
||||
typedef mdb_u4 mork_percent; // 0..100, with values >100 same as 100
|
||||
|
||||
typedef mork_i4 mork_pos; // negative means "before first" (at zero pos)
|
||||
typedef mork_i4 mork_line; // negative means "before first line in file"
|
||||
|
||||
|
@ -98,12 +100,21 @@ typedef mork_u1 mork_usage; // 1-byte magic usage signature slot in object
|
|||
typedef mork_u1 mork_access; // 1-byte magic access signature slot in object
|
||||
|
||||
typedef mork_u1 mork_change; // add, cut, put, set, nil
|
||||
typedef mork_u1 mork_priority; // 0..9, for a total of ten different values
|
||||
|
||||
typedef mork_u1 mork_able; // on, off, asleep (clone IronDoc's fe_able)
|
||||
typedef mork_u1 mork_load; // dirty or clean (clone IronDoc's fe_load)
|
||||
// } %%%%% end specific-size integer scalar typedefs %%%%%
|
||||
|
||||
// { %%%%% begin constants for Mork scalar types %%%%%
|
||||
#define morkPriority_kHi ((mork_priority) 0) /* best priority */
|
||||
#define morkPriority_kMin ((mork_priority) 0) /* best priority is smallest */
|
||||
|
||||
#define morkPriority_kLo ((mork_priority) 9) /* worst priority */
|
||||
#define morkPriority_kMax ((mork_priority) 9) /* worst priority is biggest */
|
||||
|
||||
#define morkPriority_kCount 10 /* number of distinct priority values */
|
||||
|
||||
#define morkAble_kEnabled ((mork_able) 0x55) /* same as IronDoc constant */
|
||||
#define morkAble_kDisabled ((mork_able) 0xAA) /* same as IronDoc constant */
|
||||
#define morkAble_kAsleep ((mork_able) 0x5A) /* same as IronDoc constant */
|
||||
|
@ -188,6 +199,7 @@ class morkSpan;
|
|||
class morkStore;
|
||||
class morkStream;
|
||||
class morkTable;
|
||||
class morkTableChange;
|
||||
class morkTableRowCursor;
|
||||
class morkThumb;
|
||||
class morkWriter;
|
||||
|
|
|
@ -88,7 +88,7 @@ morkAtom::GetYarn(mdbYarn* outYarn) const
|
|||
mdb_size size = outYarn->mYarn_Size; // max dest size
|
||||
if ( fill > size ) // too much atom content?
|
||||
{
|
||||
outYarn->mYarn_More = size - fill; // extra atom bytes omitted
|
||||
outYarn->mYarn_More = fill - size; // extra atom bytes omitted
|
||||
fill = size; // copy no more bytes than size of yarn buffer
|
||||
}
|
||||
void* dest = outYarn->mYarn_Buf; // where bytes are going
|
||||
|
|
|
@ -60,6 +60,14 @@ public:
|
|||
|
||||
mork_bool IsBook() const { return this->IsWeeBook() || this->IsBigBook(); }
|
||||
|
||||
public: // clean vs dirty
|
||||
|
||||
void SetAtomClean() { mAtom_Change = morkChange_kNil; }
|
||||
void SetAtomDirty() { mAtom_Change = morkChange_kAdd; }
|
||||
|
||||
mork_bool IsAtomClean() const { return mAtom_Change == morkChange_kNil; }
|
||||
mork_bool IsAtomDirty() const { return mAtom_Change == morkChange_kAdd; }
|
||||
|
||||
public: // atom space scope if IsBook() is true, or else zero:
|
||||
|
||||
mork_scope GetBookAtomSpaceScope(morkEnv* ev) const;
|
||||
|
@ -79,8 +87,6 @@ public: // one-byte refcounting, freezing at maximum
|
|||
mork_bool IsCellUseForever() const
|
||||
{ return mAtom_CellUses == morkAtom_kForeverCellUses; }
|
||||
|
||||
void SetAtomDirty() { mAtom_Change = morkChange_kAdd; }
|
||||
|
||||
private: // warnings
|
||||
|
||||
static void CellUsesUnderflowWarning(morkEnv* ev);
|
||||
|
|
|
@ -96,6 +96,7 @@ morkAtomSpace::morkAtomSpace(morkEnv* ev, const morkUsage& inUsage,
|
|||
, mAtomSpace_AtomAids(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap)
|
||||
, mAtomSpace_AtomBodies(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap)
|
||||
{
|
||||
// the morkSpace base constructor handles any dirty propagation
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kAtomSpace;
|
||||
}
|
||||
|
@ -137,6 +138,9 @@ morkAtomSpace::NonAtomSpaceTypeError(morkEnv* ev)
|
|||
mork_num
|
||||
morkAtomSpace::CutAllAtoms(morkEnv* ev, morkPool* ioPool)
|
||||
{
|
||||
if ( this->IsAtomSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
|
||||
mork_num outSlots = mAtomSpace_AtomAids.mMap_Fill;
|
||||
morkBookAtom* a = 0; // old key atom in the map
|
||||
|
||||
|
@ -165,6 +169,13 @@ morkAtomSpace::MakeBookAtomCopyWithAid(morkEnv* ev,
|
|||
outAtom = pool->NewBookAtomCopy(ev, inAtom);
|
||||
if ( outAtom )
|
||||
{
|
||||
if ( mSpace_Store->mStore_CanDirty )
|
||||
{
|
||||
outAtom->SetAtomDirty();
|
||||
if ( this->IsAtomSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
}
|
||||
|
||||
outAtom->mBookAtom_Id = inAid;
|
||||
outAtom->mBookAtom_Space = this;
|
||||
mAtomSpace_AtomAids.AddAtom(ev, outAtom);
|
||||
|
@ -184,9 +195,10 @@ morkAtomSpace::MakeBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom)
|
|||
// make copy of inAtom and put it in both maps, using a new ID as needed.
|
||||
{
|
||||
morkBookAtom* outAtom = 0;
|
||||
if ( ev->Good() )
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( ev->Good() && store )
|
||||
{
|
||||
if ( mSpace_Store->mStore_CanAutoAssignAtomIdentity )
|
||||
if ( store->mStore_CanAutoAssignAtomIdentity )
|
||||
{
|
||||
morkPool* pool = this->GetSpaceStorePool();
|
||||
morkBookAtom* atom = pool->NewBookAtomCopy(ev, inAtom);
|
||||
|
@ -195,6 +207,13 @@ morkAtomSpace::MakeBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom)
|
|||
mork_aid id = this->MakeNewAtomId(ev, atom);
|
||||
if ( id )
|
||||
{
|
||||
if ( store->mStore_CanDirty )
|
||||
{
|
||||
atom->SetAtomDirty();
|
||||
if ( this->IsAtomSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
}
|
||||
|
||||
outAtom = atom;
|
||||
atom->mBookAtom_Space = this;
|
||||
mAtomSpace_AtomAids.AddAtom(ev, atom);
|
||||
|
|
|
@ -99,6 +99,13 @@ public: // state is public because the entire Mork system is private
|
|||
morkAtomAidMap mAtomSpace_AtomAids; // all atoms in space by ID
|
||||
morkAtomBodyMap mAtomSpace_AtomBodies; // all atoms in space by body
|
||||
|
||||
public: // more specific dirty methods for atom space:
|
||||
void SetAtomSpaceDirty() { this->SetNodeDirty(); }
|
||||
void SetAtomSpaceClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsAtomSpaceClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsAtomSpaceDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseAtomSpace() only if open
|
||||
|
|
|
@ -133,6 +133,11 @@ morkBuilder::morkBuilder(morkEnv* ev,
|
|||
, mBuilder_TableAtomScope( (mork_scope) 'v' )
|
||||
, mBuilder_TableKind( 0 )
|
||||
|
||||
, mBuilder_TablePriority( morkPriority_kLo )
|
||||
, mBuilder_TableIsUnique( morkBool_kFalse )
|
||||
, mBuilder_TableIsVerbose( morkBool_kFalse )
|
||||
, mBuilder_TablePadByte( 0 )
|
||||
|
||||
, mBuilder_RowForm( 0 )
|
||||
, mBuilder_RowRowScope( (mork_scope) 'r' )
|
||||
, mBuilder_RowAtomScope( (mork_scope) 'v' )
|
||||
|
@ -283,9 +288,21 @@ morkBuilder::OnPortEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
/*virtual*/ void
|
||||
morkBuilder::OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid)
|
||||
{
|
||||
MORK_USED_2(inPlace,inGid);
|
||||
MORK_USED_1(inPlace);
|
||||
// mParser_InGroup = morkBool_kTrue;
|
||||
ev->StubMethodOnlyError();
|
||||
mork_pos startPos = inPlace.mPlace_Pos;
|
||||
|
||||
morkStore* store = mBuilder_Store;
|
||||
if ( store )
|
||||
{
|
||||
if ( inGid >= store->mStore_CommitGroupIdentity )
|
||||
store->mStore_CommitGroupIdentity = inGid + 1;
|
||||
|
||||
if ( !store->mStore_FirstCommitGroupPos )
|
||||
store->mStore_FirstCommitGroupPos = startPos;
|
||||
else if ( !store->mStore_SecondCommitGroupPos )
|
||||
store->mStore_SecondCommitGroupPos = startPos;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
|
@ -297,9 +314,9 @@ morkBuilder::OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch)
|
|||
/*virtual*/ void
|
||||
morkBuilder::OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan)
|
||||
{
|
||||
MORK_USED_1(inSpan);
|
||||
MORK_USED_2(ev,inSpan);
|
||||
// mParser_InGroup = morkBool_kFalse;
|
||||
ev->StubMethodOnlyError();
|
||||
// ev->StubMethodOnlyError();
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
|
@ -335,24 +352,35 @@ morkBuilder::OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnNewTable(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange)
|
||||
const morkMid& inMid, mork_bool inCutAllRows)
|
||||
// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd
|
||||
// mp:TableItem ::= mp:Row | mp:MetaTable | OnTableGlitch
|
||||
// mp:MetaTable ::= OnNewMeta mp:MetaItem* mp:Row OnMetaEnd
|
||||
// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd
|
||||
// mp:MetaItem ::= mp:Cell | OnMetaGlitch
|
||||
{
|
||||
MORK_USED_2(inPlace,inChange);
|
||||
MORK_USED_1(inPlace);
|
||||
// mParser_InTable = morkBool_kTrue;
|
||||
mBuilder_TableForm = mBuilder_PortForm;
|
||||
mBuilder_TableRowScope = mBuilder_PortRowScope;
|
||||
mBuilder_TableAtomScope = mBuilder_PortAtomScope;
|
||||
mBuilder_TableKind = morkStore_kNoneToken;
|
||||
|
||||
mBuilder_TablePriority = morkPriority_kLo;
|
||||
mBuilder_TableIsUnique = morkBool_kFalse;
|
||||
mBuilder_TableIsVerbose = morkBool_kFalse;
|
||||
|
||||
morkTable* table = mBuilder_Store->MidToTable(ev, inMid);
|
||||
morkTable::SlotStrongTable(table, ev, &mBuilder_Table);
|
||||
if ( table && table->mTable_RowSpace )
|
||||
mBuilder_TableRowScope = table->mTable_RowSpace->mSpace_Scope;}
|
||||
if ( table )
|
||||
{
|
||||
if ( table->mTable_RowSpace )
|
||||
mBuilder_TableRowScope = table->mTable_RowSpace->mSpace_Scope;
|
||||
|
||||
if ( inCutAllRows )
|
||||
table->CutAllRows(ev);
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch)
|
||||
|
@ -368,6 +396,14 @@ morkBuilder::OnTableEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
// mParser_InTable = morkBool_kFalse;
|
||||
if ( mBuilder_Table )
|
||||
{
|
||||
mBuilder_Table->mTable_Priority = mBuilder_TablePriority;
|
||||
|
||||
if ( mBuilder_TableIsUnique )
|
||||
mBuilder_Table->SetTableUnique();
|
||||
|
||||
if ( mBuilder_TableIsVerbose )
|
||||
mBuilder_Table->SetTableVerbose();
|
||||
|
||||
morkTable::SlotStrongTable((morkTable*) 0, ev, &mBuilder_Table);
|
||||
}
|
||||
else
|
||||
|
@ -376,18 +412,26 @@ morkBuilder::OnTableEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
mBuilder_Row = 0;
|
||||
mBuilder_Cell = 0;
|
||||
|
||||
|
||||
mBuilder_TablePriority = morkPriority_kLo;
|
||||
mBuilder_TableIsUnique = morkBool_kFalse;
|
||||
mBuilder_TableIsVerbose = morkBool_kFalse;
|
||||
|
||||
if ( mBuilder_TableKind == morkStore_kNoneToken )
|
||||
ev->NewError("missing table kind");
|
||||
|
||||
mBuilder_CellAtomScope = mBuilder_RowAtomScope =
|
||||
mBuilder_TableAtomScope = mBuilder_PortAtomScope;
|
||||
|
||||
mBuilder_DoCutCell = morkBool_kFalse;
|
||||
mBuilder_DoCutRow = morkBool_kFalse;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnNewMeta(morkEnv* ev, const morkPlace& inPlace)
|
||||
// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd
|
||||
// mp:MetaItem ::= mp:Cell | OnMetaGlitch
|
||||
// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
|
||||
// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
|
||||
{
|
||||
|
@ -410,22 +454,28 @@ morkBuilder::OnMetaEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
// mParser_InMeta = morkBool_kFalse;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnMinusRow(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mBuilder_DoCutRow = morkBool_kTrue;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnNewRow(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange)
|
||||
const morkMid& inMid, mork_bool inCutAllCols)
|
||||
// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd
|
||||
// mp:TableItem ::= mp:Row | mp:MetaTable | OnTableGlitch
|
||||
// mp:MetaTable ::= OnNewMeta mp:MetaItem* mp:Row OnMetaEnd
|
||||
// mp:Row ::= OnNewRow mp:RowItem* OnRowEnd
|
||||
// mp:Row ::= OnMinusRow? OnNewRow mp:RowItem* OnRowEnd
|
||||
// mp:RowItem ::= mp:Cell | mp:Meta | OnRowGlitch
|
||||
// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
|
||||
// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
|
||||
{
|
||||
MORK_USED_2(inPlace,inChange);
|
||||
MORK_USED_1(inPlace);
|
||||
// mParser_InRow = morkBool_kTrue;
|
||||
if ( mBuilder_Table )
|
||||
{
|
||||
|
||||
mBuilder_CellForm = mBuilder_RowForm = mBuilder_TableForm;
|
||||
mBuilder_CellAtomScope = mBuilder_RowAtomScope = mBuilder_TableAtomScope;
|
||||
mBuilder_RowRowScope = mBuilder_TableRowScope;
|
||||
|
@ -441,28 +491,42 @@ morkBuilder::OnNewRow(morkEnv* ev, const morkPlace& inPlace,
|
|||
{
|
||||
mBuilder_Row = store->MidToRow(ev, inMid);
|
||||
}
|
||||
|
||||
morkRow* row = mBuilder_Row;
|
||||
if ( row && inCutAllCols )
|
||||
{
|
||||
row->CutAllColumns(ev);
|
||||
}
|
||||
|
||||
morkTable* table = mBuilder_Table;
|
||||
if ( table )
|
||||
{
|
||||
if ( row )
|
||||
{
|
||||
morkTable* table = mBuilder_Table;
|
||||
if ( mParser_InMeta )
|
||||
{
|
||||
if ( !table->mTable_MetaRow )
|
||||
morkRow* metaRow = table->mTable_MetaRow;
|
||||
if ( !metaRow )
|
||||
{
|
||||
table->mTable_MetaRow = row;
|
||||
table->mTable_MetaRowOid = row->mRow_Oid;
|
||||
row->AddTableUse(ev);
|
||||
row->AddRowGcUse(ev);
|
||||
}
|
||||
else
|
||||
else if ( metaRow != row ) // not identical?
|
||||
ev->NewError("duplicate table meta row");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mBuilder_DoCutRow )
|
||||
table->CutRow(ev, row);
|
||||
else
|
||||
table->AddRow(ev, row);
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilBuilderTableError(ev);
|
||||
}
|
||||
// else // it is now okay to have rows outside a table:
|
||||
// this->NilBuilderTableError(ev);
|
||||
|
||||
mBuilder_DoCutRow = morkBool_kFalse;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
|
@ -496,7 +560,7 @@ morkBuilder::FlushBuilderCells(morkEnv* ev)
|
|||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnRowEnd(morkEnv* ev, const morkSpan& inSpan)
|
||||
// mp:Row ::= OnNewRow mp:RowItem* OnRowEnd
|
||||
// mp:Row ::= OnMinusRow? OnNewRow mp:RowItem* OnRowEnd
|
||||
{
|
||||
MORK_USED_1(inSpan);
|
||||
// mParser_InRow = morkBool_kFalse;
|
||||
|
@ -509,6 +573,9 @@ morkBuilder::OnRowEnd(morkEnv* ev, const morkSpan& inSpan)
|
|||
|
||||
mBuilder_Row = 0;
|
||||
mBuilder_Cell = 0;
|
||||
|
||||
mBuilder_DoCutCell = morkBool_kFalse;
|
||||
mBuilder_DoCutRow = morkBool_kFalse;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
|
@ -589,20 +656,32 @@ morkBuilder::AddBuilderCell(morkEnv* ev,
|
|||
return outCell;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnMinusCell(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mBuilder_DoCutCell = morkBool_kTrue;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid* inMid, const morkBuf* inBuf, mork_change inChange)
|
||||
const morkMid* inMid, const morkBuf* inBuf)
|
||||
// Exactly one of inMid and inBuf is nil, and the other is non-nil.
|
||||
// When hex ID syntax is used for a column, then inMid is not nil, and
|
||||
// when a naked string names a column, then inBuf is not nil.
|
||||
|
||||
// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
|
||||
// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
|
||||
{
|
||||
MORK_USED_1(inPlace);
|
||||
// mParser_InCell = morkBool_kTrue;
|
||||
|
||||
mork_change cellChange = ( mBuilder_DoCutCell )?
|
||||
morkChange_kCut : morkChange_kAdd;
|
||||
|
||||
mBuilder_DoCutCell = morkBool_kFalse;
|
||||
|
||||
mBuilder_CellAtomScope = mBuilder_RowAtomScope;
|
||||
|
||||
mBuilder_Cell = 0; // nil until determined for a row
|
||||
|
@ -639,7 +718,7 @@ morkBuilder::OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
|||
|
||||
if ( mBuilder_Row && ev->Good() ) // this cell must be inside a row
|
||||
{
|
||||
// mBuilder_Cell = this->AddBuilderCell(ev, *cellMid, inChange);
|
||||
// mBuilder_Cell = this->AddBuilderCell(ev, *cellMid, cellChange);
|
||||
|
||||
if ( mBuilder_CellsVecFill >= morkBuilder_kCellsVecSize )
|
||||
this->FlushBuilderCells(ev);
|
||||
|
@ -647,9 +726,10 @@ morkBuilder::OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
|||
{
|
||||
if ( mBuilder_CellsVecFill < morkBuilder_kCellsVecSize )
|
||||
{
|
||||
mork_fill indx = mBuilder_CellsVecFill++;
|
||||
morkCell* cell = mBuilder_CellsVec + indx;
|
||||
cell->SetColumnAndChange(column, inChange);
|
||||
mork_fill ix = mBuilder_CellsVecFill++;
|
||||
morkCell* cell = mBuilder_CellsVec + ix;
|
||||
cell->SetColumnAndChange(column, cellChange);
|
||||
|
||||
cell->mCell_Atom = 0;
|
||||
mBuilder_Cell = cell;
|
||||
}
|
||||
|
@ -666,6 +746,8 @@ morkBuilder::OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
|||
{
|
||||
if ( column == morkStore_kKindColumn )
|
||||
mBuilder_MetaTokenSlot = &mBuilder_TableKind;
|
||||
else if ( column == morkStore_kStatusColumn )
|
||||
mBuilder_MetaTokenSlot = &mBuilder_TableStatus;
|
||||
else if ( column == morkStore_kRowScopeColumn )
|
||||
mBuilder_MetaTokenSlot = &mBuilder_TableRowScope;
|
||||
else if ( column == morkStore_kAtomScopeColumn )
|
||||
|
@ -715,7 +797,7 @@ morkBuilder::OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat)
|
|||
|
||||
/*virtual*/ void
|
||||
morkBuilder::OnCellEnd(morkEnv* ev, const morkSpan& inSpan)
|
||||
// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
|
||||
{
|
||||
MORK_USED_2(ev,inSpan);
|
||||
// mParser_InCell = morkBool_kFalse;
|
||||
|
@ -748,6 +830,49 @@ morkBuilder::OnValue(morkEnv* ev, const morkSpan& inSpan,
|
|||
{
|
||||
mork_token* metaSlot = mBuilder_MetaTokenSlot;
|
||||
if ( metaSlot )
|
||||
{
|
||||
if ( metaSlot == &mBuilder_TableStatus ) // table status?
|
||||
{
|
||||
if ( mParser_InTable && mBuilder_Table )
|
||||
{
|
||||
const char* body = (const char*) inBuf.mBuf_Body;
|
||||
mork_fill bufFill = inBuf.mBuf_Fill;
|
||||
if ( body && bufFill )
|
||||
{
|
||||
const char* bodyEnd = body + bufFill;
|
||||
while ( body < bodyEnd )
|
||||
{
|
||||
int c = *body++;
|
||||
switch ( c )
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
mBuilder_TablePriority = (mork_priority) ( c - '0' );
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
case 'U':
|
||||
mBuilder_TableIsUnique = morkBool_kTrue;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
case 'V':
|
||||
mBuilder_TableIsVerbose = morkBool_kTrue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mork_token token = store->BufToToken(ev, &inBuf);
|
||||
if ( token )
|
||||
|
@ -761,6 +886,7 @@ morkBuilder::OnValue(morkEnv* ev, const morkSpan& inSpan,
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilBuilderCellError(ev);
|
||||
}
|
||||
|
@ -815,6 +941,15 @@ morkBuilder::OnValueMid(morkEnv* ev, const morkSpan& inSpan,
|
|||
else
|
||||
ev->NewWarning("mBuilder_TableKind not in table");
|
||||
}
|
||||
else if ( metaSlot == &mBuilder_TableStatus ) // table status?
|
||||
{
|
||||
if ( mParser_InTable && mBuilder_Table )
|
||||
{
|
||||
// $$ what here??
|
||||
}
|
||||
else
|
||||
ev->NewWarning("mBuilder_TableStatus not in table");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -854,7 +989,7 @@ morkBuilder::OnRowMid(morkEnv* ev, const morkSpan& inSpan,
|
|||
cell->SetAtom(ev, atom, pool);
|
||||
morkRow* row = store->OidToRow(ev, &rowOid);
|
||||
if ( row ) // found or created such a row?
|
||||
row->AddTableUse(ev);
|
||||
row->AddRowGcUse(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -892,7 +1027,7 @@ morkBuilder::OnTableMid(morkEnv* ev, const morkSpan& inSpan,
|
|||
morkTable* table = store->OidToTable(ev, &tableOid,
|
||||
/*optionalMetaRowOid*/ (mdbOid*) 0);
|
||||
if ( table ) // found or created such a table?
|
||||
table->AddCellUse(ev);
|
||||
table->AddTableGcUse(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,6 +139,13 @@ protected: // protected morkBuilder members
|
|||
mork_scope mBuilder_TableAtomScope; // table atom scope
|
||||
mork_kind mBuilder_TableKind; // table kind
|
||||
|
||||
mork_token mBuilder_TableStatus; // dummy: priority/unique/verbose
|
||||
|
||||
mork_priority mBuilder_TablePriority; // table priority
|
||||
mork_bool mBuilder_TableIsUnique; // table uniqueness
|
||||
mork_bool mBuilder_TableIsVerbose; // table verboseness
|
||||
mork_u1 mBuilder_TablePadByte; // for u4 alignment
|
||||
|
||||
// tokens that become set as the result of meta cells in meta rows:
|
||||
mork_cscode mBuilder_RowForm; // default row charset format
|
||||
mork_scope mBuilder_RowRowScope; // row scope per row metainfo
|
||||
|
@ -160,8 +167,8 @@ protected: // protected morkBuilder members
|
|||
// CutCell implies the current column should be cut from the row.
|
||||
mork_bool mBuilder_DoCutRow; // row with kCut change
|
||||
mork_bool mBuilder_DoCutCell; // cell with kCut change
|
||||
mork_u1 mBuilder_Pad1; // pad to u4 alignment
|
||||
mork_u1 mBuilder_Pad2; // pad to u4 alignment
|
||||
mork_u1 mBuilder_row_pad; // pad to u4 alignment
|
||||
mork_u1 mBuilder_cell_pad; // pad to u4 alignment
|
||||
|
||||
morkCell mBuilder_CellsVec[ morkBuilder_kCellsVecSize + 1 ];
|
||||
mork_fill mBuilder_CellsVecFill; // count used in CellsVec
|
||||
|
@ -243,7 +250,7 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange);
|
||||
const morkMid& inMid, mork_bool inCutAllRows);
|
||||
virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
|
@ -251,8 +258,9 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnMinusRow(morkEnv* ev);
|
||||
virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange);
|
||||
const morkMid& inMid, mork_bool inCutAllCols);
|
||||
virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
|
@ -265,8 +273,9 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
|
||||
virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
|
||||
virtual void OnMinusCell(morkEnv* ev);
|
||||
virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid* inMid, const morkBuf* inBuf, mork_change inChange);
|
||||
const morkMid* inMid, const morkBuf* inBuf);
|
||||
// Exactly one of inMid and inBuf is nil, and the other is non-nil.
|
||||
// When hex ID syntax is used for a column, then inMid is not nil, and
|
||||
// when a naked string names a column, then inBuf is not nil.
|
||||
|
|
|
@ -69,6 +69,13 @@ morkCell::AliasYarn(morkEnv* ev, mdbYarn* outYarn) const
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
morkCell::SetCellClean()
|
||||
{
|
||||
mork_column col = this->GetColumn();
|
||||
this->SetColumnAndChange(col, morkChange_kNil);
|
||||
}
|
||||
|
||||
void
|
||||
morkCell::SetCellDirty()
|
||||
{
|
||||
|
|
|
@ -61,7 +61,17 @@ public:
|
|||
mork_column GetColumn() const { return morkDelta_Column(mCell_Delta); }
|
||||
mork_change GetChange() const { return morkDelta_Change(mCell_Delta); }
|
||||
|
||||
void SetCellDirty();
|
||||
mork_bool IsCellClean() const { return GetChange() == morkChange_kNil; }
|
||||
mork_bool IsCellDirty() const { return GetChange() != morkChange_kNil; }
|
||||
|
||||
void SetCellClean(); // set change to kNil
|
||||
void SetCellDirty(); // set change to kAdd
|
||||
|
||||
void SetCellColumnDirty(mork_column inCol)
|
||||
{ this->SetColumnAndChange(inCol, morkChange_kAdd); }
|
||||
|
||||
void SetCellColumnClean(mork_column inCol)
|
||||
{ this->SetColumnAndChange(inCol, morkChange_kNil); }
|
||||
|
||||
void SetColumnAndChange(mork_column inCol, mork_change inChange)
|
||||
{ morkDelta_Init(mCell_Delta, inCol, inChange); }
|
||||
|
|
|
@ -25,6 +25,10 @@ which are used interchangeably with the name IronDoc in the sources.)
|
|||
* There are no warranties, no guarantees, no promises, and no remedies.
|
||||
*/
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
@ -33,6 +37,174 @@ which are used interchangeably with the name IronDoc in the sources.)
|
|||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
/*=============================================================================
|
||||
* morkNext: linked list node for very simple, singly-linked list
|
||||
*/
|
||||
|
||||
morkNext::morkNext() : mNext_Link( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
/*static*/ void*
|
||||
morkNext::MakeNewNext(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{
|
||||
void* next = 0;
|
||||
if ( &ioHeap )
|
||||
{
|
||||
ioHeap.Alloc(ev->AsMdbEnv(), inSize, (void**) &next);
|
||||
if ( !next )
|
||||
ev->OutOfMemoryError();
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void morkNext::ZapOldNext(morkEnv* ev, nsIMdbHeap* ioHeap)
|
||||
{
|
||||
if ( &ioHeap )
|
||||
{
|
||||
if ( this )
|
||||
ioHeap->Free(ev->AsMdbEnv(), this);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
/*=============================================================================
|
||||
* morkList: simple, singly-linked list
|
||||
*/
|
||||
|
||||
morkList::morkList() : mList_Head( 0 ), mList_Tail( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void morkList::CutAndZapAllListMembers(morkEnv* ev, nsIMdbHeap* ioHeap)
|
||||
// make empty list, zapping every member by calling ZapOldNext()
|
||||
{
|
||||
if ( ioHeap )
|
||||
{
|
||||
morkNext* next = 0;
|
||||
while ( (next = this->PopHead()) != 0 )
|
||||
next->ZapOldNext(ev, ioHeap);
|
||||
|
||||
mList_Head = 0;
|
||||
mList_Tail = 0;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
void morkList::CutAllListMembers()
|
||||
// just make list empty, dropping members without zapping
|
||||
{
|
||||
while ( this->PopHead() )
|
||||
/* empty */;
|
||||
|
||||
mList_Head = 0;
|
||||
mList_Tail = 0;
|
||||
}
|
||||
|
||||
morkNext* morkList::PopHead() // cut head of list
|
||||
{
|
||||
morkNext* outHead = mList_Head;
|
||||
if ( outHead ) // anything to cut from list?
|
||||
{
|
||||
morkNext* next = outHead->mNext_Link;
|
||||
mList_Head = next;
|
||||
if ( !next ) // cut the last member, so tail no longer exists?
|
||||
mList_Tail = 0;
|
||||
|
||||
outHead->mNext_Link = 0; // nil outgoing node link; unnecessary, but tidy
|
||||
}
|
||||
return outHead;
|
||||
}
|
||||
|
||||
|
||||
void morkList::PushHead(morkNext* ioLink) // add to head of list
|
||||
{
|
||||
morkNext* head = mList_Head; // old head of list
|
||||
morkNext* tail = mList_Tail; // old tail of list
|
||||
|
||||
MORK_ASSERT( (head && tail) || (!head && !tail));
|
||||
|
||||
ioLink->mNext_Link = head; // make old head follow the new link
|
||||
if ( !head ) // list was previously empty?
|
||||
mList_Tail = ioLink; // head is also tail for first member added
|
||||
|
||||
mList_Head = ioLink; // head of list is the new link
|
||||
}
|
||||
|
||||
void morkList::PushTail(morkNext* ioLink) // add to tail of list
|
||||
{
|
||||
morkNext* head = mList_Head; // old head of list
|
||||
morkNext* tail = mList_Tail; // old tail of list
|
||||
|
||||
MORK_ASSERT( (head && tail) || (!head && !tail));
|
||||
|
||||
ioLink->mNext_Link = tail; // make old tail follow the new link
|
||||
if ( !tail ) // list was previously empty?
|
||||
mList_Head = ioLink; // tail is also head for first member added
|
||||
|
||||
mList_Tail = ioLink; // tail of list is the new link
|
||||
}
|
||||
|
||||
/*=============================================================================
|
||||
* morkLink: linked list node embedded in objs to allow insertion in morkDeques
|
||||
*/
|
||||
|
||||
morkLink::morkLink() : mLink_Next( 0 ), mLink_Prev( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
/*static*/ void*
|
||||
morkLink::MakeNewLink(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{
|
||||
void* link = 0;
|
||||
if ( &ioHeap )
|
||||
{
|
||||
ioHeap.Alloc(ev->AsMdbEnv(), inSize, (void**) &link);
|
||||
if ( !link )
|
||||
ev->OutOfMemoryError();
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void morkLink::ZapOldLink(morkEnv* ev, nsIMdbHeap* ioHeap)
|
||||
{
|
||||
if ( &ioHeap )
|
||||
{
|
||||
if ( this )
|
||||
ioHeap->Free(ev->AsMdbEnv(), this);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
/*=============================================================================
|
||||
* morkDeque: doubly linked list modeled after VAX queue instructions
|
||||
*/
|
||||
|
||||
morkDeque::morkDeque()
|
||||
{
|
||||
mDeque_Head.SelfRefer();
|
||||
}
|
||||
|
||||
|
||||
/*| RemoveFirst:
|
||||
|*/
|
||||
morkLink*
|
||||
|
|
|
@ -32,6 +32,81 @@ which are used interchangeably with the name IronDoc in the sources.)
|
|||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
/*=============================================================================
|
||||
* morkNext: linked list node for very simple, singly-linked list
|
||||
*/
|
||||
|
||||
class morkNext /*d*/ {
|
||||
public:
|
||||
morkNext* mNext_Link;
|
||||
|
||||
public:
|
||||
morkNext(int inZero) : mNext_Link( 0 ) { }
|
||||
|
||||
morkNext(morkNext* ioLink) : mNext_Link( ioLink ) { }
|
||||
|
||||
morkNext(); // mNext_Link( 0 ), { }
|
||||
|
||||
public:
|
||||
morkNext* GetNextLink() const { return mNext_Link; }
|
||||
|
||||
public: // link memory management methods
|
||||
static void* MakeNewNext(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev);
|
||||
void ZapOldNext(morkEnv* ev, nsIMdbHeap* ioHeap);
|
||||
|
||||
public: // link memory management operators
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{ return morkNext::MakeNewNext(inSize, ioHeap, ev); }
|
||||
|
||||
void operator delete(void* ioAddress) // DO NOT CALL THIS, hope to crash:
|
||||
{ ((morkNext*) 0)->ZapOldNext((morkEnv*) 0, (nsIMdbHeap*) 0); } // boom
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkList: simple, singly-linked list
|
||||
*/
|
||||
|
||||
/*| morkList: a list of singly-linked members (instances of morkNext), where
|
||||
**| the number of list members might be so numerous that we must about cost
|
||||
**| for two pointer link slots per member (as happens with morkLink).
|
||||
**|
|
||||
**|| morkList is intended to support lists of changes in morkTable, where we
|
||||
**| are worried about the space cost of representing such changes. (Later we
|
||||
**| can use an array instead, when we get even more worried, to avoid cost
|
||||
**| of link slots at all, per member).
|
||||
**|
|
||||
**|| Do NOT create cycles in links using this list class, since we do not
|
||||
**| deal with them very nicely.
|
||||
|*/
|
||||
class morkList /*d*/ {
|
||||
public:
|
||||
morkNext* mList_Head; // first link in the list
|
||||
morkNext* mList_Tail; // last link in the list
|
||||
|
||||
public:
|
||||
morkNext* GetListHead() const { return mList_Head; }
|
||||
morkNext* GetListTail() const { return mList_Tail; }
|
||||
|
||||
mork_bool IsListEmpty() const { return ( mList_Head == 0 ); }
|
||||
|
||||
public:
|
||||
morkList(); // : mList_Head( 0 ), mList_Tail( 0 ) { }
|
||||
|
||||
void CutAndZapAllListMembers(morkEnv* ev, nsIMdbHeap* ioHeap);
|
||||
// make empty list, zapping every member by calling ZapOldNext()
|
||||
|
||||
void CutAllListMembers();
|
||||
// just make list empty, dropping members without zapping
|
||||
|
||||
public:
|
||||
morkNext* PopHead(); // cut head of list
|
||||
|
||||
// Note we don't support PopTail(), so use morkDeque if you need that.
|
||||
|
||||
void PushHead(morkNext* ioLink); // add to head of list
|
||||
void PushTail(morkNext* ioLink); // add to tail of list
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkLink: linked list node embedded in objs to allow insertion in morkDeques
|
||||
*/
|
||||
|
@ -41,6 +116,11 @@ public:
|
|||
morkLink* mLink_Next;
|
||||
morkLink* mLink_Prev;
|
||||
|
||||
public:
|
||||
morkLink(int inZero) : mLink_Next( 0 ), mLink_Prev( 0 ) { }
|
||||
|
||||
morkLink(); // mLink_Next( 0 ), mLink_Prev( 0 ) { }
|
||||
|
||||
public:
|
||||
morkLink* Next() const { return mLink_Next; }
|
||||
morkLink* Prev() const { return mLink_Prev; }
|
||||
|
@ -64,6 +144,17 @@ public:
|
|||
{
|
||||
(mLink_Prev->mLink_Next = mLink_Next)->mLink_Prev = mLink_Prev;
|
||||
}
|
||||
|
||||
public: // link memory management methods
|
||||
static void* MakeNewLink(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev);
|
||||
void ZapOldLink(morkEnv* ev, nsIMdbHeap* ioHeap);
|
||||
|
||||
public: // link memory management operators
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{ return morkLink::MakeNewLink(inSize, ioHeap, ev); }
|
||||
|
||||
void operator delete(void* ioAddress) // DO NOT CALL THIS, hope to crash:
|
||||
{ ((morkLink*) 0)->ZapOldLink((morkEnv*) 0, (nsIMdbHeap*) 0); } // boom
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
|
@ -75,7 +166,7 @@ public:
|
|||
morkLink mDeque_Head;
|
||||
|
||||
public: // construction
|
||||
morkDeque() { mDeque_Head.SelfRefer(); }
|
||||
morkDeque(); // { mDeque_Head.SelfRefer(); }
|
||||
|
||||
public:// methods
|
||||
morkLink* RemoveFirst();
|
||||
|
|
|
@ -86,6 +86,7 @@ morkEnv::morkEnv(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
|||
, mEnv_DoTrace( morkBool_kFalse )
|
||||
, mEnv_AutoClear( morkAble_kDisabled )
|
||||
, mEnv_ShouldAbort( morkBool_kFalse )
|
||||
, mEnv_BeVerbose( morkBool_kFalse )
|
||||
{
|
||||
MORK_ASSERT(ioSlotHeap && ioFactory );
|
||||
if ( ioSlotHeap )
|
||||
|
@ -124,6 +125,8 @@ morkEnv::morkEnv(morkEnv* ev, /*i*/
|
|||
|
||||
, mEnv_DoTrace( morkBool_kFalse )
|
||||
, mEnv_AutoClear( morkAble_kDisabled )
|
||||
, mEnv_ShouldAbort( morkBool_kFalse )
|
||||
, mEnv_BeVerbose( morkBool_kFalse )
|
||||
{
|
||||
// $$$ do we need to refcount the inSelfAsMdbEnv nsIMdbEnv??
|
||||
|
||||
|
@ -159,6 +162,8 @@ morkEnv::CloseEnv(morkEnv* ev) /*i*/ // called by CloseMorkNode();
|
|||
mEnv_SelfAsMdbEnv = 0;
|
||||
mEnv_ErrorHook = 0;
|
||||
|
||||
morkPool::SlotStrongPool((morkPool*) 0, ev, &mEnv_HandlePool);
|
||||
|
||||
// mEnv_Factory is NOT refcounted
|
||||
|
||||
this->MarkShut();
|
||||
|
@ -260,6 +265,40 @@ morkEnv::TokenAsHex(void* outBuf, mork_token inToken)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::StringToYarn(const char* inString, mdbYarn* outYarn)
|
||||
{
|
||||
if ( outYarn )
|
||||
{
|
||||
mdb_fill fill = ( inString )? (mdb_fill) MORK_STRLEN(inString) : 0;
|
||||
|
||||
if ( fill ) // have nonempty content?
|
||||
{
|
||||
mdb_size size = outYarn->mYarn_Size; // max dest size
|
||||
if ( fill > size ) // too much string content?
|
||||
{
|
||||
outYarn->mYarn_More = fill - size; // extra string bytes omitted
|
||||
fill = size; // copy no more bytes than size of yarn buffer
|
||||
}
|
||||
void* dest = outYarn->mYarn_Buf; // where bytes are going
|
||||
if ( !dest ) // nil destination address buffer?
|
||||
fill = 0; // we can't write any content at all
|
||||
|
||||
if ( fill ) // anything to copy?
|
||||
MORK_MEMCPY(dest, inString, fill); // copy fill bytes to yarn
|
||||
|
||||
outYarn->mYarn_Fill = fill; // tell yarn size of copied content
|
||||
}
|
||||
else // no content to put into the yarn
|
||||
{
|
||||
outYarn->mYarn_Fill = 0; // tell yarn that string has no bytes
|
||||
}
|
||||
outYarn->mYarn_Form = 0; // always update the form slot
|
||||
}
|
||||
else
|
||||
this->NilPointerError();
|
||||
}
|
||||
|
||||
char*
|
||||
morkEnv::CopyString(nsIMdbHeap* ioHeap, const char* inString)
|
||||
{
|
||||
|
@ -351,6 +390,12 @@ morkEnv::OutOfMemoryError()
|
|||
this->NewError("out of memory");
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::CantMakeWhenBadError()
|
||||
{
|
||||
this->NewError("can't make an object when ev->Bad()");
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::NilPointerError()
|
||||
{
|
||||
|
|
|
@ -93,7 +93,7 @@ public: // state is public because the entire Mork system is private
|
|||
mork_bool mEnv_DoTrace;
|
||||
mork_able mEnv_AutoClear;
|
||||
mork_bool mEnv_ShouldAbort;
|
||||
mork_bool mEnv_Pad;
|
||||
mork_bool mEnv_BeVerbose;
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
|
@ -129,6 +129,7 @@ public: // utility env methods
|
|||
|
||||
char* CopyString(nsIMdbHeap* ioHeap, const char* inString);
|
||||
void FreeString(nsIMdbHeap* ioHeap, char* ioString);
|
||||
void StringToYarn(const char* inString, mdbYarn* outYarn);
|
||||
|
||||
public: // other env methods
|
||||
|
||||
|
@ -157,6 +158,7 @@ public: // other env methods
|
|||
void StubMethodOnlyError();
|
||||
void OutOfMemoryError();
|
||||
void NilPointerError();
|
||||
void CantMakeWhenBadError();
|
||||
void NewNonEnvError();
|
||||
void NilEnvSlotError();
|
||||
|
||||
|
|
|
@ -36,6 +36,10 @@
|
|||
#include "morkFile.h"
|
||||
#endif
|
||||
|
||||
// #ifndef _ORKINFILE_
|
||||
// #include "orkinFile.h"
|
||||
// #endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
|
@ -65,7 +69,7 @@ morkFile::~morkFile() // assert CloseFile() executed earlier
|
|||
/*public non-poly*/
|
||||
morkFile::morkFile(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkNode(ev, inUsage, ioHeap)
|
||||
: morkObject(ev, inUsage, ioHeap, (morkHandle*) 0)
|
||||
, mFile_Frozen( 0 )
|
||||
, mFile_DoTrace( 0 )
|
||||
, mFile_IoOpen( 0 )
|
||||
|
@ -73,6 +77,7 @@ morkFile::morkFile(morkEnv* ev, const morkUsage& inUsage,
|
|||
|
||||
, mFile_SlotHeap( 0 )
|
||||
, mFile_Name( 0 )
|
||||
, mFile_Thief( 0 )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
|
@ -101,6 +106,10 @@ morkFile::CloseFile(morkEnv* ev) // called by CloseMorkNode();
|
|||
|
||||
if ( mFile_Name )
|
||||
this->SetFileName(ev, (const char*) 0);
|
||||
|
||||
nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mFile_SlotHeap);
|
||||
nsIMdbFile_SlotStrongFile((nsIMdbFile*) 0, ev, &mFile_Thief);
|
||||
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
|
@ -113,6 +122,28 @@ morkFile::CloseFile(morkEnv* ev) // called by CloseMorkNode();
|
|||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
nsIMdbFile*
|
||||
morkFile::AcquireFileHandle(morkEnv* ev)
|
||||
{
|
||||
nsIMdbFile* outFile = 0;
|
||||
|
||||
#ifdef MORK_CONFIG_USE_ORKINFILE
|
||||
orkinFile* f = (orkinFile*) mObject_Handle;
|
||||
if ( f ) // have an old handle?
|
||||
f->AddStrongRef(ev->AsMdbEnv());
|
||||
else // need new handle?
|
||||
{
|
||||
f = orkinFile::MakeFile(ev, this);
|
||||
mObject_Handle = f;
|
||||
}
|
||||
if ( f )
|
||||
outFile = f;
|
||||
#endif /*MORK_CONFIG_USE_ORKINFILE*/
|
||||
MORK_USED_1(ev);
|
||||
|
||||
return outFile;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkFile::BecomeTrunk(morkEnv* ev)
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
|
@ -158,6 +189,12 @@ morkFile::NewMissingIoError(morkEnv* ev) const
|
|||
ev->NewError("file missing io");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkFile::NonFileTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkFile");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkFile::NilSlotHeapError(morkEnv* ev)
|
||||
{
|
||||
|
@ -170,6 +207,12 @@ morkFile::NilFileNameError(morkEnv* ev)
|
|||
ev->NewError("nil mFile_Name");
|
||||
}
|
||||
|
||||
void
|
||||
morkFile::SetThief(morkEnv* ev, nsIMdbFile* ioThief)
|
||||
{
|
||||
nsIMdbFile_SlotStrongFile(ioThief, ev, &mFile_Thief);
|
||||
}
|
||||
|
||||
void
|
||||
morkFile::SetFileName(morkEnv* ev, const char* inName) // inName can be nil
|
||||
{
|
||||
|
@ -216,7 +259,8 @@ void
|
|||
morkFile::NewFileErrnoError(morkEnv* ev) const
|
||||
// call NewFileErrnoError() to convert std C errno into AB fault
|
||||
{
|
||||
ev->NewError("errno"); // maybe pass value of strerror() instead
|
||||
const char* errnoString = strerror(errno);
|
||||
ev->NewError(errnoString); // maybe pass value of strerror() instead
|
||||
}
|
||||
|
||||
// ````` ````` ````` ````` newlines ````` ````` ````` `````
|
||||
|
@ -347,6 +391,7 @@ morkStdioFile::CreateNewStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
|
|||
}
|
||||
|
||||
|
||||
|
||||
/*public virtual*/ void
|
||||
morkStdioFile::BecomeTrunk(morkEnv* ev)
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
|
@ -414,7 +459,15 @@ morkStdioFile::AcquireBud(morkEnv* ev, nsIMdbHeap* ioHeap)
|
|||
if ( ev->Good() && this->AddStrongRef(ev) )
|
||||
outFile = this;
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
{
|
||||
nsIMdbFile* outBud = 0;
|
||||
mFile_Thief->AcquireBud(ev->AsMdbEnv(), ioHeap, &outBud);
|
||||
if ( outBud )
|
||||
outBud->CutStrongRef(ev->AsMdbEnv()); // convert to morkFile later
|
||||
}
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -452,7 +505,10 @@ morkStdioFile::Length(morkEnv* ev) const
|
|||
}
|
||||
else this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Eof(ev->AsMdbEnv(), &outPos);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -475,7 +531,10 @@ morkStdioFile::Tell(morkEnv* ev) const
|
|||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Tell(ev->AsMdbEnv(), &outPos);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -499,7 +558,10 @@ morkStdioFile::Read(morkEnv* ev, void* outBuf, mork_size inSize)
|
|||
}
|
||||
else this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Read(ev->AsMdbEnv(), outBuf, inSize, &outCount);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -522,7 +584,10 @@ morkStdioFile::Seek(morkEnv* ev, mork_pos inPos)
|
|||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Seek(ev->AsMdbEnv(), inPos);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -539,12 +604,16 @@ morkStdioFile::Write(morkEnv* ev, const void* inBuf, mork_size inSize)
|
|||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( file )
|
||||
{
|
||||
if ( fwrite(inBuf, 1, inSize, file) >= 0 )
|
||||
fwrite(inBuf, 1, inSize, file);
|
||||
if ( !ferror(file) )
|
||||
outCount = inSize;
|
||||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Write(ev->AsMdbEnv(), inBuf, inSize, &outCount);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
|
@ -562,7 +631,10 @@ morkStdioFile::Flush(morkEnv* ev)
|
|||
MORK_FILEFLUSH(file);
|
||||
|
||||
}
|
||||
else this->NewMissingIoError(ev);
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Flush(ev->AsMdbEnv());
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
}
|
||||
|
@ -575,9 +647,14 @@ morkStdioFile::new_stdio_file_fault(morkEnv* ev) const
|
|||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
|
||||
int copyErrno = errno; // facilitate seeing error in debugger
|
||||
|
||||
// bunch of stuff not ported here
|
||||
if ( !errno && file )
|
||||
errno = ferror(file);
|
||||
if ( !copyErrno && file )
|
||||
{
|
||||
copyErrno = ferror(file);
|
||||
errno = copyErrno;
|
||||
}
|
||||
|
||||
this->NewFileErrnoError(ev);
|
||||
}
|
||||
|
@ -714,4 +791,23 @@ morkStdioFile::CloseStdio(morkEnv* ev)
|
|||
}
|
||||
|
||||
|
||||
/*public virtual*/ void
|
||||
morkStdioFile::Steal(morkEnv* ev, nsIMdbFile* ioThief)
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
// file's content, typically by assuming the original file's identity.
|
||||
{
|
||||
if ( mStdioFile_File && this->FileActive() && this->FileIoOpen() )
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( MORK_FILECLOSE(file) < 0 )
|
||||
this->new_stdio_file_fault(ev);
|
||||
|
||||
mStdioFile_File = 0;
|
||||
}
|
||||
this->SetThief(ev, ioThief);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*=============================================================================
|
||||
|
@ -35,7 +39,25 @@
|
|||
|
||||
#define morkDerived_kFile /*i*/ 0x4669 /* ascii 'Fi' */
|
||||
|
||||
class morkFile /*d*/ : public morkNode { /* ````` simple file API ````` */
|
||||
class morkFile /*d*/ : public morkObject { /* ````` simple file API ````` */
|
||||
|
||||
// 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: // slots inherited from morkObject (meant to inform only)
|
||||
|
||||
// morkHandle* mObject_Handle; // weak ref to handle for this object
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
protected: // protected morkFile members (similar to public domain IronDoc)
|
||||
|
@ -49,6 +71,8 @@ protected: // protected morkFile members (similar to public domain IronDoc)
|
|||
char* mFile_Name; // can be nil if SetFileName() is never called
|
||||
// mFile_Name convention: managed with morkEnv::CopyString()/FreeString()
|
||||
|
||||
nsIMdbFile* mFile_Thief; // from a call to orkinFile::Steal()
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseFile() only if open
|
||||
|
@ -92,6 +116,17 @@ public: // public static standard file creation entry point
|
|||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // virtual morkFile methods
|
||||
|
||||
virtual void Steal(morkEnv* ev, nsIMdbFile* ioThief) = 0;
|
||||
// Steal: tell this file to close any associated i/o stream in the file
|
||||
// system, because the file ioThief intends to reopen the file in order
|
||||
// to provide the MDB implementation with more exotic file access than is
|
||||
// offered by the nsIMdbFile alone. Presumably the thief knows enough
|
||||
// from Path() in order to know which file to reopen. If Steal() is
|
||||
// successful, this file should probably delegate all future calls to
|
||||
// the nsIMdbFile interface down to the thief files, so that even after
|
||||
// the file has been stolen, it can still be read, written, or forcibly
|
||||
// closed (by a call to CloseMdbObject()).
|
||||
|
||||
virtual void BecomeTrunk(morkEnv* ev);
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
|
@ -127,6 +162,8 @@ public: // virtual morkFile methods
|
|||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // non-poly morkFile methods
|
||||
|
||||
nsIMdbFile* AcquireFileHandle(morkEnv* ev); // mObject_Handle
|
||||
|
||||
mork_bool FileFrozen() const { return mFile_Frozen == 'F'; }
|
||||
mork_bool FileDoTrace() const { return mFile_DoTrace == 'T'; }
|
||||
mork_bool FileIoOpen() const { return mFile_IoOpen == 'O'; }
|
||||
|
@ -146,9 +183,15 @@ public: // non-poly morkFile methods
|
|||
{ return ( this->IsOpenNode() && this->FileActive() ); }
|
||||
// call IsOpenAndActiveFile() before using a file
|
||||
|
||||
|
||||
nsIMdbFile* GetThief() const { return mFile_Thief; }
|
||||
void SetThief(morkEnv* ev, nsIMdbFile* ioThief); // ioThief can be nil
|
||||
|
||||
const char* GetFileNameString() const { return mFile_Name; }
|
||||
void SetFileName(morkEnv* ev, const char* inName); // inName can be nil
|
||||
static void NilSlotHeapError(morkEnv* ev);
|
||||
static void NilFileNameError(morkEnv* ev);
|
||||
static void NonFileTypeError(morkEnv* ev);
|
||||
|
||||
void NewMissingIoError(morkEnv* ev) const;
|
||||
|
||||
|
@ -220,6 +263,17 @@ public: // compatible with the morkFile::OpenOldFile() entry point
|
|||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // virtual ab_File methods
|
||||
|
||||
virtual void Steal(morkEnv* ev, nsIMdbFile* ioThief);
|
||||
// Steal: tell this file to close any associated i/o stream in the file
|
||||
// system, because the file ioThief intends to reopen the file in order
|
||||
// to provide the MDB implementation with more exotic file access than is
|
||||
// offered by the nsIMdbFile alone. Presumably the thief knows enough
|
||||
// from Path() in order to know which file to reopen. If Steal() is
|
||||
// successful, this file should probably delegate all future calls to
|
||||
// the nsIMdbFile interface down to the thief files, so that even after
|
||||
// the file has been stolen, it can still be read, written, or forcibly
|
||||
// closed (by a call to CloseMdbObject()).
|
||||
|
||||
virtual void BecomeTrunk(morkEnv* ev);
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
|
|
|
@ -63,6 +63,7 @@ morkHandle::~morkHandle() // assert CloseHandle() executed earlier
|
|||
MORK_ASSERT(mHandle_Face==0);
|
||||
MORK_ASSERT(mHandle_Object==0);
|
||||
MORK_ASSERT(mHandle_Magic==0);
|
||||
MORK_ASSERT(mHandle_Tag==morkHandle_kTag); // should still have correct tag
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
|
@ -90,6 +91,8 @@ morkHandle::morkHandle(morkEnv* ev, // note morkUsage is always morkUsage_kPool
|
|||
mNode_Derived = morkDerived_kHandle;
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->CantMakeWhenBadError();
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
|
|
@ -250,6 +250,8 @@ morkNode::morkNode(const morkUsage& inUsage, nsIMdbHeap* ioHeap)
|
|||
, mNode_Uses( 1 )
|
||||
, mNode_Refs( 1 )
|
||||
{
|
||||
if ( !ioHeap && mNode_Usage == morkUsage_kHeap )
|
||||
MORK_ASSERT(ioHeap);
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
|
@ -340,12 +342,31 @@ morkNode::CloseNode(morkEnv* ev) // called by CloseMorkNode();
|
|||
}
|
||||
|
||||
|
||||
extern void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbFile_SlotStrongFile(nsIMdbFile* self, morkEnv* ev, nsIMdbFile** ioSlot)
|
||||
// If *ioSlot is non-nil, that file is released by CutStrongRef() and
|
||||
// then zeroed out. Then if self is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we take
|
||||
// expression 'nsIMdbFile_SlotStrongFile(0, ev, &slot)'.
|
||||
{
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
nsIMdbFile* file = *ioSlot;
|
||||
if ( file )
|
||||
{
|
||||
*ioSlot = 0;
|
||||
file->CutStrongRef(menv);
|
||||
}
|
||||
if ( self && ev->Good() && (self->AddStrongRef(menv)==0) && ev->Good() )
|
||||
*ioSlot = self;
|
||||
}
|
||||
|
||||
void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbHeap_SlotStrongHeap(nsIMdbHeap* self, morkEnv* ev, nsIMdbHeap** ioSlot)
|
||||
// If *ioSlot is non-nil, that heap is released by CutStrongRef() and
|
||||
// then zeroed out. Then if this is non-nil, this is acquired by
|
||||
// then zeroed out. Then if self is non-nil, self is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then this is put into slot *ioSlot. Note self can be nil, so we
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we
|
||||
// permit expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'.
|
||||
{
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
|
|
|
@ -121,11 +121,11 @@ public: // inlines for weird mNode_Mutable and mNode_Load constants
|
|||
mork_bool IsMutable() const { return mNode_Mutable == morkAble_kEnabled; }
|
||||
mork_bool IsAsleep() const { return mNode_Mutable == morkAble_kAsleep; }
|
||||
|
||||
void SetClean() { mNode_Load = morkLoad_kClean; }
|
||||
void SetDirty() { mNode_Load = morkLoad_kDirty; }
|
||||
void SetNodeClean() { mNode_Load = morkLoad_kClean; }
|
||||
void SetNodeDirty() { mNode_Load = morkLoad_kDirty; }
|
||||
|
||||
mork_bool IsClean() const { return mNode_Load == morkLoad_kClean; }
|
||||
mork_bool IsDirty() const { return mNode_Load == morkLoad_kDirty; }
|
||||
mork_bool IsNodeClean() const { return mNode_Load == morkLoad_kClean; }
|
||||
mork_bool IsNodeDirty() const { return mNode_Load == morkLoad_kDirty; }
|
||||
|
||||
public: // morkNode memory management methods
|
||||
static void* MakeNew(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev);
|
||||
|
@ -264,10 +264,18 @@ public: // refcounting for typesafe subclass inline methods
|
|||
extern void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbHeap_SlotStrongHeap(nsIMdbHeap* self, morkEnv* ev, nsIMdbHeap** ioSlot);
|
||||
// If *ioSlot is non-nil, that heap is released by CutStrongRef() and
|
||||
// then zeroed out. Then if me is non-nil, this is acquired by
|
||||
// then zeroed out. Then if self is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then me is put into slot *ioSlot. Note me can be nil, so we take
|
||||
// expression 'nsIMdbHeap_SlotStrongNode(0, ev, &slot)'.
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we take
|
||||
// expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'.
|
||||
|
||||
extern void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbFile_SlotStrongFile(nsIMdbFile* self, morkEnv* ev, nsIMdbFile** ioSlot);
|
||||
// If *ioSlot is non-nil, that file is released by CutStrongRef() and
|
||||
// then zeroed out. Then if self is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we take
|
||||
// expression 'nsIMdbHeap_SlotStrongFile(0, ev, &slot)'.
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
|
|
@ -325,7 +325,11 @@ int morkParser::eat_comment(morkEnv* ev) // last char was '/'
|
|||
if ( c == '*' ) // maybe end of a comment, if next char is '/'?
|
||||
{
|
||||
if ( (c = s->Getc(ev)) == '/' ) // end of comment?
|
||||
{
|
||||
--depth; // depth of comments has decreased by one
|
||||
if ( !depth ) // comments all done?
|
||||
c = s->Getc(ev); // return the byte after end of comment
|
||||
}
|
||||
else if ( c != EOF ) // need to put the char back?
|
||||
s->Ungetc(c); // especially need to put back '*', 0xA, or 0xD
|
||||
}
|
||||
|
@ -543,8 +547,9 @@ morkParser::ReadCell(morkEnv* ev)
|
|||
|
||||
mParser_InCell = morkBool_kTrue;
|
||||
this->OnNewCell(ev, *mParser_CellSpan.AsPlace(),
|
||||
cellMid, cellBuf, mParser_CellChange);
|
||||
cellMid, cellBuf); // , mParser_CellChange
|
||||
|
||||
mParser_CellChange = morkChange_kNil;
|
||||
if ( (c = this->NextChar(ev)) != EOF && ev->Good() )
|
||||
{
|
||||
this->StartSpanOnLastByte(ev, &mParser_SlotSpan);
|
||||
|
@ -589,6 +594,7 @@ morkParser::ReadCell(morkEnv* ev)
|
|||
this->OnCellEnd(ev, mParser_CellSpan);
|
||||
}
|
||||
}
|
||||
mParser_CellChange = morkChange_kNil;
|
||||
|
||||
if ( c == EOF && ev->Good() )
|
||||
this->UnexpectedEofError(ev);
|
||||
|
@ -608,11 +614,18 @@ void morkParser::ReadRow(morkEnv* ev, int c)
|
|||
|
||||
if ( c == '[' )
|
||||
{
|
||||
mork_bool cutAllRowCols = morkBool_kFalse;
|
||||
|
||||
if ( ( c = this->NextChar(ev) ) == '-' )
|
||||
cutAllRowCols = morkBool_kTrue;
|
||||
else if ( ev->Good() && c != EOF )
|
||||
mParser_Stream->Ungetc(c);
|
||||
|
||||
if ( this->ReadMid(ev, &mParser_RowMid) )
|
||||
{
|
||||
mParser_InRow = morkBool_kTrue;
|
||||
this->OnNewRow(ev, *mParser_RowSpan.AsPlace(),
|
||||
mParser_RowMid, mParser_RowChange);
|
||||
mParser_RowMid, cutAllRowCols);
|
||||
|
||||
mParser_Change = mParser_RowChange = morkChange_kNil;
|
||||
|
||||
|
@ -628,17 +641,18 @@ void morkParser::ReadRow(morkEnv* ev, int c)
|
|||
this->ReadMeta(ev, ']');
|
||||
break;
|
||||
|
||||
case '+': // plus
|
||||
mParser_CellChange = morkChange_kAdd;
|
||||
break;
|
||||
// case '+': // plus
|
||||
// mParser_CellChange = morkChange_kAdd;
|
||||
// break;
|
||||
|
||||
case '-': // minus
|
||||
mParser_CellChange = morkChange_kCut;
|
||||
// mParser_CellChange = morkChange_kCut;
|
||||
this->OnMinusCell(ev);
|
||||
break;
|
||||
|
||||
case '!': // bang
|
||||
mParser_CellChange = morkChange_kSet;
|
||||
break;
|
||||
// case '!': // bang
|
||||
// mParser_CellChange = morkChange_kSet;
|
||||
// break;
|
||||
|
||||
default:
|
||||
ev->NewWarning("unexpected byte in row");
|
||||
|
@ -688,11 +702,19 @@ void morkParser::ReadTable(morkEnv* ev)
|
|||
if ( mParser_Change )
|
||||
mParser_TableChange = mParser_Change;
|
||||
|
||||
mork_bool cutAllTableRows = morkBool_kFalse;
|
||||
|
||||
int c = this->NextChar(ev);
|
||||
if ( c == '-' )
|
||||
cutAllTableRows = morkBool_kTrue;
|
||||
else if ( ev->Good() && c != EOF )
|
||||
mParser_Stream->Ungetc(c);
|
||||
|
||||
if ( ev->Good() && this->ReadMid(ev, &mParser_TableMid) )
|
||||
{
|
||||
mParser_InTable = morkBool_kTrue;
|
||||
this->OnNewTable(ev, *mParser_TableSpan.AsPlace(),
|
||||
mParser_TableMid, mParser_TableChange);
|
||||
mParser_TableMid, cutAllTableRows);
|
||||
|
||||
mParser_Change = mParser_TableChange = morkChange_kNil;
|
||||
|
||||
|
@ -715,17 +737,18 @@ void morkParser::ReadTable(morkEnv* ev)
|
|||
this->ReadMeta(ev, '}');
|
||||
break;
|
||||
|
||||
case '+': // plus
|
||||
mParser_RowChange = morkChange_kAdd;
|
||||
break;
|
||||
// case '+': // plus
|
||||
// mParser_RowChange = morkChange_kAdd;
|
||||
// break;
|
||||
|
||||
case '-': // minus
|
||||
mParser_RowChange = morkChange_kCut;
|
||||
// mParser_RowChange = morkChange_kCut;
|
||||
this->OnMinusRow(ev);
|
||||
break;
|
||||
|
||||
case '!': // bang
|
||||
mParser_RowChange = morkChange_kSet;
|
||||
break;
|
||||
// case '!': // bang
|
||||
// mParser_RowChange = morkChange_kSet;
|
||||
// break;
|
||||
|
||||
default:
|
||||
ev->NewWarning("unexpected byte in table");
|
||||
|
@ -809,6 +832,7 @@ morkParser::UnexpectedEofError(morkEnv* ev)
|
|||
ev->NewWarning("unexpected eof");
|
||||
}
|
||||
|
||||
|
||||
morkBuf* morkParser::ReadValue(morkEnv* ev)
|
||||
{
|
||||
morkBuf* outBuf = 0;
|
||||
|
@ -825,11 +849,17 @@ morkBuf* morkParser::ReadValue(morkEnv* ev)
|
|||
register int c;
|
||||
while ( (c = s->Getc(ev)) != EOF && c != ')' && ev->Good() )
|
||||
{
|
||||
if ( c == '\\' ) // "\" escapes the next char?
|
||||
if ( c == '\\' ) // next char is escaped by '\'?
|
||||
{
|
||||
if ( (c = s->Getc(ev)) == 0xA || c == 0xD ) // linebreak after \?
|
||||
{
|
||||
c = this->eat_line_break(ev, c);
|
||||
|
||||
if ( c == ')' || c == '\\' || c == '$' )
|
||||
{
|
||||
s->Ungetc(c); // just let while loop test read this again
|
||||
continue; // goto next iteration of while loop
|
||||
}
|
||||
}
|
||||
if ( c == EOF || ev->Bad() )
|
||||
break; // end while loop
|
||||
}
|
||||
|
@ -844,10 +874,10 @@ morkBuf* morkParser::ReadValue(morkEnv* ev)
|
|||
c = ev->HexToByte(first, second);
|
||||
}
|
||||
else
|
||||
break;
|
||||
break; // end while loop
|
||||
}
|
||||
else
|
||||
break;
|
||||
break; // end while loop
|
||||
}
|
||||
spool->Putc(ev, c);
|
||||
}
|
||||
|
@ -974,10 +1004,10 @@ morkParser::NonParserTypeError(morkEnv* ev)
|
|||
mork_bool morkParser::MatchPattern(morkEnv* ev, const char* inPattern)
|
||||
{
|
||||
// if an error occurs, we want original inPattern in the debugger:
|
||||
const char* pattern = inPattern; // mutable copy
|
||||
const char* pattern = inPattern; // mutable copy of pointer
|
||||
morkStream* s = mParser_Stream;
|
||||
register int c;
|
||||
while ( *inPattern && ev->Good() )
|
||||
while ( *pattern && ev->Good() )
|
||||
{
|
||||
char byte = *pattern++;
|
||||
if ( (c = s->Getc(ev)) != byte )
|
||||
|
@ -988,27 +1018,165 @@ mork_bool morkParser::MatchPattern(morkEnv* ev, const char* inPattern)
|
|||
return ev->Good();
|
||||
}
|
||||
|
||||
mork_bool morkParser::FindGroupEnd(morkEnv* ev)
|
||||
{
|
||||
mork_bool foundEnd = morkBool_kFalse;
|
||||
|
||||
// char gidBuf[ 64 ]; // to hold hex pattern we want
|
||||
// (void) ev->TokenAsHex(gidBuf, mParser_GroupId);
|
||||
|
||||
morkStream* s = mParser_Stream;
|
||||
register int c;
|
||||
|
||||
while ( (c = s->Getc(ev)) != EOF && ev->Good() && !foundEnd )
|
||||
{
|
||||
if ( c == '@' ) // maybe start of group ending?
|
||||
{
|
||||
this->EndSpanOnThisByte(ev, &mParser_GroupSpan);
|
||||
if ( (c = s->Getc(ev)) == '$' ) // '$' follows '@' ?
|
||||
{
|
||||
if ( (c = s->Getc(ev)) == '$' ) // '$' follows "@$" ?
|
||||
{
|
||||
if ( (c = s->Getc(ev)) == '}' )
|
||||
{
|
||||
foundEnd = this->ReadEndGroupId(ev);
|
||||
this->EndSpanOnThisByte(ev, &mParser_GroupSpan);
|
||||
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '}' after @$$");
|
||||
}
|
||||
}
|
||||
if ( !foundEnd && c == '@' )
|
||||
s->Ungetc(c);
|
||||
}
|
||||
}
|
||||
|
||||
return foundEnd && ev->Good();
|
||||
}
|
||||
|
||||
void morkParser::ReadGroup(morkEnv* ev)
|
||||
{
|
||||
int next = 0;
|
||||
mParser_GroupId = this->ReadHex(ev, &next);
|
||||
if ( next == '{' )
|
||||
{
|
||||
morkStream* s = mParser_Stream;
|
||||
register int c;
|
||||
if ( (c = s->Getc(ev)) == '@' )
|
||||
{
|
||||
this->StartSpanOnThisByte(ev, &mParser_GroupSpan);
|
||||
mork_pos startPos = mParser_GroupSpan.mSpan_Start.mPlace_Pos;
|
||||
|
||||
// if ( !store->mStore_FirstCommitGroupPos )
|
||||
// store->mStore_FirstCommitGroupPos = startPos;
|
||||
// else if ( !store->mStore_SecondCommitGroupPos )
|
||||
// store->mStore_SecondCommitGroupPos = startPos;
|
||||
|
||||
if ( this->FindGroupEnd(ev) )
|
||||
{
|
||||
s->Seek(ev, startPos);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->OnNewGroup(ev, mParser_GroupSpan.mSpan_Start,
|
||||
mParser_GroupId);
|
||||
|
||||
this->ReadContent(ev, /*inInsideGroup*/ morkBool_kTrue);
|
||||
|
||||
this->OnGroupCommitEnd(ev, mParser_GroupSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '@' after @$${id{");
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '{' after @$$id");
|
||||
|
||||
}
|
||||
|
||||
mork_bool morkParser::ReadAt(morkEnv* ev, mork_bool inInsideGroup)
|
||||
/* groups must be ignored until properly terminated */
|
||||
// zm:Group ::= zm:GroupStart zm:Content zm:GroupEnd /* transaction */
|
||||
// zm:GroupStart ::= zm:S? '@$${' zm:Id '{@' /* transaction id has own space */
|
||||
// zm:GroupStart ::= zm:S? '@$${' zm:Hex+ '{@' /* xaction id has own space */
|
||||
// zm:GroupEnd ::= zm:GroupCommit | zm:GroupAbort
|
||||
// zm:GroupCommit ::= zm:S? '@$$}' zm:Id '}@' /* id matches start id */
|
||||
// zm:GroupAbort ::= zm:S? '@$$}~~' zm:Id '}@' /* id matches start id */
|
||||
// zm:GroupCommit ::= zm:S? '@$$}' zm:Hex+ '}@' /* id matches start id */
|
||||
// zm:GroupAbort ::= zm:S? '@$$}~~}@' /* id matches start id */
|
||||
/* We must allow started transactions to be aborted in summary files. */
|
||||
/* Note '$$' will never occur unescaped in values we will see in Mork. */
|
||||
{
|
||||
if ( this->MatchPattern(ev, "$${") )
|
||||
if ( this->MatchPattern(ev, "$$") )
|
||||
{
|
||||
//morkMid cellMid = &mParser_CellMid;
|
||||
//if ( this->ReadMid(ev, cellMid) )
|
||||
//{
|
||||
// if ( this->MatchPattern(ev, "}@") )
|
||||
// {
|
||||
// }
|
||||
//}
|
||||
morkStream* s = mParser_Stream;
|
||||
register int c;
|
||||
int next = 0;
|
||||
if ( ((c = s->Getc(ev)) == '{' || c == '}') && ev->Good() )
|
||||
{
|
||||
if ( c == '{' ) // start of new group?
|
||||
{
|
||||
if ( !inInsideGroup )
|
||||
this->ReadGroup(ev);
|
||||
else
|
||||
ev->NewError("nested @$${ inside another group");
|
||||
}
|
||||
else // c == '}' // end of old group?
|
||||
{
|
||||
if ( inInsideGroup )
|
||||
{
|
||||
this->ReadEndGroupId(ev);
|
||||
mParser_GroupId = 0;
|
||||
}
|
||||
else
|
||||
ev->NewError("unmatched @$$} outside any group");
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '{' or '}' after @$$");
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
mork_bool morkParser::ReadEndGroupId(morkEnv* ev)
|
||||
{
|
||||
mork_bool outSawGroupId = morkBool_kFalse;
|
||||
morkStream* s = mParser_Stream;
|
||||
register int c;
|
||||
if ( (c = s->Getc(ev)) != EOF && ev->Good() )
|
||||
{
|
||||
if ( c == '~' ) // transaction is aborted?
|
||||
{
|
||||
this->MatchPattern(ev, "~}@"); // finish rest of pattern
|
||||
}
|
||||
else // push back byte and read expected trailing hex id
|
||||
{
|
||||
s->Ungetc(c);
|
||||
int next = 0;
|
||||
mork_gid endGroupId = this->ReadHex(ev, &next);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( endGroupId == mParser_GroupId ) // matches start?
|
||||
{
|
||||
if ( next == '}' ) // '}' after @$$}id ?
|
||||
{
|
||||
if ( (c = s->Getc(ev)) == '@' ) // '@' after @$$}id} ?
|
||||
{
|
||||
// looks good, so return with no error
|
||||
outSawGroupId = morkBool_kTrue;
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '@' after @$$}id}");
|
||||
}
|
||||
else
|
||||
ev->NewError("expected '}' after @$$}id");
|
||||
}
|
||||
else
|
||||
ev->NewError("end group id mismatch");
|
||||
}
|
||||
}
|
||||
}
|
||||
return ( outSawGroupId && ev->Good() );
|
||||
}
|
||||
|
||||
|
||||
void morkParser::ReadDict(morkEnv* ev)
|
||||
// zm:Dict ::= zm:S? '<' zm:DictItem* zm:S? '>'
|
||||
|
@ -1062,6 +1230,21 @@ void morkParser::EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan)
|
|||
}
|
||||
}
|
||||
|
||||
void morkParser::EndSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan)
|
||||
{
|
||||
mork_pos here = mParser_Stream->Tell(ev);
|
||||
if ( here > 0 ) // positive?
|
||||
--here;
|
||||
else
|
||||
here = 0;
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->SetHerePos(here);
|
||||
ioSpan->SetEndWithEnd(mParser_PortSpan);
|
||||
}
|
||||
}
|
||||
|
||||
void morkParser::StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan)
|
||||
{
|
||||
mork_pos here = mParser_Stream->Tell(ev);
|
||||
|
@ -1078,12 +1261,20 @@ void morkParser::StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkParser::OnPortState(morkEnv* ev)
|
||||
void morkParser::StartSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan)
|
||||
{
|
||||
mParser_InPort = morkBool_kTrue;
|
||||
this->OnNewPort(ev, *mParser_PortSpan.AsPlace());
|
||||
mork_pos here = mParser_Stream->Tell(ev);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->SetHerePos(here);
|
||||
ioSpan->SetStartWithEnd(mParser_PortSpan);
|
||||
ioSpan->SetEndWithEnd(mParser_PortSpan);
|
||||
}
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkParser::ReadContent(morkEnv* ev, mork_bool inInsideGroup)
|
||||
{
|
||||
int c;
|
||||
while ( (c = this->NextChar(ev)) != EOF && ev->Good() )
|
||||
{
|
||||
|
@ -1102,34 +1293,48 @@ morkParser::OnPortState(morkEnv* ev)
|
|||
break;
|
||||
|
||||
case '@': // group
|
||||
this->ReadGroup(ev);
|
||||
break;
|
||||
return this->ReadAt(ev, inInsideGroup);
|
||||
// break;
|
||||
|
||||
case '+': // plus
|
||||
mParser_Change = morkChange_kAdd;
|
||||
break;
|
||||
// case '+': // plus
|
||||
// mParser_Change = morkChange_kAdd;
|
||||
// break;
|
||||
|
||||
case '-': // minus
|
||||
mParser_Change = morkChange_kCut;
|
||||
break;
|
||||
// case '-': // minus
|
||||
// mParser_Change = morkChange_kCut;
|
||||
// break;
|
||||
|
||||
case '!': // bang
|
||||
mParser_Change = morkChange_kSet;
|
||||
break;
|
||||
// case '!': // bang
|
||||
// mParser_Change = morkChange_kSet;
|
||||
// break;
|
||||
|
||||
default:
|
||||
ev->NewWarning("unexpected byte in OnPortState()");
|
||||
ev->NewWarning("unexpected byte in ReadContent()");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ev->Bad() )
|
||||
mParser_State = morkParser_kBrokenState;
|
||||
else if ( c == EOF )
|
||||
mParser_State = morkParser_kDoneState;
|
||||
|
||||
return ( ev->Good() && c != EOF );
|
||||
}
|
||||
|
||||
void
|
||||
morkParser::OnPortState(morkEnv* ev)
|
||||
{
|
||||
mParser_InPort = morkBool_kTrue;
|
||||
this->OnNewPort(ev, *mParser_PortSpan.AsPlace());
|
||||
|
||||
while ( this->ReadContent(ev, /*inInsideGroup*/ morkBool_kFalse) )
|
||||
/* empty */;
|
||||
|
||||
mParser_InPort = morkBool_kFalse;
|
||||
this->OnPortEnd(ev, mParser_PortSpan);
|
||||
|
||||
if ( ev->Bad() )
|
||||
mParser_State = morkParser_kBrokenState;
|
||||
else if ( c == EOF )
|
||||
mParser_State = morkParser_kDoneState;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -383,9 +383,9 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
// mp:MetaTable ::= OnNewMeta mp:MetaItem* mp:Row OnMetaEnd
|
||||
// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd
|
||||
// mp:MetaItem ::= mp:Cell | OnMetaGlitch
|
||||
// mp:Row ::= OnNewRow mp:RowItem* OnRowEnd
|
||||
// mp:Row ::= OnMinusRow? OnNewRow mp:RowItem* OnRowEnd
|
||||
// mp:RowItem ::= mp:Cell | mp:Meta | OnRowGlitch
|
||||
// mp:Cell ::= OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
|
||||
// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
|
||||
|
||||
|
@ -409,7 +409,7 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange) = 0;
|
||||
const morkMid& inMid, mork_bool inCutAllRows) = 0;
|
||||
virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
|
@ -417,8 +417,9 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnMinusRow(morkEnv* ev) = 0;
|
||||
virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange) = 0;
|
||||
const morkMid& inMid, mork_bool inCutAllCols) = 0;
|
||||
virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
|
@ -431,8 +432,9 @@ public: // out virtual morkParser methods, data flow parser to subclass
|
|||
|
||||
virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
|
||||
virtual void OnMinusCell(morkEnv* ev) = 0;
|
||||
virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid* inMid, const morkBuf* inBuf, mork_change inChange) = 0;
|
||||
const morkMid* inMid, const morkBuf* inBuf) = 0;
|
||||
// Exactly one of inMid and inBuf is nil, and the other is non-nil.
|
||||
// When hex ID syntax is used for a column, then inMid is not nil, and
|
||||
// when a naked string names a column, then inBuf is not nil.
|
||||
|
@ -476,7 +478,11 @@ protected: // protected parser helper methods
|
|||
void ReadTable(morkEnv* ev);
|
||||
void ReadTableMeta(morkEnv* ev);
|
||||
void ReadDict(morkEnv* ev);
|
||||
mork_bool ReadContent(morkEnv* ev, mork_bool inInsideGroup);
|
||||
void ReadGroup(morkEnv* ev);
|
||||
mork_bool ReadEndGroupId(morkEnv* ev);
|
||||
mork_bool ReadAt(morkEnv* ev, mork_bool inInsideGroup);
|
||||
mork_bool FindGroupEnd(morkEnv* ev);
|
||||
void ReadMeta(morkEnv* ev, int inEndMeta);
|
||||
void ReadAlias(morkEnv* ev);
|
||||
mork_id ReadHex(morkEnv* ev, int* outNextChar);
|
||||
|
@ -487,8 +493,11 @@ protected: // protected parser helper methods
|
|||
mork_bool MatchPattern(morkEnv* ev, const char* inPattern);
|
||||
|
||||
void EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
void EndSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
void StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
|
||||
void StartSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
|
||||
int eat_line_break(morkEnv* ev, int inLast);
|
||||
int eat_line_continue(morkEnv* ev); // last char was '\\'
|
||||
int eat_comment(morkEnv* ev); // last char was '/'
|
||||
|
|
|
@ -66,43 +66,102 @@
|
|||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// notifications regarding row changes:
|
||||
|
||||
void morkRow::NoteRowAddCol(morkEnv* ev, mork_column inColumn)
|
||||
{
|
||||
if ( !this->IsRowRewrite() )
|
||||
{
|
||||
mork_delta newDelta;
|
||||
morkDelta_Init(newDelta, inColumn, morkChange_kAdd);
|
||||
|
||||
if ( newDelta != mRow_Delta ) // not repeating existing data?
|
||||
{
|
||||
if ( this->HasRowDelta() ) // already have one change recorded?
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
else
|
||||
this->SetRowDelta(inColumn, morkChange_kAdd);
|
||||
}
|
||||
}
|
||||
else
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
void morkRow::NoteRowCutCol(morkEnv* ev, mork_column inColumn)
|
||||
{
|
||||
if ( !this->IsRowRewrite() )
|
||||
{
|
||||
mork_delta newDelta;
|
||||
morkDelta_Init(newDelta, inColumn, morkChange_kCut);
|
||||
|
||||
if ( newDelta != mRow_Delta ) // not repeating existing data?
|
||||
{
|
||||
if ( this->HasRowDelta() ) // already have one change recorded?
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
else
|
||||
this->SetRowDelta(inColumn, morkChange_kCut);
|
||||
}
|
||||
}
|
||||
else
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
void morkRow::NoteRowSetCol(morkEnv* ev, mork_column inColumn)
|
||||
{
|
||||
if ( !this->IsRowRewrite() )
|
||||
{
|
||||
if ( this->HasRowDelta() ) // already have one change recorded?
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
else
|
||||
this->SetRowDelta(inColumn, morkChange_kSet);
|
||||
}
|
||||
else
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
void morkRow::NoteRowSetAll(morkEnv* ev)
|
||||
{
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
mork_u2
|
||||
morkRow::AddTableUse(morkEnv* ev)
|
||||
morkRow::AddRowGcUse(morkEnv* ev)
|
||||
{
|
||||
if ( this->IsRow() )
|
||||
{
|
||||
if ( mRow_TableUses < morkRow_kMaxTableUses ) // not already maxed out?
|
||||
++mRow_TableUses;
|
||||
if ( mRow_GcUses < morkRow_kMaxGcUses ) // not already maxed out?
|
||||
++mRow_GcUses;
|
||||
}
|
||||
else
|
||||
this->NonRowTypeError(ev);
|
||||
|
||||
return mRow_TableUses;
|
||||
return mRow_GcUses;
|
||||
}
|
||||
|
||||
mork_u2
|
||||
morkRow::CutTableUse(morkEnv* ev)
|
||||
morkRow::CutRowGcUse(morkEnv* ev)
|
||||
{
|
||||
if ( this->IsRow() )
|
||||
{
|
||||
if ( mRow_TableUses ) // any outstanding uses to cut?
|
||||
if ( mRow_GcUses ) // any outstanding uses to cut?
|
||||
{
|
||||
if ( mRow_TableUses < morkRow_kMaxTableUses ) // not frozen at max?
|
||||
--mRow_TableUses;
|
||||
if ( mRow_GcUses < morkRow_kMaxGcUses ) // not frozen at max?
|
||||
--mRow_GcUses;
|
||||
}
|
||||
else
|
||||
this->TableUsesUnderflowWarning(ev);
|
||||
this->GcUsesUnderflowWarning(ev);
|
||||
}
|
||||
else
|
||||
this->NonRowTypeError(ev);
|
||||
|
||||
return mRow_TableUses;
|
||||
return mRow_GcUses;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRow::TableUsesUnderflowWarning(morkEnv* ev)
|
||||
morkRow::GcUsesUnderflowWarning(morkEnv* ev)
|
||||
{
|
||||
ev->NewWarning("mRow_TableUses underflow");
|
||||
ev->NewWarning("mRow_GcUses underflow");
|
||||
}
|
||||
|
||||
|
||||
|
@ -155,12 +214,19 @@ morkRow::InitRow(morkEnv* ev, const mdbOid* inOid, morkRowSpace* ioSpace,
|
|||
mRow_Length = (mork_u2) inLength;
|
||||
mRow_Seed = (mork_u2) (mork_ip) this; // "random" assignment
|
||||
|
||||
mRow_TableUses = 0;
|
||||
mRow_Load = morkLoad_kClean;
|
||||
mRow_GcUses = 0;
|
||||
mRow_Pad = 0;
|
||||
mRow_Flags = 0;
|
||||
mRow_Tag = morkRow_kTag;
|
||||
|
||||
if ( inLength )
|
||||
mRow_Cells = ioPool->NewCells(ev, inLength);
|
||||
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() ) // new row might dirty store
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
}
|
||||
else
|
||||
ioSpace->MinusOneRidError(ev);
|
||||
|
@ -333,6 +399,28 @@ morkRow::TakeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength,
|
|||
}
|
||||
}
|
||||
|
||||
mork_bool morkRow::MaybeDirtySpaceStoreAndRow()
|
||||
{
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
if ( rowSpace )
|
||||
{
|
||||
morkStore* store = rowSpace->mSpace_Store;
|
||||
if ( store && store->mStore_CanDirty )
|
||||
{
|
||||
store->SetStoreDirty();
|
||||
rowSpace->mSpace_CanDirty = morkBool_kTrue;
|
||||
}
|
||||
|
||||
if ( rowSpace->mSpace_CanDirty )
|
||||
{
|
||||
this->SetRowDirty();
|
||||
rowSpace->SetRowSpaceDirty();
|
||||
return morkBool_kTrue;
|
||||
}
|
||||
}
|
||||
return morkBool_kFalse;
|
||||
}
|
||||
|
||||
morkCell*
|
||||
morkRow::NewCell(morkEnv* ev, mdb_column inColumn,
|
||||
mork_pos* outPos, morkStore* ioStore)
|
||||
|
@ -341,10 +429,21 @@ morkRow::NewCell(morkEnv* ev, mdb_column inColumn,
|
|||
mork_size length = (mork_size) mRow_Length;
|
||||
*outPos = (mork_pos) length;
|
||||
morkPool* pool = ioStore->StorePool();
|
||||
|
||||
mork_bool canDirty = this->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
if ( pool->AddRowCells(ev, this, length + 1) )
|
||||
{
|
||||
morkCell* cell = mRow_Cells + length;
|
||||
cell->SetColumnAndChange(inColumn, morkChange_kAdd);
|
||||
// next line equivalent to inline morkCell::SetCellDirty():
|
||||
if ( canDirty )
|
||||
cell->SetCellColumnDirty(inColumn);
|
||||
else
|
||||
cell->SetCellColumnClean(inColumn);
|
||||
|
||||
if ( canDirty && !this->IsRowRewrite() )
|
||||
this->NoteRowAddCol(ev, inColumn);
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
@ -432,6 +531,11 @@ morkRow::EmptyAllCells(morkEnv* ev)
|
|||
morkStore* store = this->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkPool* pool = store->StorePool();
|
||||
morkCell* end = cells + mRow_Length;
|
||||
--cells; // prepare for preincrement:
|
||||
|
@ -480,6 +584,11 @@ morkRow::CutAllColumns(morkEnv* ev)
|
|||
morkStore* store = this->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
if ( rowSpace->mRowSpace_IndexCount ) // any indexes?
|
||||
this->cut_all_index_entries(ev);
|
||||
|
@ -497,6 +606,11 @@ morkRow::SetRow(morkEnv* ev, const morkRow* inSourceRow)
|
|||
morkStore* srcStore = inSourceRow->GetRowSpaceStore(ev);
|
||||
if ( store && srcStore )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
mork_count indexes = rowSpace->mRowSpace_IndexCount; // any indexes?
|
||||
|
||||
|
@ -518,9 +632,13 @@ morkRow::SetRow(morkEnv* ev, const morkRow* inSourceRow)
|
|||
{
|
||||
morkAtom* atom = src->mCell_Atom;
|
||||
mork_column dstCol = src->GetColumn();
|
||||
// Note we modify the mCell_Atom slot directly instead of using
|
||||
// morkCell::SetAtom(), because we know it starts equal to nil.
|
||||
|
||||
if ( sameStore ) // source and dest in same store?
|
||||
{
|
||||
dst->SetColumnAndChange(dstCol, morkChange_kAdd);
|
||||
// next line equivalent to inline morkCell::SetCellDirty():
|
||||
dst->SetCellColumnDirty(dstCol);
|
||||
dst->mCell_Atom = atom;
|
||||
if ( atom ) // another ref to non-nil atom?
|
||||
atom->AddCellUse(ev);
|
||||
|
@ -530,7 +648,8 @@ morkRow::SetRow(morkEnv* ev, const morkRow* inSourceRow)
|
|||
dstCol = store->CopyToken(ev, dstCol, srcStore);
|
||||
if ( dstCol )
|
||||
{
|
||||
dst->SetColumnAndChange(dstCol, morkChange_kAdd);
|
||||
// next line equivalent to inline morkCell::SetCellDirty():
|
||||
dst->SetCellColumnDirty(dstCol);
|
||||
atom = store->CopyAtom(ev, atom);
|
||||
dst->mCell_Atom = atom;
|
||||
if ( atom ) // another ref?
|
||||
|
@ -565,19 +684,23 @@ morkRow::AddRow(morkEnv* ev, const morkRow* inSourceRow)
|
|||
}
|
||||
|
||||
void
|
||||
morkRow::OnZeroTableUse(morkEnv* ev)
|
||||
// OnZeroTableUse() is called when CutTableUse() returns zero.
|
||||
morkRow::OnZeroRowGcUse(morkEnv* ev)
|
||||
// OnZeroRowGcUse() is called when CutRowGcUse() returns zero.
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
// ev->NewWarning("need to implement OnZeroTableUse");
|
||||
// ev->NewWarning("need to implement OnZeroRowGcUse");
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::DirtyAllRowContent(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
this->SetRowDirty();
|
||||
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkCell* cells = mRow_Cells;
|
||||
if ( cells )
|
||||
{
|
||||
|
@ -624,6 +747,9 @@ void morkRow::CutColumn(morkEnv* ev, mdb_column inColumn)
|
|||
morkStore* store = this->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() && !this->IsRowRewrite() )
|
||||
this->NoteRowCutCol(ev, inColumn);
|
||||
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
|
||||
rowSpace->FindMap(ev, inColumn) : (morkAtomRowMap*) 0;
|
||||
|
@ -664,25 +790,6 @@ void morkRow::CutColumn(morkEnv* ev, mdb_column inColumn)
|
|||
}
|
||||
}
|
||||
|
||||
// void morkRow::cut_cell_from_space_index(morkEnv* ev, morkCell* ioCell)
|
||||
// {
|
||||
// morkAtom* oldAtom = ioCell->mCell_Atom;
|
||||
// if ( oldAtom )
|
||||
// {
|
||||
// mork_column col = ioCell->GetColumn();
|
||||
// morkRowSpace* rowSpace = mRow_Space;
|
||||
// morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
|
||||
// rowSpace->FindMap(ev, col) : (morkAtomRowMap*) 0;
|
||||
//
|
||||
// if ( map ) // col is indexed by row space?
|
||||
// {
|
||||
// mork_aid oldAid = oldAtom->GetBookAtomAid();
|
||||
// if ( oldAid ) // cut old row attribute from row index in space?
|
||||
// map->CutAid(ev, oldAid);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
void morkRow::AddColumn(morkEnv* ev, mdb_column inColumn,
|
||||
const mdbYarn* inYarn, morkStore* ioStore)
|
||||
{
|
||||
|
@ -690,16 +797,16 @@ void morkRow::AddColumn(morkEnv* ev, mdb_column inColumn,
|
|||
{
|
||||
mork_pos pos = -1;
|
||||
morkCell* cell = this->GetCell(ev, inColumn, &pos);
|
||||
morkCell* oldCell = cell; // need to know later whether new
|
||||
if ( !cell ) // column does not yet exist?
|
||||
cell = this->NewCell(ev, inColumn, &pos, ioStore);
|
||||
else
|
||||
++mRow_Seed;
|
||||
|
||||
if ( cell )
|
||||
{
|
||||
// cell->SetYarn(ev, inYarn, ioStore);
|
||||
morkAtom* oldAtom = cell->mCell_Atom;
|
||||
|
||||
morkAtom* atom = ioStore->YarnToAtom(ev, inYarn);
|
||||
if ( atom )
|
||||
if ( atom && atom != oldAtom )
|
||||
{
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
|
||||
|
@ -707,7 +814,6 @@ void morkRow::AddColumn(morkEnv* ev, mdb_column inColumn,
|
|||
|
||||
if ( map ) // inColumn is indexed by row space?
|
||||
{
|
||||
morkAtom* oldAtom = cell->mCell_Atom;
|
||||
if ( oldAtom && oldAtom != atom ) // cut old cell from index?
|
||||
{
|
||||
mork_aid oldAid = oldAtom->GetBookAtomAid();
|
||||
|
@ -718,6 +824,13 @@ void morkRow::AddColumn(morkEnv* ev, mdb_column inColumn,
|
|||
|
||||
cell->SetAtom(ev, atom, ioStore->StorePool()); // refcounts atom
|
||||
|
||||
if ( oldCell ) // we changed a pre-existing cell in the row?
|
||||
{
|
||||
++mRow_Seed;
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() && !this->IsRowRewrite() )
|
||||
this->NoteRowAddCol(ev, inColumn);
|
||||
}
|
||||
|
||||
if ( map ) // inColumn is indexed by row space?
|
||||
{
|
||||
mork_aid newAid = atom->GetBookAtomAid();
|
||||
|
|
|
@ -23,18 +23,25 @@
|
|||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCELL_
|
||||
#include "morkCell.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class nsIMdbRow;
|
||||
class nsIMdbCell;
|
||||
#define morkDerived_kRow /*i*/ 0x5277 /* ascii 'Rw' */
|
||||
|
||||
#define morkRow_kMaxTableUses 0x0FFFF /* max for 16-bit unsigned int */
|
||||
#define morkRow_kMaxGcUses 0x0FF /* max for 8-bit unsigned int */
|
||||
#define morkRow_kMaxLength 0x0FFFF /* max for 16-bit unsigned int */
|
||||
#define morkRow_kMinusOneRid ((mork_rid) -1)
|
||||
|
||||
#define morkRow_kTag 'r' /* magic signature for mRow_Tag */
|
||||
|
||||
#define morkRow_kNotedBit ((mork_u1) (1 << 0)) /* space has change notes */
|
||||
#define morkRow_kRewriteBit ((mork_u1) (1 << 1)) /* must rewrite all cells */
|
||||
#define morkRow_kDirtyBit ((mork_u1) (1 << 2)) /* row has been changed */
|
||||
|
||||
class morkRow { // row of cells
|
||||
|
||||
|
@ -44,13 +51,57 @@ public: // state is public because the entire Mork system is private
|
|||
morkCell* mRow_Cells;
|
||||
mdbOid mRow_Oid;
|
||||
|
||||
mork_delta mRow_Delta; // space to note a single column change
|
||||
|
||||
mork_u2 mRow_Length; // physical count of cells in mRow_Cells
|
||||
mork_u2 mRow_Seed; // count changes in mRow_Cells structure
|
||||
|
||||
mork_u2 mRow_TableUses; // persistent references from tables
|
||||
mork_load mRow_Load; // is this row clean or dirty?
|
||||
mork_u1 mRow_GcUses; // persistent references from tables
|
||||
mork_u1 mRow_Pad; // for u1 alignment
|
||||
mork_u1 mRow_Flags; // one-byte flags slot
|
||||
mork_u1 mRow_Tag; // one-byte tag (need u4 alignment pad)
|
||||
|
||||
public: // interpreting mRow_Delta
|
||||
|
||||
mork_bool HasRowDelta() const { return ( mRow_Delta != 0 ); }
|
||||
|
||||
void ClearRowDelta() { mRow_Delta = 0; }
|
||||
|
||||
void SetRowDelta(mork_column inCol, mork_change inChange)
|
||||
{ morkDelta_Init(mRow_Delta, inCol, inChange); }
|
||||
|
||||
mork_column GetDeltaColumn() const { return morkDelta_Column(mRow_Delta); }
|
||||
mork_change GetDeltaChange() const { return morkDelta_Change(mRow_Delta); }
|
||||
|
||||
public: // noting row changes
|
||||
|
||||
void NoteRowSetAll(morkEnv* ev);
|
||||
void NoteRowSetCol(morkEnv* ev, mork_column inCol);
|
||||
void NoteRowAddCol(morkEnv* ev, mork_column inCol);
|
||||
void NoteRowCutCol(morkEnv* ev, mork_column inCol);
|
||||
|
||||
public: // flags bit twiddling
|
||||
|
||||
void SetRowNoted() { mRow_Flags |= morkRow_kNotedBit; }
|
||||
void SetRowRewrite() { mRow_Flags |= morkRow_kRewriteBit; }
|
||||
void SetRowDirty() { mRow_Flags |= morkRow_kDirtyBit; }
|
||||
|
||||
void ClearRowNoted() { mRow_Flags &= (mork_u1) ~morkRow_kNotedBit; }
|
||||
void ClearRowRewrite() { mRow_Flags &= (mork_u1) ~morkRow_kRewriteBit; }
|
||||
void SetRowClean() { mRow_Flags = 0; mRow_Delta = 0; }
|
||||
|
||||
mork_bool IsRowNoted() const
|
||||
{ return ( mRow_Flags & morkRow_kNotedBit ) != 0; }
|
||||
|
||||
mork_bool IsRowRewrite() const
|
||||
{ return ( mRow_Flags & morkRow_kRewriteBit ) != 0; }
|
||||
|
||||
mork_bool IsRowClean() const
|
||||
{ return ( mRow_Flags & morkRow_kDirtyBit ) == 0; }
|
||||
|
||||
mork_bool IsRowDirty() const
|
||||
{ return ( mRow_Flags & morkRow_kDirtyBit ) != 0; }
|
||||
|
||||
public: // other row methods
|
||||
morkRow( ) { }
|
||||
morkRow(const mdbOid* inOid) :mRow_Oid(*inOid) { }
|
||||
|
@ -63,14 +114,11 @@ public: // other row methods
|
|||
nsIMdbCell* AcquireCellHandle(morkEnv* ev, morkCell* ioCell,
|
||||
mdb_column inColumn, mork_pos inPos);
|
||||
|
||||
mork_u2 AddTableUse(morkEnv* ev);
|
||||
mork_u2 CutTableUse(morkEnv* ev);
|
||||
mork_u2 AddRowGcUse(morkEnv* ev);
|
||||
mork_u2 CutRowGcUse(morkEnv* ev);
|
||||
|
||||
void SetRowClean() { mRow_Load = morkLoad_kClean; }
|
||||
void SetRowDirty() { mRow_Load = morkLoad_kDirty; }
|
||||
|
||||
mork_bool IsRowClean() const { return mRow_Load == morkLoad_kClean; }
|
||||
mork_bool IsRowDirty() const { return mRow_Load == morkLoad_kDirty; }
|
||||
mork_bool MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
public: // internal row methods
|
||||
|
||||
|
@ -129,8 +177,8 @@ public: // external row methods
|
|||
void SetRow(morkEnv* ev, const morkRow* inSourceRow);
|
||||
void CutAllColumns(morkEnv* ev);
|
||||
|
||||
void OnZeroTableUse(morkEnv* ev);
|
||||
// OnZeroTableUse() is called when CutTableUse() returns zero.
|
||||
void OnZeroRowGcUse(morkEnv* ev);
|
||||
// OnZeroRowGcUse() is called when CutRowGcUse() returns zero.
|
||||
|
||||
public: // dynamic typing
|
||||
|
||||
|
@ -167,7 +215,7 @@ public: // errors
|
|||
static void NilCellsError(morkEnv* ev);
|
||||
static void NonRowTypeError(morkEnv* ev);
|
||||
static void NonRowTypeWarning(morkEnv* ev);
|
||||
static void TableUsesUnderflowWarning(morkEnv* ev);
|
||||
static void GcUsesUnderflowWarning(morkEnv* ev);
|
||||
|
||||
private: // copying is not allowed
|
||||
morkRow(const morkRow& other);
|
||||
|
|
|
@ -82,6 +82,15 @@ public: // other map methods
|
|||
// GetRow() returns the row equal to ioRow, or else nil
|
||||
|
||||
// note the rows are owned elsewhere, usuall by morkRowSpace
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakRowMap(morkMap* me,
|
||||
morkEnv* ev, morkRowMap** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongRowMap(morkMap* me,
|
||||
morkEnv* ev, morkRowMap** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
class morkRowMapIter: public morkMapIter{ // typesafe wrapper class
|
||||
|
|
|
@ -122,6 +122,8 @@ morkRowSpace::morkRowSpace(morkEnv* ev,
|
|||
if ( ioSlotHeap )
|
||||
{
|
||||
mNode_Derived = morkDerived_kRowSpace;
|
||||
|
||||
// the morkSpace base constructor handles any dirty propagation
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
@ -207,6 +209,9 @@ morkRowSpace::MinusOneRidError(morkEnv* ev)
|
|||
mork_num
|
||||
morkRowSpace::CutAllRows(morkEnv* ev, morkPool* ioPool)
|
||||
{
|
||||
if ( this->IsRowSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
|
||||
mork_num outSlots = mRowSpace_Rows.mMap_Fill;
|
||||
morkRow* r = 0; // old key row in the map
|
||||
|
||||
|
@ -268,13 +273,14 @@ morkRowSpace::NewTableWithTid(morkEnv* ev, mork_tid inTid,
|
|||
const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
|
||||
{
|
||||
morkTable* outTable = 0;
|
||||
morkStore* store = mSpace_Store;
|
||||
|
||||
if ( inTableKind )
|
||||
if ( inTableKind && store )
|
||||
{
|
||||
mdb_bool mustBeUnique = morkBool_kFalse;
|
||||
nsIMdbHeap* heap = mSpace_Store->mPort_Heap;
|
||||
nsIMdbHeap* heap = store->mPort_Heap;
|
||||
morkTable* table = new(*heap, ev)
|
||||
morkTable(ev, morkUsage::kHeap, heap, mSpace_Store, heap, this,
|
||||
morkTable(ev, morkUsage::kHeap, heap, store, heap, this,
|
||||
inOptionalMetaRowOid, inTid, inTableKind, mustBeUnique);
|
||||
if ( table )
|
||||
{
|
||||
|
@ -284,11 +290,17 @@ morkRowSpace::NewTableWithTid(morkEnv* ev, mork_tid inTid,
|
|||
if ( mRowSpace_NextTableId <= inTid )
|
||||
mRowSpace_NextTableId = inTid + 1;
|
||||
}
|
||||
table->CutStrongRef(ev);
|
||||
table->CutStrongRef(ev); // always cut ref; AddTable() adds its own
|
||||
|
||||
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
|
||||
this->MaybeDirtyStoreAndSpace(); // morkTable does already
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ( store )
|
||||
this->ZeroKindError(ev);
|
||||
else
|
||||
this->NilSpaceStoreError(ev);
|
||||
|
||||
return outTable;
|
||||
}
|
||||
|
@ -299,8 +311,9 @@ morkRowSpace::NewTable(morkEnv* ev, mork_kind inTableKind,
|
|||
const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
|
||||
{
|
||||
morkTable* outTable = 0;
|
||||
morkStore* store = mSpace_Store;
|
||||
|
||||
if ( inTableKind )
|
||||
if ( inTableKind && store )
|
||||
{
|
||||
if ( inMustBeUnique ) // need to look for existing table first?
|
||||
outTable = this->FindTableByKind(ev, inTableKind);
|
||||
|
@ -320,12 +333,17 @@ morkRowSpace::NewTable(morkEnv* ev, mork_kind inTableKind,
|
|||
outTable = table;
|
||||
else
|
||||
table->CutStrongRef(ev);
|
||||
|
||||
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
|
||||
this->MaybeDirtyStoreAndSpace(); // morkTable does already
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ( store )
|
||||
this->ZeroKindError(ev);
|
||||
else
|
||||
this->NilSpaceStoreError(ev);
|
||||
|
||||
return outTable;
|
||||
}
|
||||
|
@ -514,6 +532,9 @@ 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);
|
||||
|
@ -530,8 +551,14 @@ morkRowSpace::NewRowWithOid(morkEnv* ev, const mdbOid* inOid)
|
|||
}
|
||||
else
|
||||
pool->ZapRow(ev, row);
|
||||
|
||||
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
|
||||
this->MaybeDirtyStoreAndSpace(); // InitRow() does already
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilSpaceStoreError(ev);
|
||||
}
|
||||
return outRow;
|
||||
}
|
||||
|
||||
|
@ -543,6 +570,9 @@ morkRowSpace::NewRow(morkEnv* ev)
|
|||
{
|
||||
mork_rid id = this->MakeNewRowId(ev);
|
||||
if ( id )
|
||||
{
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( store )
|
||||
{
|
||||
mdbOid oid;
|
||||
oid.mOid_Scope = mSpace_Scope;
|
||||
|
@ -557,12 +587,19 @@ morkRowSpace::NewRow(morkEnv* ev)
|
|||
outRow = row;
|
||||
else
|
||||
pool->ZapRow(ev, row);
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -47,6 +47,10 @@
|
|||
#include "morkArray.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kRowSpace /*i*/ 0x7253 /* ascii 'rS' */
|
||||
|
@ -98,6 +102,15 @@ public: // state is public because the entire Mork system is private
|
|||
// every nonzero slot in IndexCache is a strong ref to a morkAtomRowMap:
|
||||
morkAtomRowMap* mRowSpace_IndexCache[ morkRowSpace_kPrimeCacheSize ];
|
||||
|
||||
morkDeque mRowSpace_TablesByPriority[ morkPriority_kCount ];
|
||||
|
||||
public: // more specific dirty methods for row space:
|
||||
void SetRowSpaceDirty() { this->SetNodeDirty(); }
|
||||
void SetRowSpaceClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsRowSpaceClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsRowSpaceDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseRowSpace() only if open
|
||||
|
|
|
@ -91,12 +91,18 @@ morkSpace::morkSpace(morkEnv* ev,
|
|||
, mSpace_Scope( inScope )
|
||||
, mSpace_DoAutoIDs( morkBool_kFalse )
|
||||
, mSpace_HaveDoneAutoIDs( morkBool_kFalse )
|
||||
, mSpace_CanDirty( morkBool_kFalse ) // only when store can be dirtied
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioStore && ioSlotHeap )
|
||||
{
|
||||
morkStore::SlotWeakStore(ioStore, ev, &mSpace_Store);
|
||||
|
||||
mSpace_CanDirty = ioStore->mStore_CanDirty;
|
||||
if ( mSpace_CanDirty ) // this new space dirties the store?
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kSpace;
|
||||
}
|
||||
|
@ -132,10 +138,34 @@ morkSpace::NonAsciiSpaceScopeName(morkEnv* ev)
|
|||
ev->NewError("mSpace_Scope > 0x7F");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkSpace::NilSpaceStoreError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mSpace_Store");
|
||||
}
|
||||
|
||||
morkPool* morkSpace::GetSpaceStorePool() const
|
||||
{
|
||||
return &mSpace_Store->mStore_Pool;
|
||||
}
|
||||
|
||||
mork_bool morkSpace::MaybeDirtyStoreAndSpace()
|
||||
{
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( store && store->mStore_CanDirty )
|
||||
{
|
||||
store->SetStoreDirty();
|
||||
mSpace_CanDirty = morkBool_kTrue;
|
||||
}
|
||||
|
||||
if ( mSpace_CanDirty )
|
||||
{
|
||||
this->SetSpaceDirty();
|
||||
return morkBool_kTrue;
|
||||
}
|
||||
|
||||
return morkBool_kFalse;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
|
|
@ -62,7 +62,15 @@ public: // state is public because the entire Mork system is private
|
|||
|
||||
mork_bool mSpace_DoAutoIDs; // whether db should assign member IDs
|
||||
mork_bool mSpace_HaveDoneAutoIDs; // whether actually auto assigned IDs
|
||||
mork_u1 mSpace_Pad[ 2 ]; // pad to u4 alignment
|
||||
mork_bool mSpace_CanDirty; // changes imply the store becomes dirty?
|
||||
mork_u1 mSpace_Pad; // pad to u4 alignment
|
||||
|
||||
public: // more specific dirty methods for space:
|
||||
void SetSpaceDirty() { this->SetNodeDirty(); }
|
||||
void SetSpaceClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsSpaceClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsSpaceDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
|
@ -84,7 +92,10 @@ public: // dynamic type identification
|
|||
|
||||
public: // other space methods
|
||||
|
||||
mork_bool MaybeDirtyStoreAndSpace();
|
||||
|
||||
static void NonAsciiSpaceScopeName(morkEnv* ev);
|
||||
static void NilSpaceStoreError(morkEnv* ev);
|
||||
|
||||
morkPool* GetSpaceStorePool() const;
|
||||
|
||||
|
|
|
@ -222,9 +222,15 @@ morkStore::morkStore(morkEnv* ev, const morkUsage& inUsage,
|
|||
, mStore_AtomSpaces(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
|
||||
, mStore_Pool(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioPortHeap)
|
||||
|
||||
, mStore_CommitGroupIdentity( 0 )
|
||||
|
||||
, mStore_FirstCommitGroupPos( 0 )
|
||||
, mStore_SecondCommitGroupPos( 0 )
|
||||
|
||||
// disable auto-assignment of atom IDs until someone knows it is okay:
|
||||
, mStore_CanAutoAssignAtomIdentity( morkBool_kFalse )
|
||||
|
||||
, mStore_CanDirty( morkBool_kFalse ) // not until the store is open
|
||||
, mStore_CanWriteIncremental( morkBool_kTrue ) // always with few exceptions
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
|
@ -271,6 +277,82 @@ morkStore::CloseStore(morkEnv* ev) // called by CloseMorkNode();
|
|||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
mork_percent morkStore::PercentOfStoreWasted(morkEnv* ev)
|
||||
{
|
||||
mork_percent outPercent = 0;
|
||||
morkFile* 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 = file->Length(ev); // 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)
|
||||
{
|
||||
|
@ -386,6 +468,8 @@ morkAtomSpace* morkStore::LazyGetGroundAtomSpace(morkEnv* ev)
|
|||
|
||||
if ( space ) // successful space creation?
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
|
||||
mStore_GroundAtomSpace = space; // transfer strong ref to this slot
|
||||
mStore_AtomSpaces.AddAtomSpace(ev, space);
|
||||
}
|
||||
|
@ -404,6 +488,8 @@ morkAtomSpace* morkStore::LazyGetGroundColumnSpace(morkEnv* ev)
|
|||
|
||||
if ( space ) // successful space creation?
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
|
||||
mStore_GroundColumnSpace = space; // transfer strong ref to this slot
|
||||
mStore_AtomSpaces.AddAtomSpace(ev, space);
|
||||
}
|
||||
|
@ -423,6 +509,7 @@ morkStream* morkStore::LazyGetInStream(morkEnv* ev)
|
|||
morkStore_kStreamBufSize, /*frozen*/ morkBool_kTrue);
|
||||
if ( stream )
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
mStore_InStream = stream; // transfer strong ref to this slot
|
||||
}
|
||||
}
|
||||
|
@ -444,6 +531,7 @@ morkStream* morkStore::LazyGetOutStream(morkEnv* ev)
|
|||
morkStore_kStreamBufSize, /*frozen*/ morkBool_kFalse);
|
||||
if ( stream )
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
mStore_InStream = stream; // transfer strong ref to this slot
|
||||
}
|
||||
}
|
||||
|
@ -494,6 +582,8 @@ morkStore::LazyGetRowSpace(morkEnv* ev, mdb_scope inRowScope)
|
|||
|
||||
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
|
||||
|
@ -521,6 +611,8 @@ morkStore::LazyGetAtomSpace(morkEnv* ev, mdb_scope inAtomScope)
|
|||
|
||||
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
|
||||
|
@ -622,8 +714,11 @@ morkStore::YarnToAtom(morkEnv* ev, const mdbYarn* inYarn)
|
|||
morkAtomBodyMap* map = &groundSpace->mAtomSpace_AtomBodies;
|
||||
outAtom = map->GetAtom(ev, keyAtom);
|
||||
if ( !outAtom )
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
outAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
|
||||
}
|
||||
}
|
||||
else if ( ev->Good() )
|
||||
{
|
||||
morkBuf buf(inYarn->mYarn_Buf, inYarn->mYarn_Fill);
|
||||
|
@ -666,6 +761,7 @@ morkStore::MidToOid(morkEnv* ev, const morkMid& inMid, mdbOid* outOid)
|
|||
outOid->mOid_Scope = bookAtom->mBookAtom_Id;
|
||||
else
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
|
||||
if ( bookAtom )
|
||||
{
|
||||
|
@ -856,6 +952,7 @@ morkStore::AddAlias(morkEnv* ev, const morkMid& inMid, mork_cscode inForm)
|
|||
}
|
||||
else
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
keyAtom->mBookAtom_Id = oid->mOid_Id;
|
||||
outAtom = atomSpace->MakeBookAtomCopyWithAid(ev,
|
||||
*keyAtom, (mork_aid) oid->mOid_Id);
|
||||
|
@ -936,6 +1033,7 @@ morkStore::BufToToken(morkEnv* ev, const morkBuf* inBuf)
|
|||
outToken = bookAtom->mBookAtom_Id;
|
||||
else
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
bookAtom = space->MakeBookAtomCopy(ev, *keyAtom);
|
||||
if ( bookAtom )
|
||||
{
|
||||
|
@ -977,6 +1075,7 @@ morkStore::StringToToken(morkEnv* ev, const char* inTokenName)
|
|||
outToken = bookAtom->mBookAtom_Id;
|
||||
else
|
||||
{
|
||||
this->MaybeDirtyStore();
|
||||
bookAtom = groundSpace->MakeBookAtomCopy(ev, *keyAtom);
|
||||
if ( bookAtom )
|
||||
{
|
||||
|
@ -1061,7 +1160,7 @@ morkStore::GetTableKind(morkEnv* ev, mdb_scope inRowScope,
|
|||
if ( outTableCount )
|
||||
*outTableCount = outTable->GetRowCount();
|
||||
if ( outMustBeUnique )
|
||||
*outMustBeUnique = outTable->mTable_MustBeUnique;
|
||||
*outMustBeUnique = outTable->IsTableUnique();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,6 +127,7 @@ public: // typesafe refcounting inlines calling inherited morkNode methods
|
|||
#define morkStore_kRowScopeColumn ((mork_column) 'r')
|
||||
#define morkStore_kMetaScope ((mork_scope) 'm')
|
||||
#define morkStore_kKindColumn ((mork_column) 'k')
|
||||
#define morkStore_kStatusColumn ((mork_column) 's')
|
||||
|
||||
/*| morkStore:
|
||||
|*/
|
||||
|
@ -168,13 +169,66 @@ public: // state is public because the entire Mork system is private
|
|||
// we alloc a max size book atom to reuse space for atom map key searches:
|
||||
morkMaxBookAtom mStore_BookAtom; // staging area for atom map searches
|
||||
|
||||
// GroupIdentity should be one more than largest seen in a parsed db file:
|
||||
mork_gid mStore_CommitGroupIdentity; // transaction ID number
|
||||
|
||||
// group positions are used to help compute PercentOfStoreWasted():
|
||||
mork_pos mStore_FirstCommitGroupPos; // start of first group
|
||||
mork_pos mStore_SecondCommitGroupPos; // start of second group
|
||||
// If the first commit group is very near the start of the file (say less
|
||||
// than 512 bytes), then we might assume the file started nearly empty and
|
||||
// that most of the first group is not wasted. In that case, the pos of
|
||||
// the second commit group might make a better estimate of the start of
|
||||
// transaction space that might represent wasted file space. That's why
|
||||
// we support fields for both first and second commit group positions.
|
||||
//
|
||||
// We assume that a zero in either group pos means that the slot has not
|
||||
// yet been given a valid value, since the file will always start with a
|
||||
// tag, and a commit group cannot actually start at position zero.
|
||||
//
|
||||
// Either or both the first or second commit group positions might be
|
||||
// supplied by either morkWriter (while committing) or morkBuilder (while
|
||||
// parsing), since either reading or writing the file might encounter the
|
||||
// first transaction groups which came into existence either in the past
|
||||
// or in the very recent present.
|
||||
|
||||
mork_bool mStore_CanAutoAssignAtomIdentity;
|
||||
mork_u1 mStore_Pad[ 3 ]; // for u4 alignment
|
||||
mork_bool mStore_CanDirty; // changes imply the store becomes dirty?
|
||||
mork_u1 mStore_CanWriteIncremental; // compress not required?
|
||||
mork_u1 mStore_Pad; // for u4 alignment
|
||||
|
||||
public: // coping with any changes to store token slots above:
|
||||
// mStore_CanDirty should be FALSE when parsing a file while building the
|
||||
// content going into the store, because such data structure modifications
|
||||
// are actuallly in sync with the file. So content read from a file must
|
||||
// be clean with respect to the file. After a file is finished parsing,
|
||||
// the mStore_CanDirty slot should become TRUE, so that any additional
|
||||
// changes at runtime cause structures to be marked dirty with respect to
|
||||
// the file which must later be updated with changes during a commit.
|
||||
//
|
||||
// It might also make sense to set mStore_CanDirty to FALSE while a commit
|
||||
// is in progress, lest some internal transformations make more content
|
||||
// appear dirty when it should not. So anyone modifying content during a
|
||||
// commit should think about the intended significance regarding dirty.
|
||||
|
||||
// void SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom,
|
||||
// const mdbOid* inOid);
|
||||
public: // more specific dirty methods for store:
|
||||
void SetStoreDirty() { this->SetNodeDirty(); }
|
||||
void SetStoreClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsStoreClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsStoreDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
public: // setting dirty based on CanDirty:
|
||||
|
||||
void MaybeDirtyStore()
|
||||
{ if ( mStore_CanDirty ) this->SetStoreDirty(); }
|
||||
|
||||
public: // space waste analysis
|
||||
|
||||
mork_percent PercentOfStoreWasted(morkEnv* ev);
|
||||
|
||||
public: // setting store and all subspaces canDirty:
|
||||
|
||||
void SetStoreAndAllSpacesCanDirty(morkEnv* ev, mork_bool inCanDirty);
|
||||
|
||||
public: // building an atom inside mStore_BookAtom from a char* string
|
||||
|
||||
|
|
|
@ -92,6 +92,8 @@ morkStream::morkStream(morkEnv* ev, const morkUsage& inUsage,
|
|||
if ( ioContentFile->FileFrozen() ) // forced to be readonly?
|
||||
inFrozen = morkBool_kTrue; // override the input value
|
||||
|
||||
mork_pos fileEnd = ioContentFile->Length(ev);
|
||||
|
||||
morkFile::SlotStrongFile(ioContentFile, ev, &mStream_ContentFile);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
|
@ -355,6 +357,22 @@ morkStream::PutLineBreak(morkEnv* ev)
|
|||
// public: // virtual morkFile methods
|
||||
|
||||
|
||||
/*public virtual*/ void
|
||||
morkStream::Steal(morkEnv* ev, nsIMdbFile* ioThief)
|
||||
// Steal: tell this file to close any associated i/o stream in the file
|
||||
// system, because the file ioThief intends to reopen the file in order
|
||||
// to provide the MDB implementation with more exotic file access than is
|
||||
// offered by the nsIMdbFile alone. Presumably the thief knows enough
|
||||
// from Path() in order to know which file to reopen. If Steal() is
|
||||
// successful, this file should probably delegate all future calls to
|
||||
// the nsIMdbFile interface down to the thief files, so that even after
|
||||
// the file has been stolen, it can still be read, written, or forcibly
|
||||
// closed (by a call to CloseMdbObject()).
|
||||
{
|
||||
MORK_USED_1(ioThief);
|
||||
ev->StubMethodOnlyError();
|
||||
}
|
||||
|
||||
/*public virtual*/ void
|
||||
morkStream::BecomeTrunk(morkEnv* ev)
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
|
|
|
@ -116,6 +116,17 @@ public: // typing
|
|||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // virtual morkFile methods
|
||||
|
||||
virtual void Steal(morkEnv* ev, nsIMdbFile* ioThief);
|
||||
// Steal: tell this file to close any associated i/o stream in the file
|
||||
// system, because the file ioThief intends to reopen the file in order
|
||||
// to provide the MDB implementation with more exotic file access than is
|
||||
// offered by the nsIMdbFile alone. Presumably the thief knows enough
|
||||
// from Path() in order to know which file to reopen. If Steal() is
|
||||
// successful, this file should probably delegate all future calls to
|
||||
// the nsIMdbFile interface down to the thief files, so that even after
|
||||
// the file has been stolen, it can still be read, written, or forcibly
|
||||
// closed (by a call to CloseMdbObject()).
|
||||
|
||||
virtual void BecomeTrunk(morkEnv* ev);
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
|
|
|
@ -99,22 +99,35 @@ morkTable::morkTable(morkEnv* ev, /*i*/
|
|||
, mTable_RowSpace( 0 )
|
||||
, mTable_MetaRow( 0 )
|
||||
|
||||
, mTable_RowMap(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap,
|
||||
morkTable_kStartRowMapSlotCount)
|
||||
, mTable_RowMap( 0 )
|
||||
// , mTable_RowMap(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap,
|
||||
// morkTable_kStartRowMapSlotCount)
|
||||
, mTable_RowArray(ev, morkUsage::kMember, (nsIMdbHeap*) 0,
|
||||
morkTable_kStartRowArraySize, ioSlotHeap)
|
||||
|
||||
, mTable_ChangeList()
|
||||
, mTable_ChangesCount( 0 )
|
||||
, mTable_ChangesMax( 3 ) // any very small number greater than zero
|
||||
|
||||
, mTable_Id( inTid )
|
||||
, mTable_Kind( inKind )
|
||||
, mTable_MustBeUnique( inMustBeUnique )
|
||||
, mTable_CellUses( 0 )
|
||||
|
||||
, mTable_Flags( 0 )
|
||||
, mTable_Priority( morkPriority_kLo ) // NOT high priority
|
||||
, mTable_GcUses( 0 )
|
||||
, mTable_Pad( 0 )
|
||||
{
|
||||
this->mLink_Next = 0;
|
||||
this->mLink_Prev = 0;
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioStore && ioSlotHeap && ioRowSpace )
|
||||
{
|
||||
if ( inKind )
|
||||
{
|
||||
if ( inMustBeUnique )
|
||||
this->SetTableUnique();
|
||||
morkStore::SlotWeakStore(ioStore, ev, &mTable_Store);
|
||||
morkRowSpace::SlotWeakRowSpace(ioRowSpace, ev, &mTable_RowSpace);
|
||||
if ( inOptionalMetaRowOid )
|
||||
|
@ -125,8 +138,14 @@ morkTable::morkTable(morkEnv* ev, /*i*/
|
|||
mTable_MetaRowOid.mOid_Id = morkRow_kMinusOneRid;
|
||||
}
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndTable() )
|
||||
this->SetTableRewrite(); // everything is dirty
|
||||
|
||||
mNode_Derived = morkDerived_kTable;
|
||||
}
|
||||
this->MaybeDirtySpaceStoreAndTable(); // new table might dirty store
|
||||
}
|
||||
else
|
||||
ioRowSpace->ZeroKindError(ev);
|
||||
}
|
||||
|
@ -142,7 +161,8 @@ morkTable::CloseTable(morkEnv* ev) /*i*/ // called by CloseMorkNode();
|
|||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mTable_RowMap.CloseMorkNode(ev);
|
||||
morkRowMap::SlotStrongRowMap((morkRowMap*) 0, ev, &mTable_RowMap);
|
||||
// mTable_RowMap.CloseMorkNode(ev);
|
||||
mTable_RowArray.CloseMorkNode(ev);
|
||||
morkStore::SlotWeakStore((morkStore*) 0, ev, &mTable_Store);
|
||||
morkRowSpace::SlotWeakRowSpace((morkRowSpace*) 0,
|
||||
|
@ -160,33 +180,106 @@ morkTable::CloseTable(morkEnv* ev) /*i*/ // called by CloseMorkNode();
|
|||
// ````` ````` ````` ````` `````
|
||||
|
||||
mork_u2
|
||||
morkTable::AddCellUse(morkEnv* ev)
|
||||
morkTable::AddTableGcUse(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
if ( mTable_CellUses < morkTable_kMaxCellUses ) // not already maxed out?
|
||||
++mTable_CellUses;
|
||||
if ( mTable_GcUses < morkTable_kMaxTableGcUses ) // not already maxed out?
|
||||
++mTable_GcUses;
|
||||
|
||||
return mTable_CellUses;
|
||||
return mTable_GcUses;
|
||||
}
|
||||
|
||||
mork_u2
|
||||
morkTable::CutCellUse(morkEnv* ev)
|
||||
morkTable::CutTableGcUse(morkEnv* ev)
|
||||
{
|
||||
if ( mTable_CellUses ) // any outstanding uses to cut?
|
||||
if ( mTable_GcUses ) // any outstanding uses to cut?
|
||||
{
|
||||
if ( mTable_CellUses < morkTable_kMaxCellUses ) // not frozen at max?
|
||||
--mTable_CellUses;
|
||||
if ( mTable_GcUses < morkTable_kMaxTableGcUses ) // not frozen at max?
|
||||
--mTable_GcUses;
|
||||
}
|
||||
else
|
||||
this->CellUsesUnderflowWarning(ev);
|
||||
this->TableGcUsesUnderflowWarning(ev);
|
||||
|
||||
return mTable_CellUses;
|
||||
return mTable_GcUses;
|
||||
}
|
||||
|
||||
// table dirty handling more complex thatn morkNode::SetNodeDirty() etc.
|
||||
|
||||
void morkTable::SetTableClean(morkEnv* ev)
|
||||
{
|
||||
nsIMdbHeap* heap = mTable_Store->mPort_Heap;
|
||||
mTable_ChangeList.CutAndZapAllListMembers(ev, heap); // forget changes
|
||||
mTable_ChangesCount = 0;
|
||||
|
||||
mTable_Flags = 0;
|
||||
this->SetNodeClean();
|
||||
}
|
||||
|
||||
// notifications regarding table changes:
|
||||
|
||||
void morkTable::NoteTableMoveRow(morkEnv* ev, morkRow* ioRow, mork_pos inPos)
|
||||
{
|
||||
nsIMdbHeap* heap = mTable_Store->mPort_Heap;
|
||||
if ( this->IsTableRewrite() || this->HasChangeOverflow() )
|
||||
this->NoteTableSetAll(ev);
|
||||
else
|
||||
{
|
||||
morkTableChange* tableChange = new(*heap, ev)
|
||||
morkTableChange(ev, ioRow, inPos);
|
||||
if ( tableChange )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mTable_ChangeList.PushTail(tableChange);
|
||||
++mTable_ChangesCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
tableChange->ZapOldNext(ev, heap);
|
||||
this->SetTableRewrite(); // just plan to write all table rows
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void morkTable::note_row_change(morkEnv* ev, mork_change inChange,
|
||||
morkRow* ioRow)
|
||||
{
|
||||
if ( this->IsTableRewrite() || this->HasChangeOverflow() )
|
||||
this->NoteTableSetAll(ev);
|
||||
else
|
||||
{
|
||||
nsIMdbHeap* heap = mTable_Store->mPort_Heap;
|
||||
morkTableChange* tableChange = new(*heap, ev)
|
||||
morkTableChange(ev, inChange, ioRow);
|
||||
if ( tableChange )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mTable_ChangeList.PushTail(tableChange);
|
||||
++mTable_ChangesCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
tableChange->ZapOldNext(ev, heap);
|
||||
this->NoteTableSetAll(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void morkTable::NoteTableSetAll(morkEnv* ev)
|
||||
{
|
||||
nsIMdbHeap* heap = mTable_Store->mPort_Heap;
|
||||
mTable_ChangeList.CutAndZapAllListMembers(ev, heap); // forget changes
|
||||
mTable_ChangesCount = 0;
|
||||
this->SetTableRewrite();
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkTable::CellUsesUnderflowWarning(morkEnv* ev)
|
||||
morkTable::TableGcUsesUnderflowWarning(morkEnv* ev)
|
||||
{
|
||||
ev->NewWarning("mTable_CellUses underflow");
|
||||
ev->NewWarning("mTable_GcUses underflow");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
|
@ -207,6 +300,38 @@ morkTable::NilRowSpaceError(morkEnv* ev)
|
|||
ev->NewError("nil mTable_RowSpace");
|
||||
}
|
||||
|
||||
mork_bool morkTable::MaybeDirtySpaceStoreAndTable()
|
||||
{
|
||||
morkRowSpace* rowSpace = mTable_RowSpace;
|
||||
if ( rowSpace )
|
||||
{
|
||||
morkStore* store = rowSpace->mSpace_Store;
|
||||
if ( store && store->mStore_CanDirty )
|
||||
{
|
||||
store->SetStoreDirty();
|
||||
rowSpace->mSpace_CanDirty = morkBool_kTrue;
|
||||
}
|
||||
|
||||
if ( rowSpace->mSpace_CanDirty ) // first time being dirtied?
|
||||
{
|
||||
if ( this->IsTableClean() )
|
||||
{
|
||||
mork_count rowCount = this->GetRowCount();
|
||||
mork_count oneThird = rowCount / 4; // one third of rows
|
||||
if ( oneThird > 0x07FFF ) // more than half max u2?
|
||||
oneThird = 0x07FFF;
|
||||
|
||||
mTable_ChangesMax = (mork_u2) oneThird;
|
||||
}
|
||||
this->SetTableDirty();
|
||||
rowSpace->SetRowSpaceDirty();
|
||||
|
||||
return morkBool_kTrue;
|
||||
}
|
||||
}
|
||||
return morkBool_kFalse;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkTable::GetMetaRow(morkEnv* ev, const mdbOid* inOptionalMetaRowOid)
|
||||
{
|
||||
|
@ -228,7 +353,13 @@ morkTable::GetMetaRow(morkEnv* ev, const mdbOid* inOptionalMetaRowOid)
|
|||
}
|
||||
mTable_MetaRow = outRow;
|
||||
if ( outRow ) // need to note another use of this row?
|
||||
outRow->AddTableUse(ev);
|
||||
{
|
||||
outRow->AddRowGcUse(ev);
|
||||
|
||||
this->SetTableNewMeta();
|
||||
if ( this->IsTableClean() ) // catch dirty status of meta row?
|
||||
this->MaybeDirtySpaceStoreAndTable();
|
||||
}
|
||||
}
|
||||
|
||||
return outRow;
|
||||
|
@ -285,26 +416,88 @@ morkTable::ArrayHasOid(morkEnv* ev, const mdbOid* inOid)
|
|||
mork_bool
|
||||
morkTable::MapHasOid(morkEnv* ev, const mdbOid* inOid)
|
||||
{
|
||||
return ( mTable_RowMap.GetOid(ev, inOid) != 0 );
|
||||
if ( mTable_RowMap )
|
||||
return ( mTable_RowMap->GetOid(ev, inOid) != 0 );
|
||||
else
|
||||
return ( ArrayHasOid(ev, inOid) >= 0 );
|
||||
}
|
||||
|
||||
void morkTable::build_row_map(morkEnv* ev)
|
||||
{
|
||||
morkRowMap* map = mTable_RowMap;
|
||||
if ( !map )
|
||||
{
|
||||
mork_count count = mTable_RowArray.mArray_Fill + 3;
|
||||
nsIMdbHeap* heap = mTable_Store->mPort_Heap;
|
||||
map = new(*heap, ev) morkRowMap(ev, morkUsage::kHeap, heap, heap, count);
|
||||
if ( map )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mTable_RowMap = map; // put strong ref here
|
||||
mork_count count = mTable_RowArray.mArray_Fill;
|
||||
mork_pos pos = -1;
|
||||
while ( ++pos < count )
|
||||
{
|
||||
morkRow* row = (morkRow*) mTable_RowArray.At(pos);
|
||||
if ( row && row->IsRow() )
|
||||
map->AddRow(ev, row);
|
||||
else
|
||||
row->NonRowTypeError(ev);
|
||||
}
|
||||
}
|
||||
else
|
||||
map->CutStrongRef(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
morkRow* morkTable::find_member_row(morkEnv* ev, morkRow* ioRow)
|
||||
{
|
||||
if ( mTable_RowMap )
|
||||
return mTable_RowMap->GetRow(ev, ioRow);
|
||||
else
|
||||
{
|
||||
mork_count count = mTable_RowArray.mArray_Fill;
|
||||
mork_pos pos = -1;
|
||||
while ( ++pos < count )
|
||||
{
|
||||
morkRow* row = (morkRow*) mTable_RowArray.At(pos);
|
||||
if ( row == ioRow )
|
||||
return row;
|
||||
}
|
||||
}
|
||||
return (morkRow*) 0;
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkTable::AddRow(morkEnv* ev, morkRow* ioRow)
|
||||
{
|
||||
morkRow* row = mTable_RowMap.GetRow(ev, ioRow);
|
||||
morkRow* row = this->find_member_row(ev, ioRow);
|
||||
if ( !row && ev->Good() )
|
||||
{
|
||||
mork_bool canDirty = ( this->IsTableClean() )?
|
||||
this->MaybeDirtySpaceStoreAndTable() : morkBool_kTrue;
|
||||
|
||||
mork_pos pos = mTable_RowArray.AppendSlot(ev, ioRow);
|
||||
if ( ev->Good() && pos >= 0 )
|
||||
{
|
||||
ioRow->AddTableUse(ev);
|
||||
if ( mTable_RowMap.AddRow(ev, ioRow) )
|
||||
ioRow->AddRowGcUse(ev);
|
||||
if ( mTable_RowMap )
|
||||
{
|
||||
if ( mTable_RowMap->AddRow(ev, ioRow) )
|
||||
{
|
||||
// okay, anything else?
|
||||
}
|
||||
else
|
||||
mTable_RowArray.CutSlot(ev, pos);
|
||||
}
|
||||
else if ( mTable_RowArray.mArray_Fill >= morkTable_kMakeRowMapThreshold )
|
||||
this->build_row_map(ev);
|
||||
|
||||
if ( canDirty && ev->Good() )
|
||||
this->NoteTableAddRow(ev, ioRow);
|
||||
}
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
@ -312,9 +505,12 @@ morkTable::AddRow(morkEnv* ev, morkRow* ioRow)
|
|||
mork_bool
|
||||
morkTable::CutRow(morkEnv* ev, morkRow* ioRow)
|
||||
{
|
||||
morkRow* row = mTable_RowMap.GetRow(ev, ioRow);
|
||||
morkRow* row = this->find_member_row(ev, ioRow);
|
||||
if ( row )
|
||||
{
|
||||
mork_bool canDirty = ( this->IsTableClean() )?
|
||||
this->MaybeDirtySpaceStoreAndTable() : morkBool_kTrue;
|
||||
|
||||
mork_count count = mTable_RowArray.mArray_Fill;
|
||||
morkRow** rowSlots = (morkRow**) mTable_RowArray.mArray_Slots;
|
||||
if ( rowSlots ) // array has vector as expected?
|
||||
|
@ -338,9 +534,50 @@ morkTable::CutRow(morkEnv* ev, morkRow* ioRow)
|
|||
else
|
||||
mTable_RowArray.NilSlotsAddressError(ev);
|
||||
|
||||
mTable_RowMap.CutRow(ev, ioRow);
|
||||
if ( ioRow->CutTableUse(ev) == 0 )
|
||||
ioRow->OnZeroTableUse(ev);
|
||||
if ( mTable_RowMap )
|
||||
mTable_RowMap->CutRow(ev, ioRow);
|
||||
|
||||
if ( canDirty )
|
||||
this->NoteTableCutRow(ev, ioRow);
|
||||
|
||||
if ( ioRow->CutRowGcUse(ev) == 0 )
|
||||
ioRow->OnZeroRowGcUse(ev);
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
|
||||
mork_bool
|
||||
morkTable::CutAllRows(morkEnv* ev)
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndTable() )
|
||||
{
|
||||
this->SetTableRewrite(); // everything is dirty
|
||||
this->NoteTableSetAll(ev);
|
||||
}
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mTable_RowArray.CutAllSlots(ev);
|
||||
if ( mTable_RowMap )
|
||||
{
|
||||
morkRowMapIter i(ev, mTable_RowMap);
|
||||
mork_change* c = 0;
|
||||
morkRow* r = 0;
|
||||
|
||||
for ( c = i.FirstRow(ev, &r); c; c = i.NextRow(ev, &r) )
|
||||
{
|
||||
if ( r )
|
||||
{
|
||||
if ( r->CutRowGcUse(ev) == 0 )
|
||||
r->OnZeroRowGcUse(ev);
|
||||
|
||||
i.CutHereRow(ev, (morkRow**) 0);
|
||||
}
|
||||
else
|
||||
ev->NewWarning("nil row in table map");
|
||||
}
|
||||
}
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
@ -367,6 +604,65 @@ morkTable::NewTableRowCursor(morkEnv* ev, mork_pos inRowPos)
|
|||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
morkTableChange::morkTableChange(morkEnv* ev, mork_change inChange,
|
||||
morkRow* ioRow)
|
||||
// use this constructor for inChange == morkChange_kAdd or morkChange_kCut
|
||||
: morkNext()
|
||||
, mTableChange_Row( ioRow )
|
||||
, mTableChange_Pos( morkTableChange_kNone )
|
||||
{
|
||||
if ( ioRow )
|
||||
{
|
||||
if ( ioRow->IsRow() )
|
||||
{
|
||||
if ( inChange == morkChange_kAdd )
|
||||
mTableChange_Pos = morkTableChange_kAdd;
|
||||
else if ( inChange == morkChange_kCut )
|
||||
mTableChange_Pos = morkTableChange_kCut;
|
||||
else
|
||||
this->UnknownChangeError(ev);
|
||||
}
|
||||
else
|
||||
ioRow->NonRowTypeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
morkTableChange::morkTableChange(morkEnv* ev, morkRow* ioRow, mork_pos inPos)
|
||||
// use this constructor when the row is moved
|
||||
: morkNext()
|
||||
, mTableChange_Row( ioRow )
|
||||
, mTableChange_Pos( inPos )
|
||||
{
|
||||
if ( ioRow )
|
||||
{
|
||||
if ( ioRow->IsRow() )
|
||||
{
|
||||
if ( inPos < 0 )
|
||||
this->NegativeMovePosError(ev);
|
||||
}
|
||||
else
|
||||
ioRow->NonRowTypeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
void morkTableChange::UnknownChangeError(morkEnv* ev) const
|
||||
// morkChange_kAdd or morkChange_kCut
|
||||
{
|
||||
ev->NewError("mTableChange_Pos neither kAdd nor kCut");
|
||||
}
|
||||
|
||||
void morkTableChange::NegativeMovePosError(morkEnv* ev) const
|
||||
// move must be non-neg position
|
||||
{
|
||||
ev->NewError("negative mTableChange_Pos for row move");
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
morkTableMap::~morkTableMap()
|
||||
{
|
||||
|
@ -380,5 +676,4 @@ morkTableMap::morkTableMap(morkEnv* ev, const morkUsage& inUsage,
|
|||
mNode_Derived = morkDerived_kTableMap;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
@ -48,12 +52,36 @@
|
|||
class nsIMdbTable;
|
||||
#define morkDerived_kTable /*i*/ 0x5462 /* ascii 'Tb' */
|
||||
|
||||
#define morkTable_kStartRowArraySize 11 /* modest starting size for array */
|
||||
/*| kStartRowArraySize: starting physical size of array for mTable_RowArray.
|
||||
**| We want this number very small, so that a table containing exactly one
|
||||
**| row member will not pay too significantly in space overhead. But we want
|
||||
**| a number bigger than one, so there is some space for growth.
|
||||
|*/
|
||||
#define morkTable_kStartRowArraySize 3 /* modest starting size for array */
|
||||
|
||||
#define morkTable_kStartRowMapSlotCount 128
|
||||
#define morkTable_kMaxCellUses 0x0FFFF /* max for 16-bit unsigned int */
|
||||
/*| kMakeRowMapThreshold: this is the number of rows in a table which causes
|
||||
**| a hash table (mTable_RowMap) to be lazily created for faster member row
|
||||
**| identification, during such operations as cuts and adds. This number must
|
||||
**| be small enough that linear searches are not bad for member counts less
|
||||
**| than this; but this number must also be large enough that creating a hash
|
||||
**| table does not increase the per-row space overhead by a big percentage.
|
||||
**| For speed, numbers on the order of ten to twenty are all fine; for space,
|
||||
**| I believe a number as small as ten will have too much space overhead.
|
||||
|*/
|
||||
#define morkTable_kMakeRowMapThreshold 17 /* when to build mTable_RowMap */
|
||||
|
||||
class morkTable : public morkObject {
|
||||
#define morkTable_kStartRowMapSlotCount 13
|
||||
#define morkTable_kMaxTableGcUses 0x0FF /* max for 8-bit unsigned int */
|
||||
|
||||
#define morkTable_kUniqueBit ((mork_u1) (1 << 0))
|
||||
#define morkTable_kVerboseBit ((mork_u1) (1 << 1))
|
||||
#define morkTable_kNotedBit ((mork_u1) (1 << 2)) /* space has change notes */
|
||||
#define morkTable_kRewriteBit ((mork_u1) (1 << 3)) /* must rewrite all rows */
|
||||
#define morkTable_kNewMetaBit ((mork_u1) (1 << 4)) /* new table meta row */
|
||||
|
||||
class morkTable : public morkObject, public morkLink {
|
||||
|
||||
// NOTE the morkLink base is for morkRowSpace::mRowSpace_TablesByPriority
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
@ -74,7 +102,6 @@ class morkTable : public morkObject {
|
|||
public: // state is public because the entire Mork system is private
|
||||
|
||||
morkStore* mTable_Store; // weak ref to port
|
||||
// mork_seed mTable_Seed; // use TableSeed() instead
|
||||
|
||||
// mTable_RowSpace->mSpace_Scope is row scope
|
||||
morkRowSpace* mTable_RowSpace; // weak ref to containing space
|
||||
|
@ -82,15 +109,65 @@ public: // state is public because the entire Mork system is private
|
|||
morkRow* mTable_MetaRow; // table's actual meta row
|
||||
mdbOid mTable_MetaRowOid; // oid for meta row
|
||||
|
||||
morkRowMap mTable_RowMap; // hash table of all members
|
||||
morkRowMap* mTable_RowMap; // (strong ref) hash table of all members
|
||||
morkArray mTable_RowArray; // array of morkRow pointers
|
||||
|
||||
morkList mTable_ChangeList; // list of table changes
|
||||
mork_u2 mTable_ChangesCount; // length of changes list
|
||||
mork_u2 mTable_ChangesMax; // max list length before rewrite
|
||||
|
||||
mork_tid mTable_Id;
|
||||
mork_kind mTable_Kind;
|
||||
|
||||
mork_bool mTable_MustBeUnique;
|
||||
mork_u1 mTable_Pad; // padding for u4 alignment
|
||||
mork_u2 mTable_CellUses; // persistent references from cells
|
||||
mork_u1 mTable_Flags; // bit flags
|
||||
mork_priority mTable_Priority; // 0..9, any other value equals 9
|
||||
mork_u1 mTable_GcUses; // persistent references from cells
|
||||
mork_u1 mTable_Pad; // for u4 alignment
|
||||
|
||||
public: // flags bit twiddling
|
||||
|
||||
void SetTableUnique() { mTable_Flags |= morkTable_kUniqueBit; }
|
||||
void SetTableVerbose() { mTable_Flags |= morkTable_kVerboseBit; }
|
||||
void SetTableNoted() { mTable_Flags |= morkTable_kNotedBit; }
|
||||
void SetTableRewrite() { mTable_Flags |= morkTable_kRewriteBit; }
|
||||
void SetTableNewMeta() { mTable_Flags |= morkTable_kNewMetaBit; }
|
||||
|
||||
void ClearTableUnique() { mTable_Flags &= (mork_u1) ~morkTable_kUniqueBit; }
|
||||
void ClearTableVerbose() { mTable_Flags &= (mork_u1) ~morkTable_kVerboseBit; }
|
||||
void ClearTableNoted() { mTable_Flags &= (mork_u1) ~morkTable_kNotedBit; }
|
||||
void ClearTableRewrite() { mTable_Flags &= (mork_u1) ~morkTable_kRewriteBit; }
|
||||
void ClearTableNewMeta() { mTable_Flags &= (mork_u1) ~morkTable_kNewMetaBit; }
|
||||
|
||||
mork_bool IsTableUnique() const
|
||||
{ return ( mTable_Flags & morkTable_kUniqueBit ) != 0; }
|
||||
|
||||
mork_bool IsTableVerbose() const
|
||||
{ return ( mTable_Flags & morkTable_kVerboseBit ) != 0; }
|
||||
|
||||
mork_bool IsTableNoted() const
|
||||
{ return ( mTable_Flags & morkTable_kNotedBit ) != 0; }
|
||||
|
||||
mork_bool IsTableRewrite() const
|
||||
{ return ( mTable_Flags & morkTable_kRewriteBit ) != 0; }
|
||||
|
||||
mork_bool IsTableNewMeta() const
|
||||
{ return ( mTable_Flags & morkTable_kNewMetaBit ) != 0; }
|
||||
|
||||
public: // table dirty handling more complex than morkNode::SetNodeDirty() etc.
|
||||
|
||||
void SetTableDirty() { this->SetNodeDirty(); }
|
||||
void SetTableClean(morkEnv* ev);
|
||||
|
||||
mork_bool IsTableClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsTableDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
public: // morkNode memory management operators
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{ return morkNode::MakeNew(inSize, ioHeap, ev); }
|
||||
|
||||
void operator delete(void* ioAddress)
|
||||
{ morkNode::OnDeleteAssert(ioAddress); }
|
||||
// do NOT call delete on morkNode instances. Call ZapOld() instead.
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
|
@ -121,14 +198,37 @@ public: // errors
|
|||
static void NilRowSpaceError(morkEnv* ev);
|
||||
|
||||
public: // warnings
|
||||
static void CellUsesUnderflowWarning(morkEnv* ev);
|
||||
static void TableGcUsesUnderflowWarning(morkEnv* ev);
|
||||
|
||||
public: // noting table changes
|
||||
|
||||
mork_bool HasChangeOverflow() const
|
||||
{ return mTable_ChangesCount >= mTable_ChangesMax; }
|
||||
|
||||
void NoteTableSetAll(morkEnv* ev);
|
||||
void NoteTableMoveRow(morkEnv* ev, morkRow* ioRow, mork_pos inPos);
|
||||
|
||||
void note_row_change(morkEnv* ev, mork_change inChange, morkRow* ioRow);
|
||||
|
||||
void NoteTableAddRow(morkEnv* ev, morkRow* ioRow)
|
||||
{ this->note_row_change(ev, morkChange_kAdd, ioRow); }
|
||||
|
||||
void NoteTableCutRow(morkEnv* ev, morkRow* ioRow)
|
||||
{ this->note_row_change(ev, morkChange_kCut, ioRow); }
|
||||
|
||||
protected: // internal row map methods
|
||||
|
||||
morkRow* find_member_row(morkEnv* ev, morkRow* ioRow);
|
||||
void build_row_map(morkEnv* ev);
|
||||
|
||||
public: // other table methods
|
||||
|
||||
mork_bool MaybeDirtySpaceStoreAndTable();
|
||||
|
||||
morkRow* GetMetaRow(morkEnv* ev, const mdbOid* inOptionalMetaRowOid);
|
||||
|
||||
mork_u2 AddCellUse(morkEnv* ev);
|
||||
mork_u2 CutCellUse(morkEnv* ev);
|
||||
mork_u2 AddTableGcUse(morkEnv* ev);
|
||||
mork_u2 CutTableGcUse(morkEnv* ev);
|
||||
|
||||
// void DirtyAllTableContent(morkEnv* ev);
|
||||
|
||||
|
@ -146,6 +246,7 @@ public: // other table methods
|
|||
mork_bool MapHasOid(morkEnv* ev, const mdbOid* inOid);
|
||||
mork_bool AddRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good()
|
||||
mork_bool CutRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good()
|
||||
mork_bool CutAllRows(morkEnv* ev); // returns ev->Good()
|
||||
|
||||
morkTableRowCursor* NewTableRowCursor(morkEnv* ev, mork_pos inRowPos);
|
||||
|
||||
|
@ -161,6 +262,48 @@ public: // typesafe refcounting inlines calling inherited morkNode methods
|
|||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// use negative values for kCut and kAdd, to keep non-neg move pos distinct:
|
||||
#define morkTableChange_kCut ((mork_pos) -1) /* shows row was cut */
|
||||
#define morkTableChange_kAdd ((mork_pos) -2) /* shows row was added */
|
||||
#define morkTableChange_kNone ((mork_pos) -3) /* unknown change */
|
||||
|
||||
class morkTableChange : public morkNext {
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
morkRow* mTableChange_Row; // the row in the change
|
||||
|
||||
mork_pos mTableChange_Pos; // kAdd, kCut, or non-neg for row move
|
||||
|
||||
public:
|
||||
morkTableChange(morkEnv* ev, mork_change inChange, morkRow* ioRow);
|
||||
// use this constructor for inChange == morkChange_kAdd or morkChange_kCut
|
||||
|
||||
morkTableChange(morkEnv* ev, morkRow* ioRow, mork_pos inPos);
|
||||
// use this constructor when the row is moved
|
||||
|
||||
public:
|
||||
void UnknownChangeError(morkEnv* ev) const; // morkChange_kAdd or morkChange_kCut
|
||||
void NegativeMovePosError(morkEnv* ev) const; // move must be non-neg position
|
||||
|
||||
public:
|
||||
|
||||
mork_bool IsAddRowTableChange() const
|
||||
{ return ( mTableChange_Pos == morkTableChange_kAdd ); }
|
||||
|
||||
mork_bool IsCutRowTableChange() const
|
||||
{ return ( mTableChange_Pos == morkTableChange_kCut ); }
|
||||
|
||||
mork_bool IsMoveRowTableChange() const
|
||||
{ return ( mTableChange_Pos >= 0 ); }
|
||||
|
||||
public:
|
||||
|
||||
mork_pos GetMovePos() const { return mTableChange_Pos; }
|
||||
// GetMovePos() assumes that IsMoveRowTableChange() is true.
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kTableMap /*i*/ 0x744D /* ascii 'tM' */
|
||||
|
||||
/*| morkTableMap: maps mork_token -> morkTable
|
||||
|
@ -214,6 +357,7 @@ public:
|
|||
HereTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
|
||||
{ return this->Here(ev, outTid, outTable); }
|
||||
|
||||
// cutting while iterating hash map might dirty the parent table:
|
||||
mork_change*
|
||||
CutHereTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
|
||||
{ return this->CutHere(ev, outTid, outTable); }
|
||||
|
|
|
@ -241,6 +241,45 @@ morkThumb::Make_OpenFileStore(morkEnv* ev, nsIMdbHeap* ioHeap,
|
|||
}
|
||||
|
||||
|
||||
/*static*/ morkThumb*
|
||||
morkThumb::Make_LargeCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore)
|
||||
{
|
||||
morkThumb* outThumb = 0;
|
||||
if ( ioHeap && ioStore )
|
||||
{
|
||||
morkFile* file = ioStore->mStore_File;
|
||||
if ( file )
|
||||
{
|
||||
outThumb = new(*ioHeap, ev)
|
||||
morkThumb(ev, morkUsage::kHeap, ioHeap, ioHeap,
|
||||
morkThumb_kMagic_LargeCommit);
|
||||
|
||||
if ( outThumb )
|
||||
{
|
||||
morkWriter* writer = new(*ioHeap, ev)
|
||||
morkWriter(ev, morkUsage::kHeap, ioHeap, ioStore, file, ioHeap);
|
||||
if ( writer )
|
||||
{
|
||||
writer->mWriter_CommitGroupIdentity =
|
||||
++ioStore->mStore_CommitGroupIdentity;
|
||||
writer->mWriter_NeedDirtyAll = morkBool_kFalse;
|
||||
outThumb->mThumb_DoCollect = morkBool_kFalse;
|
||||
morkStore::SlotStrongStore(ioStore, ev, &outThumb->mThumb_Store);
|
||||
morkFile::SlotStrongFile(file, ev, &outThumb->mThumb_File);
|
||||
morkWriter::SlotStrongWriter(writer, ev, &outThumb->mThumb_Writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ioStore->NilStoreFileError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return outThumb;
|
||||
}
|
||||
|
||||
/*static*/ morkThumb*
|
||||
morkThumb::Make_CompressCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore, mork_bool inDoCollect)
|
||||
|
@ -266,6 +305,10 @@ morkThumb::Make_CompressCommit(morkEnv* ev,
|
|||
morkStore::SlotStrongStore(ioStore, ev, &outThumb->mThumb_Store);
|
||||
morkFile::SlotStrongFile(file, ev, &outThumb->mThumb_File);
|
||||
morkWriter::SlotStrongWriter(writer, ev, &outThumb->mThumb_Writer);
|
||||
|
||||
// cope with fact that parsed transaction groups are going away:
|
||||
ioStore->mStore_FirstCommitGroupPos = 0;
|
||||
ioStore->mStore_SecondCommitGroupPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -406,15 +449,15 @@ void morkThumb::DoMore_ImportContent(morkEnv* ev)
|
|||
|
||||
void morkThumb::DoMore_LargeCommit(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
this->DoMore_Commit(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_SessionCommit(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
this->DoMore_Commit(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_CompressCommit(morkEnv* ev)
|
||||
void morkThumb::DoMore_Commit(morkEnv* ev)
|
||||
{
|
||||
morkWriter* writer = mThumb_Writer;
|
||||
if ( writer )
|
||||
|
@ -433,6 +476,11 @@ void morkThumb::DoMore_CompressCommit(morkEnv* ev)
|
|||
}
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_CompressCommit(morkEnv* ev)
|
||||
{
|
||||
this->DoMore_Commit(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_SearchManyColumns(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
|
|
|
@ -128,6 +128,7 @@ public: // 'do more' methods
|
|||
void DoMore_LargeCommit(morkEnv* ev);
|
||||
void DoMore_SessionCommit(morkEnv* ev);
|
||||
void DoMore_CompressCommit(morkEnv* ev);
|
||||
void DoMore_Commit(morkEnv* ev);
|
||||
void DoMore_SearchManyColumns(morkEnv* ev);
|
||||
void DoMore_NewSortColumn(morkEnv* ev);
|
||||
void DoMore_NewSortColumnWithCompare(morkEnv* ev);
|
||||
|
@ -150,6 +151,9 @@ public: // assorted thumb constructors
|
|||
static morkThumb* Make_CompressCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore, mork_bool inDoCollect);
|
||||
|
||||
static morkThumb* Make_LargeCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore);
|
||||
|
||||
// { ===== begin non-poly methods imitating nsIMdbThumb =====
|
||||
void GetProgress(morkEnv* ev, mdb_count* outTotal,
|
||||
mdb_count* outCurrent, mdb_bool* outDone, mdb_bool* outBroken);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -103,6 +103,8 @@
|
|||
#define morkWriter_kRowCellDepth 4 /* */
|
||||
#define morkWriter_kRowCellValueDepth 6 /* */
|
||||
|
||||
#define morkWriter_kGroupBufSize 64 /* */
|
||||
|
||||
// v=1.1 retired on 23-Mar-99 (for metainfo one char column names)
|
||||
// v=1.2 retired on 20-Apr-99 (for ":c" suffix on table kind hex refs)
|
||||
// v=1.3 retired on 20-Apr-99 (for 1CE:m instead of ill-formed 1CE:^6D)
|
||||
|
@ -129,6 +131,13 @@ public: // state is public because the entire Mork system is private
|
|||
morkStream* mWriter_Stream; // strong ref to stream on bud file
|
||||
nsIMdbHeap* mWriter_SlotHeap; // strong ref to slot heap
|
||||
|
||||
// GroupIdentity should be based on mStore_CommitGroupIdentity:
|
||||
mork_gid mWriter_CommitGroupIdentity; // transaction ID number
|
||||
|
||||
// GroupBuf holds a hex version of mWriter_CommitGroupIdentity:
|
||||
char mWriter_GroupBuf[ morkWriter_kGroupBufSize ];
|
||||
mork_fill mWriter_GroupBufFill; // actual bytes in GroupBuf
|
||||
|
||||
mork_count mWriter_TotalCount; // count of all things to be written
|
||||
mork_count mWriter_DoneCount; // count of things already written
|
||||
|
||||
|
@ -149,11 +158,18 @@ public: // state is public because the entire Mork system is private
|
|||
mork_scope mWriter_DictAtomScope; // current atom scope
|
||||
|
||||
mork_bool mWriter_NeedDirtyAll; // need to call DirtyAll()
|
||||
mork_u1 mWriter_Phase; // status of writing process
|
||||
mork_bool mWriter_Incremental; // opposite of mWriter_NeedDirtyAll
|
||||
mork_bool mWriter_DidStartDict; // true when a dict has been started
|
||||
mork_bool mWriter_DidEndDict; // true when a dict has been ended
|
||||
|
||||
mork_bool mWriter_SuppressDirtyRowNewline; // for table meta rows
|
||||
mork_bool mWriter_DidStartGroup; // true when a group has been started
|
||||
mork_bool mWriter_DidEndGroup; // true when a group has been ended
|
||||
mork_u1 mWriter_Phase; // status of writing process
|
||||
|
||||
mork_bool mWriter_BeVerbose; // driven by env and table verbose settings:
|
||||
// mWriter_BeVerbose equals ( ev->mEnv_BeVerbose || table->IsTableVerbose() )
|
||||
|
||||
mork_u1 mWriter_Pad[ 3 ]; // for u4 alignment
|
||||
|
||||
mork_pos mWriter_TableRowArrayPos; // index into mTable_RowArray
|
||||
|
@ -202,9 +218,11 @@ public: // typing & errors
|
|||
static void NilWriterStoreError(morkEnv* ev);
|
||||
static void NilWriterBudError(morkEnv* ev);
|
||||
static void NilWriterStreamError(morkEnv* ev);
|
||||
static void NilWriterFileError(morkEnv* ev);
|
||||
static void UnsupportedPhaseError(morkEnv* ev);
|
||||
|
||||
public: // utitlities
|
||||
void ChangeRowForm(morkEnv* ev, mork_cscode inNewForm);
|
||||
void ChangeDictForm(morkEnv* ev, mork_cscode inNewForm);
|
||||
void ChangeDictAtomScope(morkEnv* ev, mork_scope inScope);
|
||||
|
||||
|
@ -228,6 +246,10 @@ public: // inlines
|
|||
mWriter_LineSize = mWriter_Stream->PutIndent(ev, inDepth);
|
||||
}
|
||||
|
||||
public: // delayed construction
|
||||
|
||||
void MakeWriterStream(morkEnv* ev); // give writer a suitable stream
|
||||
|
||||
public: // iterative/asynchronous writing
|
||||
|
||||
mork_bool WriteMore(morkEnv* ev); // call until IsWritingDone() is true
|
||||
|
@ -247,6 +269,12 @@ public: // marking all content dirty
|
|||
// written only at need (because of being dirty). Note the method can
|
||||
// stop early when any error happens, since this will abort any commit.
|
||||
|
||||
public: // group commit transactions
|
||||
|
||||
mork_bool StartGroup(morkEnv* ev);
|
||||
mork_bool CommitGroup(morkEnv* ev);
|
||||
mork_bool AbortGroup(morkEnv* ev);
|
||||
|
||||
public: // phase methods
|
||||
mork_bool OnNothingDone(morkEnv* ev);
|
||||
mork_bool OnDirtyAllDone(morkEnv* ev);
|
||||
|
@ -275,6 +303,12 @@ public: // writing node content second pass
|
|||
mork_bool PutTable(morkEnv* ev, morkTable* ioTable);
|
||||
mork_bool PutRow(morkEnv* ev, morkRow* ioRow);
|
||||
mork_bool PutRowCells(morkEnv* ev, morkRow* ioRow);
|
||||
mork_bool PutVerboseRowCells(morkEnv* ev, morkRow* ioRow);
|
||||
|
||||
mork_bool PutCell(morkEnv* ev, morkCell* ioCell, mork_bool inWithVal);
|
||||
mork_bool PutVerboseCell(morkEnv* ev, morkCell* ioCell, mork_bool inWithVal);
|
||||
|
||||
mork_bool PutTableChange(morkEnv* ev, const morkTableChange* inChange);
|
||||
|
||||
public: // other writer methods
|
||||
|
||||
|
|
|
@ -299,6 +299,8 @@ orkinCell::SetBlob(nsIMdbEnv* mev,
|
|||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -317,6 +319,8 @@ orkinCell::ClearBlob( // make empty (so content has zero length)
|
|||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -363,7 +367,11 @@ orkinCell::SetYarn(nsIMdbEnv* mev,
|
|||
{
|
||||
morkStore* store = row->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
cell->SetYarn(ev, inYarn, store);
|
||||
if ( row->IsRowClean() && store->mStore_CanDirty )
|
||||
row->MaybeDirtySpaceStoreAndRow();
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
@ -429,8 +437,11 @@ orkinCell::SetColumn(nsIMdbEnv* mev, mdb_column inColumn)
|
|||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
morkCellObject* cellObj;
|
||||
cellObj = (morkCellObject*) mHandle_Object;
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
morkCellObject* cellObj = (morkCellObject*) mHandle_Object;
|
||||
MORK_USED_1(cellObj);
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -518,6 +529,7 @@ orkinCell::GetRow(nsIMdbEnv* mev, // parent row for this cell
|
|||
*acqRow = outRow;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinCell::GetPort(nsIMdbEnv* mev, // port containing cell
|
||||
nsIMdbPort** acqPort)
|
||||
|
@ -623,8 +635,11 @@ orkinCell::SetChildRow( // access table of specific attribute
|
|||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
morkCellObject* cellObj;
|
||||
cellObj = (morkCellObject*) mHandle_Object;
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
morkCellObject* cellObj = (morkCellObject*) mHandle_Object;
|
||||
MORK_USED_1(cellObj);
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -668,8 +683,11 @@ orkinCell::SetChildTable( // access table of specific attribute
|
|||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
morkCellObject* cellObj;
|
||||
cellObj = (morkCellObject*) mHandle_Object;
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
morkCellObject* cellObj = (morkCellObject*) mHandle_Object;
|
||||
MORK_USED_1(cellObj);
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
|
|
@ -247,6 +247,33 @@ orkinEnv::GetWarningCount(mdb_count* outCount,
|
|||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinEnv::GetEnvBeVerbose(mdb_bool* outBeVerbose)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mork_bool beVerbose = morkBool_kFalse;
|
||||
morkEnv* ev = this->CanUseEnv(/*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
beVerbose = ev->mEnv_BeVerbose;
|
||||
}
|
||||
if ( outBeVerbose )
|
||||
*outBeVerbose = beVerbose;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinEnv::SetEnvBeVerbose(mdb_bool inBeVerbose)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = this->CanUseEnv(/*inMutable*/ morkBool_kTrue, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
ev->mEnv_BeVerbose = inBeVerbose;
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinEnv::GetDoTrace(mdb_bool* outDoTrace)
|
||||
{
|
||||
|
|
|
@ -138,6 +138,9 @@ public:
|
|||
virtual mdb_err GetWarningCount(mdb_count* outCount,
|
||||
mdb_bool* outShouldAbort);
|
||||
|
||||
virtual mdb_err GetEnvBeVerbose(mdb_bool* outBeVerbose);
|
||||
virtual mdb_err SetEnvBeVerbose(mdb_bool inBeVerbose);
|
||||
|
||||
virtual mdb_err GetDoTrace(mdb_bool* outDoTrace);
|
||||
virtual mdb_err SetDoTrace(mdb_bool inDoTrace);
|
||||
|
||||
|
|
|
@ -274,6 +274,78 @@ orkinFactory::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen)
|
|||
|
||||
// { ===== begin nsIMdbFactory methods =====
|
||||
|
||||
// { ----- begin file methods -----
|
||||
/*virtual*/ mdb_err
|
||||
orkinFactory::OpenOldFile(nsIMdbEnv* mev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, mork_bool inFrozen, nsIMdbFile** acqFile)
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be open and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbFile* outFile = 0;
|
||||
morkEnv* ev = this->CanUseFactory(mev,
|
||||
/*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkFactory* factory = (morkFactory*) this->mHandle_Object;
|
||||
if ( !ioHeap )
|
||||
ioHeap = &factory->mFactory_Heap;
|
||||
|
||||
morkFile* file = morkFile::OpenOldFile(ev, ioHeap, inFilePath, inFrozen);
|
||||
if ( file )
|
||||
{
|
||||
outFile = file->AcquireFileHandle(ev);
|
||||
file->CutStrongRef(ev);
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqFile )
|
||||
*acqFile = outFile;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinFactory::CreateNewFile(nsIMdbEnv* mev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, nsIMdbFile** acqFile)
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be created and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbFile* outFile = 0;
|
||||
morkEnv* ev = this->CanUseFactory(mev,
|
||||
/*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkFactory* factory = (morkFactory*) this->mHandle_Object;
|
||||
if ( !ioHeap )
|
||||
ioHeap = &factory->mFactory_Heap;
|
||||
|
||||
morkFile* file = morkFile::CreateNewFile(ev, ioHeap, inFilePath);
|
||||
if ( file )
|
||||
{
|
||||
outFile = file->AcquireFileHandle(ev);
|
||||
file->CutStrongRef(ev);
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqFile )
|
||||
*acqFile = outFile;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end file methods -----
|
||||
|
||||
// { ----- begin env methods -----
|
||||
/*virtual*/ mdb_err
|
||||
orkinFactory::MakeEnv(nsIMdbHeap* ioHeap, nsIMdbEnv** acqEnv)
|
||||
|
@ -451,6 +523,9 @@ orkinFactory::ThumbToOpenPort( // redeeming a completed thumb from OpenFilePort(
|
|||
if ( store )
|
||||
{
|
||||
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
|
||||
store->mStore_CanDirty = morkBool_kTrue;
|
||||
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
|
||||
|
||||
outPort = orkinStore::MakeStore(ev, store);
|
||||
}
|
||||
}
|
||||
|
@ -595,6 +670,9 @@ orkinFactory::ThumbToOpenStore( // redeem completed thumb from OpenFileStore()
|
|||
if ( store )
|
||||
{
|
||||
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
|
||||
store->mStore_CanDirty = morkBool_kTrue;
|
||||
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
|
||||
|
||||
outStore = orkinStore::MakeStore(ev, store);
|
||||
}
|
||||
}
|
||||
|
@ -635,6 +713,9 @@ orkinFactory::CreateNewFileStore( // create a new db with minimal content
|
|||
if ( store )
|
||||
{
|
||||
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
|
||||
store->mStore_CanDirty = morkBool_kTrue;
|
||||
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
|
||||
|
||||
if ( store->CreateStoreFile(ev, inFilePath, inOpenPolicy) )
|
||||
outStore = orkinStore::MakeStore(ev, store);
|
||||
|
||||
|
|
|
@ -140,6 +140,26 @@ public:
|
|||
|
||||
// { ===== begin nsIMdbFactory methods =====
|
||||
|
||||
// { ----- begin file methods -----
|
||||
virtual mdb_err OpenOldFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, mdb_bool inFrozen, nsIMdbFile** acqFile);
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be open and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
|
||||
virtual mdb_err CreateNewFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, nsIMdbFile** acqFile);
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be created and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
// } ----- end file methods -----
|
||||
|
||||
// { ----- begin env methods -----
|
||||
virtual mdb_err MakeEnv(nsIMdbHeap* ioHeap, nsIMdbEnv** acqEnv); // new env
|
||||
// ioHeap can be nil, causing a MakeHeap() style heap instance to be used
|
||||
|
|
|
@ -377,6 +377,8 @@ orkinRow::BecomeContent(nsIMdbEnv* mev,
|
|||
&outErr, &row);
|
||||
if ( ev )
|
||||
{
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
|
|
@ -68,6 +68,10 @@
|
|||
#include "morkThumb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKFILE_
|
||||
#include "morkFile.h"
|
||||
#endif
|
||||
|
||||
#ifndef _ORKINTHUMB_
|
||||
#include "orkinThumb.h"
|
||||
#endif
|
||||
|
@ -566,7 +570,7 @@ orkinStore::GetRowRefCount( // get number of tables that contain a row
|
|||
morkStore* store = (morkStore*) mHandle_Object;
|
||||
morkRow* row = store->GetRow(ev, inOid);
|
||||
if ( row && ev->Good() )
|
||||
count = row->mRow_TableUses;
|
||||
count = row->mRow_GcUses;
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -758,6 +762,35 @@ orkinStore::GetPortTableCursor( // get cursor for all tables of specific type
|
|||
}
|
||||
// } ----- end table methods -----
|
||||
|
||||
// { ----- begin commit methods -----
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinStore::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 = ((morkStore*) mHandle_Object)->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 =====
|
||||
|
||||
// { ===== begin nsIMdbStore methods =====
|
||||
|
@ -809,7 +842,7 @@ orkinStore::NewTableWithOid( // make one new table of specific type
|
|||
{
|
||||
table->mTable_Kind = inTableKind;
|
||||
if ( inMustBeUnique )
|
||||
table->mTable_MustBeUnique = inMustBeUnique;
|
||||
table->SetTableUnique();
|
||||
outTable = table->AcquireTableHandle(ev);
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
|
@ -1030,10 +1063,24 @@ orkinStore::LargeCommit( // save important changes if at all possible
|
|||
{
|
||||
morkStore* store = (morkStore*) mHandle_Object;
|
||||
nsIMdbHeap* heap = store->mPort_Heap;
|
||||
|
||||
morkThumb* thumb = 0;
|
||||
morkFile* file = store->mStore_File;
|
||||
if ( file && file->Length(ev) > 128 && store->mStore_CanWriteIncremental )
|
||||
{
|
||||
thumb = morkThumb::Make_LargeCommit(ev, heap, store);
|
||||
}
|
||||
else
|
||||
{
|
||||
mork_bool doCollect = morkBool_kFalse;
|
||||
morkThumb* thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
|
||||
thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
|
||||
}
|
||||
|
||||
if ( thumb )
|
||||
{
|
||||
outThumb = orkinThumb::MakeThumb(ev, thumb);
|
||||
thumb->CutStrongRef(ev);
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -1058,11 +1105,24 @@ orkinStore::SessionCommit( // save all changes if large commits delayed
|
|||
{
|
||||
morkStore* store = (morkStore*) mHandle_Object;
|
||||
nsIMdbHeap* heap = store->mPort_Heap;
|
||||
mork_bool doCollect = morkBool_kFalse;
|
||||
morkThumb* thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
|
||||
if ( thumb )
|
||||
outThumb = orkinThumb::MakeThumb(ev, thumb);
|
||||
|
||||
morkThumb* thumb = 0;
|
||||
morkFile* file = store->mStore_File;
|
||||
if ( file && file->Length(ev) > 128 && store->mStore_CanWriteIncremental )
|
||||
{
|
||||
thumb = morkThumb::Make_LargeCommit(ev, heap, store);
|
||||
}
|
||||
else
|
||||
{
|
||||
mork_bool doCollect = morkBool_kFalse;
|
||||
thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
|
||||
}
|
||||
|
||||
if ( thumb )
|
||||
{
|
||||
outThumb = orkinThumb::MakeThumb(ev, thumb);
|
||||
thumb->CutStrongRef(ev);
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqThumb )
|
||||
|
@ -1078,7 +1138,6 @@ orkinStore::CompressCommit( // commit and make db smaller if possible
|
|||
// 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.
|
||||
// } ----- end commit methods -----
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbThumb* outThumb = 0;
|
||||
|
@ -1090,7 +1149,11 @@ orkinStore::CompressCommit( // commit and make db smaller if possible
|
|||
mork_bool doCollect = morkBool_kFalse;
|
||||
morkThumb* thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
|
||||
if ( thumb )
|
||||
{
|
||||
outThumb = orkinThumb::MakeThumb(ev, thumb);
|
||||
thumb->CutStrongRef(ev);
|
||||
store->mStore_CanWriteIncremental = morkBool_kTrue;
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -1099,6 +1162,8 @@ orkinStore::CompressCommit( // commit and make db smaller if possible
|
|||
return outErr;
|
||||
}
|
||||
|
||||
// } ----- end commit methods -----
|
||||
|
||||
// } ===== end nsIMdbStore methods =====
|
||||
|
||||
|
||||
|
|
|
@ -302,6 +302,69 @@ public: // type identification
|
|||
nsIMdbPortTableCursor** acqCursor); // all such tables in the port
|
||||
// } ----- end table methods -----
|
||||
|
||||
|
||||
// { ----- begin commit methods -----
|
||||
|
||||
virtual mdb_err ShouldCompress( // store wastes at least inPercentWaste?
|
||||
nsIMdbEnv* ev, // 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
|
||||
// ShouldCompress() returns true if the store can determine that the file
|
||||
// will shrink by an estimated percentage of inPercentWaste% (or more) if
|
||||
// CompressCommit() is called, because that percentage of the file seems
|
||||
// to be recoverable free space. The granularity is only in terms of
|
||||
// percentage points, and any value over 100 is considered equal to 100.
|
||||
//
|
||||
// If a store only has an approximate idea how much space might be saved
|
||||
// during a compress, then a best guess should be made. For example, the
|
||||
// Mork implementation might keep track of how much file space began with
|
||||
// text content before the first updating transaction, and then consider
|
||||
// all content following the start of the first transaction as potentially
|
||||
// wasted space if it is all updates and not just new content. (This is
|
||||
// a safe assumption in the sense that behavior will stabilize on a low
|
||||
// estimate of wastage after a commit removes all transaction updates.)
|
||||
//
|
||||
// Some db formats might attempt to keep a very accurate reckoning of free
|
||||
// space size, so a very accurate determination can be made. But other db
|
||||
// formats might have difficulty determining size of free space, and might
|
||||
// require some lengthy calculation to answer. This is the reason for
|
||||
// passing in the percentage threshold of interest, so that such lengthy
|
||||
// computations can terminate early as soon as at least inPercentWaste is
|
||||
// found, so that the entire file need not be groveled when unnecessary.
|
||||
// However, we hope implementations will always favor fast but imprecise
|
||||
// heuristic answers instead of extremely slow but very precise answers.
|
||||
//
|
||||
// If the outActualWaste parameter is non-nil, it will be used to return
|
||||
// the actual estimated space wasted as a percentage of file size. (This
|
||||
// parameter is provided so callers need not call repeatedly with altered
|
||||
// inPercentWaste values to isolate the actual wastage figure.) Note the
|
||||
// actual wastage figure returned can exactly equal inPercentWaste even
|
||||
// when this grossly underestimates the real figure involved, if the db
|
||||
// finds it very expensive to determine the extent of wastage after it is
|
||||
// known to at least exceed inPercentWaste. Note we expect that whenever
|
||||
// outShould returns true, that outActualWaste returns >= inPercentWaste.
|
||||
//
|
||||
// The effect of different inPercentWaste values is not very uniform over
|
||||
// the permitted range. For example, 50 represents 50% wastage, or a file
|
||||
// that is about double what it should be ideally. But 99 represents 99%
|
||||
// wastage, or a file that is about ninety-nine times as big as it should
|
||||
// be ideally. In the smaller direction, 25 represents 25% wastage, or
|
||||
// a file that is only 33% larger than it should be ideally.
|
||||
//
|
||||
// Callers can determine what policy they want to use for considering when
|
||||
// a file holds too much wasted space, and express this as a percentage
|
||||
// of total file size to pass as in the inPercentWaste parameter. A zero
|
||||
// likely returns always trivially true, and 100 always trivially false.
|
||||
// The great majority of callers are expected to use values from 25 to 75,
|
||||
// since most plausible thresholds for compressing might fall between the
|
||||
// extremes of 133% of ideal size and 400% of ideal size. (Presumably the
|
||||
// larger a file gets, the more important the percentage waste involved, so
|
||||
// a sliding scale for compress thresholds might use smaller numbers for
|
||||
// much bigger file sizes.)
|
||||
|
||||
// } ----- end commit methods -----
|
||||
|
||||
// } ===== end nsIMdbPort methods =====
|
||||
|
||||
// { ===== begin nsIMdbStore methods =====
|
||||
|
|
|
@ -315,8 +315,11 @@ orkinTable::BecomeContent(nsIMdbEnv* mev,
|
|||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table;
|
||||
table = (morkTable*) mHandle_Object;
|
||||
// remember table->MaybeDirtySpaceStoreAndTable();
|
||||
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
MORK_USED_1(table);
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -347,6 +350,99 @@ orkinTable::DropActivity( // tell collection usage no longer expected
|
|||
// { ===== begin nsIMdbTable methods =====
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::SetTablePriority(nsIMdbEnv* mev, mdb_priority inPrio)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
if ( inPrio > morkPriority_kMax )
|
||||
inPrio = morkPriority_kMax;
|
||||
|
||||
table->mTable_Priority = inPrio;
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::GetTablePriority(nsIMdbEnv* mev, mdb_priority* outPrio)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mork_priority prio = 0;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
prio = table->mTable_Priority;
|
||||
if ( prio > morkPriority_kMax )
|
||||
{
|
||||
prio = morkPriority_kMax;
|
||||
table->mTable_Priority = prio;
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outPrio )
|
||||
*outPrio = prio;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable:: GetTableBeVerbose(nsIMdbEnv* mev, mdb_bool* outBeVerbose)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_bool beVerbose = morkBool_kFalse;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
beVerbose = table->IsTableVerbose();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outBeVerbose )
|
||||
*outBeVerbose = beVerbose;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::SetTableBeVerbose(nsIMdbEnv* mev, mdb_bool inBeVerbose)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
if ( inBeVerbose )
|
||||
table->SetTableVerbose();
|
||||
else
|
||||
table->ClearTableVerbose();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::GetTableIsUnique(nsIMdbEnv* mev, mdb_bool* outIsUnique)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_bool isUnique = morkBool_kFalse;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table = (morkTable*) mHandle_Object;
|
||||
isUnique = table->IsTableUnique();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outIsUnique )
|
||||
*outIsUnique = isUnique;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::GetTableKind(nsIMdbEnv* mev, mdb_kind* outTableKind)
|
||||
{
|
||||
|
@ -731,6 +827,20 @@ orkinTable::CutRow( // make sure the row with inOid is not a member
|
|||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinTable::CutAllRows( // remove all rows from the table
|
||||
nsIMdbEnv* mev) // context
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
((morkTable*) mHandle_Object)->CutAllRows(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end row set methods -----
|
||||
|
||||
// { ----- begin searching methods -----
|
||||
|
@ -1021,6 +1131,8 @@ orkinTable::MoveOid( // change position of row in unsorted table
|
|||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
// remember table->MaybeDirtySpaceStoreAndTable();
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
@ -1043,6 +1155,8 @@ orkinTable::MoveRow( // change position of row in unsorted table
|
|||
morkEnv* ev = this->CanUseTable(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
// remember table->MaybeDirtySpaceStoreAndTable();
|
||||
|
||||
ev->StubMethodOnlyError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
|
|
@ -165,6 +165,14 @@ public: // type identification
|
|||
// { ===== begin nsIMdbTable methods =====
|
||||
|
||||
// { ----- begin meta attribute methods -----
|
||||
virtual mdb_err SetTablePriority(nsIMdbEnv* ev, mdb_priority inPrio);
|
||||
virtual mdb_err GetTablePriority(nsIMdbEnv* ev, mdb_priority* outPrio);
|
||||
|
||||
virtual mdb_err GetTableBeVerbose(nsIMdbEnv* ev, mdb_bool* outBeVerbose);
|
||||
virtual mdb_err SetTableBeVerbose(nsIMdbEnv* ev, mdb_bool inBeVerbose);
|
||||
|
||||
virtual mdb_err GetTableIsUnique(nsIMdbEnv* ev, mdb_bool* outIsUnique);
|
||||
|
||||
virtual mdb_err GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind);
|
||||
virtual mdb_err GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope);
|
||||
|
||||
|
@ -260,6 +268,9 @@ public: // type identification
|
|||
virtual mdb_err CutRow( // make sure the row with inOid is not a member
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioRow); // row to remove from table
|
||||
|
||||
virtual mdb_err CutAllRows( // remove all rows from the table
|
||||
nsIMdbEnv* ev); // context
|
||||
// } ----- end row set methods -----
|
||||
|
||||
// { ----- begin searching methods -----
|
||||
|
|
Загрузка…
Ссылка в новой задаче