incremental writing, memory leak fixed for davidmc

This commit is contained in:
bienvenu%netscape.com 1999-07-14 15:52:46 +00:00
Родитель 033a49841f
Коммит 3d0e42f707
96 изменённых файлов: 7018 добавлений и 1070 удалений

Просмотреть файл

@ -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 =====
};
@ -949,6 +1005,12 @@ public:
nsIMdbEnv* ev, // context
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
@ -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

Просмотреть файл

@ -132,6 +132,11 @@ morkBuilder::morkBuilder(morkEnv* ev,
, mBuilder_TableRowScope( (mork_scope) 'r' )
, 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' )
@ -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
@ -375,19 +411,27 @@ 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,59 +454,79 @@ 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;
morkStore* store = mBuilder_Store;
if ( !inMid.mMid_Buf && !inMid.mMid_Oid.mOid_Scope )
{
mBuilder_CellForm = mBuilder_RowForm = mBuilder_TableForm;
mBuilder_CellAtomScope = mBuilder_RowAtomScope = mBuilder_TableAtomScope;
mBuilder_RowRowScope = mBuilder_TableRowScope;
morkStore* store = mBuilder_Store;
if ( !inMid.mMid_Buf && !inMid.mMid_Oid.mOid_Scope )
{
morkMid mid(inMid);
mid.mMid_Oid.mOid_Scope = mBuilder_RowRowScope;
mBuilder_Row = store->MidToRow(ev, mid);
}
else
{
mBuilder_Row = store->MidToRow(ev, inMid);
}
morkMid mid(inMid);
mid.mMid_Oid.mOid_Scope = mBuilder_RowRowScope;
mBuilder_Row = store->MidToRow(ev, mid);
}
else
{
mBuilder_Row = store->MidToRow(ev, inMid);
}
morkRow* row = mBuilder_Row;
if ( row && inCutAllCols )
{
row->CutAllColumns(ev);
}
morkRow* row = mBuilder_Row;
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
table->AddRow(ev, row);
{
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;
@ -749,14 +831,58 @@ morkBuilder::OnValue(morkEnv* ev, const morkSpan& inSpan,
mork_token* metaSlot = mBuilder_MetaTokenSlot;
if ( metaSlot )
{
mork_token token = store->BufToToken(ev, &inBuf);
if ( token )
if ( metaSlot == &mBuilder_TableStatus ) // table status?
{
*metaSlot = token;
if ( metaSlot == &mBuilder_TableKind ) // table kind?
if ( mParser_InTable && mBuilder_Table )
{
if ( mParser_InTable && mBuilder_Table )
mBuilder_Table->mTable_Kind = token;
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 )
{
*metaSlot = token;
if ( metaSlot == &mBuilder_TableKind ) // table kind?
{
if ( mParser_InTable && mBuilder_Table )
mBuilder_Table->mTable_Kind = token;
}
}
}
}
@ -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()
{

Просмотреть файл

@ -60,8 +60,18 @@ public:
mork_column GetColumn() const { return morkDelta_Column(mCell_Delta); }
mork_change GetChange() const { return morkDelta_Change(mCell_Delta); }
mork_bool IsCellClean() const { return GetChange() == morkChange_kNil; }
mork_bool IsCellDirty() const { return GetChange() != morkChange_kNil; }
void SetCellDirty();
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; }
@ -62,8 +142,19 @@ public:
void Remove()
{
(mLink_Prev->mLink_Next = mLink_Next)->mLink_Prev = mLink_Prev;
(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??
@ -158,6 +161,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
@ -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()
{
@ -419,7 +464,7 @@ morkEnv::FromMdbEnv(nsIMdbEnv* ioEnv) // dynamic type checking
if ( oenv->IsOpenNode() )
{
morkEnv* ev = (morkEnv*) oenv->mHandle_Object;
if ( ev && ev->IsEnv() )
if ( ev && ev->IsEnv() )
{
if ( ev->DoAutoClear() )
{

Просмотреть файл

@ -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,8 +391,9 @@ morkStdioFile::CreateNewStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
}
/*public virtual*/ void
morkStdioFile:: BecomeTrunk(morkEnv* ev)
morkStdioFile::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
// file's content, typically by assuming the original file's identity.
@ -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)
@ -48,6 +70,8 @@ protected: // protected morkFile members (similar to public domain IronDoc)
nsIMdbHeap* mFile_SlotHeap; // heap for Name and other allocated slots
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
@ -91,6 +115,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(),
@ -126,6 +161,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'; }
@ -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*/
@ -339,13 +341,32 @@ morkNode::CloseNode(morkEnv* ev) // called by CloseMorkNode();
ev->NilPointerError();
}
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");
@ -687,12 +701,20 @@ 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,28 +1018,166 @@ 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? '>'
// zm:DictItem ::= zm:MetaDict | zm:Alias
@ -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
mork_u2
morkRow::AddTableUse(morkEnv* ev)
// notifications regarding row changes:
void morkRow::NoteRowAddCol(morkEnv* ev, mork_column inColumn)
{
if ( this->IsRow() )
if ( !this->IsRowRewrite() )
{
if ( mRow_TableUses < morkRow_kMaxTableUses ) // not already maxed out?
++mRow_TableUses;
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->NonRowTypeError(ev);
this->ClearRowDelta();
}
void morkRow::NoteRowCutCol(morkEnv* ev, mork_column inColumn)
{
if ( !this->IsRowRewrite() )
{
mork_delta newDelta;
morkDelta_Init(newDelta, inColumn, morkChange_kCut);
return mRow_TableUses;
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::CutTableUse(morkEnv* ev)
morkRow::AddRowGcUse(morkEnv* ev)
{
if ( this->IsRow() )
{
if ( mRow_TableUses ) // any outstanding uses to cut?
{
if ( mRow_TableUses < morkRow_kMaxTableUses ) // not frozen at max?
--mRow_TableUses;
}
else
this->TableUsesUnderflowWarning(ev);
if ( mRow_GcUses < morkRow_kMaxGcUses ) // not already maxed out?
++mRow_GcUses;
}
else
this->NonRowTypeError(ev);
return mRow_TableUses;
return mRow_GcUses;
}
mork_u2
morkRow::CutRowGcUse(morkEnv* ev)
{
if ( this->IsRow() )
{
if ( mRow_GcUses ) // any outstanding uses to cut?
{
if ( mRow_GcUses < morkRow_kMaxGcUses ) // not frozen at max?
--mRow_GcUses;
}
else
this->GcUsesUnderflowWarning(ev);
}
else
this->NonRowTypeError(ev);
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);
@ -181,7 +247,7 @@ morkRow::AcquireRowObject(morkEnv* ev, morkStore* ioStore)
else
{
nsIMdbHeap* heap = ioStore->mPort_Heap;
ro = new (*heap, ev)
ro = new(*heap, ev)
morkRowObject(ev, morkUsage::kHeap, heap, this, ioStore);
morkRowObject::SlotWeakRowObject(ro, ev, &mRow_Object);
@ -207,7 +273,7 @@ morkRow::AcquireCellHandle(morkEnv* ev, morkCell* ioCell,
mdb_column inCol, mork_pos inPos)
{
nsIMdbHeap* heap = ev->mEnv_Heap;
morkCellObject* cellObj = new (*heap, ev)
morkCellObject* cellObj = new(*heap, ev)
morkCellObject(ev, morkUsage::kHeap, heap, this, ioCell, inCol, inPos);
if ( cellObj )
{
@ -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();
@ -742,7 +855,7 @@ morkRow::NewRowCellCursor(morkEnv* ev, mdb_pos inPos)
if ( rowObj )
{
nsIMdbHeap* heap = store->mPort_Heap;
morkRowCellCursor* cursor = new (*heap, ev)
morkRowCellCursor* cursor = new(*heap, ev)
morkRowCellCursor(ev, morkUsage::kHeap, heap, rowObj);
if ( cursor )

Просмотреть файл

@ -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
@ -43,14 +50,58 @@ public: // state is public because the entire Mork system is private
morkRowObject* mRow_Object; // refcount & other state for object sharing
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_Tag; // one-byte tag (need u4 alignment pad)
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;
}
@ -515,22 +533,31 @@ morkRowSpace::NewRowWithOid(morkEnv* ev, const mdbOid* inOid)
MORK_ASSERT(outRow==0);
if ( !outRow && ev->Good() )
{
morkPool* pool = this->GetSpaceStorePool();
morkRow* row = pool->NewRow(ev);
if ( row )
morkStore* store = mSpace_Store;
if ( store )
{
row->InitRow(ev, inOid, this, /*length*/ 0, pool);
if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) )
morkPool* pool = this->GetSpaceStorePool();
morkRow* row = pool->NewRow(ev);
if ( row )
{
outRow = row;
mork_rid rid = inOid->mOid_Id;
if ( mRowSpace_NextRowId <= rid )
mRowSpace_NextRowId = rid + 1;
row->InitRow(ev, inOid, this, /*length*/ 0, pool);
if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) )
{
outRow = row;
mork_rid rid = inOid->mOid_Id;
if ( mRowSpace_NextRowId <= rid )
mRowSpace_NextRowId = rid + 1;
}
else
pool->ZapRow(ev, row);
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
this->MaybeDirtyStoreAndSpace(); // InitRow() does already
}
else
pool->ZapRow(ev, row);
}
else
this->NilSpaceStoreError(ev);
}
return outRow;
}
@ -544,25 +571,35 @@ morkRowSpace::NewRow(morkEnv* ev)
mork_rid id = this->MakeNewRowId(ev);
if ( id )
{
mdbOid oid;
oid.mOid_Scope = mSpace_Scope;
oid.mOid_Id = id;
morkPool* pool = this->GetSpaceStorePool();
morkRow* row = pool->NewRow(ev);
if ( row )
morkStore* store = mSpace_Store;
if ( store )
{
row->InitRow(ev, &oid, this, /*length*/ 0, pool);
if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) )
outRow = row;
else
pool->ZapRow(ev, row);
mdbOid oid;
oid.mOid_Scope = mSpace_Scope;
oid.mOid_Id = id;
morkPool* pool = this->GetSpaceStorePool();
morkRow* row = pool->NewRow(ev);
if ( row )
{
row->InitRow(ev, &oid, this, /*length*/ 0, pool);
if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) )
outRow = row;
else
pool->ZapRow(ev, row);
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' */
@ -81,7 +85,7 @@ class morkRowSpace : public morkSpace { //
// 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_u1 mSpace_Pad[ 2 ]; // pad to u4 alignment
public: // state is public because the entire Mork system is private
@ -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
@ -83,8 +91,11 @@ public: // dynamic type identification
// } ===== end morkNode methods =====
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,7 +714,10 @@ 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() )
{
@ -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
// 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.
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: // coping with any changes to store token slots above:
public: // setting dirty based on CanDirty:
// void SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom,
// const mdbOid* inOid);
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,7 +138,13 @@ 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,25 +416,87 @@ 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 )
{
// okay, anything else?
if ( mTable_RowMap->AddRow(ev, ioRow) )
{
// okay, anything else?
}
else
mTable_RowArray.CutSlot(ev, pos);
}
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,16 +109,66 @@ 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
virtual void CloseMorkNode(morkEnv* ev); // CloseTable() if open
@ -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,7 +246,8 @@ 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);
public: // typesafe refcounting inlines calling inherited morkNode methods
@ -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);
@ -145,10 +146,13 @@ public: // other thumb methods
public: // assorted thumb constructors
static morkThumb* Make_OpenFileStore(morkEnv* ev,
nsIMdbHeap* ioHeap,morkStore* ioStore);
nsIMdbHeap* ioHeap, morkStore* ioStore);
static morkThumb* Make_CompressCommit(morkEnv* ev,
nsIMdbHeap* ioHeap,morkStore* ioStore, mork_bool inDoCollect);
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,

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

Просмотреть файл

@ -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)
@ -128,6 +130,13 @@ public: // state is public because the entire Mork system is private
morkFile* mWriter_Bud; // strong ref to bud of mWriter_File
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,12 +158,19 @@ 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_u1 mWriter_Pad[ 3 ]; // for u4 alignment
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,10 +333,10 @@ public: // other writer methods
mork_token inValue);
// Note inCol should begin with '(' and end with '=', with col in between.
void StartDict(morkEnv* ev);
void StartDict(morkEnv* ev);
void EndDict(morkEnv* ev);
void StartTable(morkEnv* ev, morkTable* ioTable);
void StartTable(morkEnv* ev, morkTable* ioTable);
void EndTable(morkEnv* ev);
public: // typesafe refcounting inlines calling inherited morkNode 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);
}
}
@ -555,7 +630,7 @@ orkinFactory::OpenFileStore( // open an existing database
if ( thumb )
{
outThumb = orkinThumb::MakeThumb(ev, thumb);
thumb->CutStrongRef(ev);
thumb->CutStrongRef(ev);
}
}
store->CutStrongRef(ev); // always cut ref (handle has its own ref)
@ -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;
mork_bool doCollect = morkBool_kFalse;
morkThumb* thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
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();
}
@ -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);
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 =====
};
@ -949,6 +1005,12 @@ public:
nsIMdbEnv* ev, // context
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
@ -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

Просмотреть файл

@ -132,6 +132,11 @@ morkBuilder::morkBuilder(morkEnv* ev,
, mBuilder_TableRowScope( (mork_scope) 'r' )
, 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' )
@ -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
@ -375,19 +411,27 @@ 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,59 +454,79 @@ 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;
morkStore* store = mBuilder_Store;
if ( !inMid.mMid_Buf && !inMid.mMid_Oid.mOid_Scope )
{
mBuilder_CellForm = mBuilder_RowForm = mBuilder_TableForm;
mBuilder_CellAtomScope = mBuilder_RowAtomScope = mBuilder_TableAtomScope;
mBuilder_RowRowScope = mBuilder_TableRowScope;
morkStore* store = mBuilder_Store;
if ( !inMid.mMid_Buf && !inMid.mMid_Oid.mOid_Scope )
{
morkMid mid(inMid);
mid.mMid_Oid.mOid_Scope = mBuilder_RowRowScope;
mBuilder_Row = store->MidToRow(ev, mid);
}
else
{
mBuilder_Row = store->MidToRow(ev, inMid);
}
morkMid mid(inMid);
mid.mMid_Oid.mOid_Scope = mBuilder_RowRowScope;
mBuilder_Row = store->MidToRow(ev, mid);
}
else
{
mBuilder_Row = store->MidToRow(ev, inMid);
}
morkRow* row = mBuilder_Row;
if ( row && inCutAllCols )
{
row->CutAllColumns(ev);
}
morkRow* row = mBuilder_Row;
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
table->AddRow(ev, row);
{
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;
@ -749,14 +831,58 @@ morkBuilder::OnValue(morkEnv* ev, const morkSpan& inSpan,
mork_token* metaSlot = mBuilder_MetaTokenSlot;
if ( metaSlot )
{
mork_token token = store->BufToToken(ev, &inBuf);
if ( token )
if ( metaSlot == &mBuilder_TableStatus ) // table status?
{
*metaSlot = token;
if ( metaSlot == &mBuilder_TableKind ) // table kind?
if ( mParser_InTable && mBuilder_Table )
{
if ( mParser_InTable && mBuilder_Table )
mBuilder_Table->mTable_Kind = token;
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 )
{
*metaSlot = token;
if ( metaSlot == &mBuilder_TableKind ) // table kind?
{
if ( mParser_InTable && mBuilder_Table )
mBuilder_Table->mTable_Kind = token;
}
}
}
}
@ -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()
{

Просмотреть файл

@ -60,8 +60,18 @@ public:
mork_column GetColumn() const { return morkDelta_Column(mCell_Delta); }
mork_change GetChange() const { return morkDelta_Change(mCell_Delta); }
mork_bool IsCellClean() const { return GetChange() == morkChange_kNil; }
mork_bool IsCellDirty() const { return GetChange() != morkChange_kNil; }
void SetCellDirty();
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; }
@ -62,8 +142,19 @@ public:
void Remove()
{
(mLink_Prev->mLink_Next = mLink_Next)->mLink_Prev = mLink_Prev;
(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??
@ -158,6 +161,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
@ -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()
{
@ -419,7 +464,7 @@ morkEnv::FromMdbEnv(nsIMdbEnv* ioEnv) // dynamic type checking
if ( oenv->IsOpenNode() )
{
morkEnv* ev = (morkEnv*) oenv->mHandle_Object;
if ( ev && ev->IsEnv() )
if ( ev && ev->IsEnv() )
{
if ( ev->DoAutoClear() )
{

Просмотреть файл

@ -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,8 +391,9 @@ morkStdioFile::CreateNewStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
}
/*public virtual*/ void
morkStdioFile:: BecomeTrunk(morkEnv* ev)
morkStdioFile::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
// file's content, typically by assuming the original file's identity.
@ -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)
@ -48,6 +70,8 @@ protected: // protected morkFile members (similar to public domain IronDoc)
nsIMdbHeap* mFile_SlotHeap; // heap for Name and other allocated slots
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
@ -91,6 +115,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(),
@ -126,6 +161,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'; }
@ -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*/
@ -339,13 +341,32 @@ morkNode::CloseNode(morkEnv* ev) // called by CloseMorkNode();
ev->NilPointerError();
}
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");
@ -687,12 +701,20 @@ 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,28 +1018,166 @@ 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? '>'
// zm:DictItem ::= zm:MetaDict | zm:Alias
@ -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
mork_u2
morkRow::AddTableUse(morkEnv* ev)
// notifications regarding row changes:
void morkRow::NoteRowAddCol(morkEnv* ev, mork_column inColumn)
{
if ( this->IsRow() )
if ( !this->IsRowRewrite() )
{
if ( mRow_TableUses < morkRow_kMaxTableUses ) // not already maxed out?
++mRow_TableUses;
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->NonRowTypeError(ev);
this->ClearRowDelta();
}
void morkRow::NoteRowCutCol(morkEnv* ev, mork_column inColumn)
{
if ( !this->IsRowRewrite() )
{
mork_delta newDelta;
morkDelta_Init(newDelta, inColumn, morkChange_kCut);
return mRow_TableUses;
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::CutTableUse(morkEnv* ev)
morkRow::AddRowGcUse(morkEnv* ev)
{
if ( this->IsRow() )
{
if ( mRow_TableUses ) // any outstanding uses to cut?
{
if ( mRow_TableUses < morkRow_kMaxTableUses ) // not frozen at max?
--mRow_TableUses;
}
else
this->TableUsesUnderflowWarning(ev);
if ( mRow_GcUses < morkRow_kMaxGcUses ) // not already maxed out?
++mRow_GcUses;
}
else
this->NonRowTypeError(ev);
return mRow_TableUses;
return mRow_GcUses;
}
mork_u2
morkRow::CutRowGcUse(morkEnv* ev)
{
if ( this->IsRow() )
{
if ( mRow_GcUses ) // any outstanding uses to cut?
{
if ( mRow_GcUses < morkRow_kMaxGcUses ) // not frozen at max?
--mRow_GcUses;
}
else
this->GcUsesUnderflowWarning(ev);
}
else
this->NonRowTypeError(ev);
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);
@ -181,7 +247,7 @@ morkRow::AcquireRowObject(morkEnv* ev, morkStore* ioStore)
else
{
nsIMdbHeap* heap = ioStore->mPort_Heap;
ro = new (*heap, ev)
ro = new(*heap, ev)
morkRowObject(ev, morkUsage::kHeap, heap, this, ioStore);
morkRowObject::SlotWeakRowObject(ro, ev, &mRow_Object);
@ -207,7 +273,7 @@ morkRow::AcquireCellHandle(morkEnv* ev, morkCell* ioCell,
mdb_column inCol, mork_pos inPos)
{
nsIMdbHeap* heap = ev->mEnv_Heap;
morkCellObject* cellObj = new (*heap, ev)
morkCellObject* cellObj = new(*heap, ev)
morkCellObject(ev, morkUsage::kHeap, heap, this, ioCell, inCol, inPos);
if ( cellObj )
{
@ -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();
@ -742,7 +855,7 @@ morkRow::NewRowCellCursor(morkEnv* ev, mdb_pos inPos)
if ( rowObj )
{
nsIMdbHeap* heap = store->mPort_Heap;
morkRowCellCursor* cursor = new (*heap, ev)
morkRowCellCursor* cursor = new(*heap, ev)
morkRowCellCursor(ev, morkUsage::kHeap, heap, rowObj);
if ( cursor )

Просмотреть файл

@ -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
@ -43,14 +50,58 @@ public: // state is public because the entire Mork system is private
morkRowObject* mRow_Object; // refcount & other state for object sharing
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_Tag; // one-byte tag (need u4 alignment pad)
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;
}
@ -515,22 +533,31 @@ morkRowSpace::NewRowWithOid(morkEnv* ev, const mdbOid* inOid)
MORK_ASSERT(outRow==0);
if ( !outRow && ev->Good() )
{
morkPool* pool = this->GetSpaceStorePool();
morkRow* row = pool->NewRow(ev);
if ( row )
morkStore* store = mSpace_Store;
if ( store )
{
row->InitRow(ev, inOid, this, /*length*/ 0, pool);
if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) )
morkPool* pool = this->GetSpaceStorePool();
morkRow* row = pool->NewRow(ev);
if ( row )
{
outRow = row;
mork_rid rid = inOid->mOid_Id;
if ( mRowSpace_NextRowId <= rid )
mRowSpace_NextRowId = rid + 1;
row->InitRow(ev, inOid, this, /*length*/ 0, pool);
if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) )
{
outRow = row;
mork_rid rid = inOid->mOid_Id;
if ( mRowSpace_NextRowId <= rid )
mRowSpace_NextRowId = rid + 1;
}
else
pool->ZapRow(ev, row);
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
this->MaybeDirtyStoreAndSpace(); // InitRow() does already
}
else
pool->ZapRow(ev, row);
}
else
this->NilSpaceStoreError(ev);
}
return outRow;
}
@ -544,25 +571,35 @@ morkRowSpace::NewRow(morkEnv* ev)
mork_rid id = this->MakeNewRowId(ev);
if ( id )
{
mdbOid oid;
oid.mOid_Scope = mSpace_Scope;
oid.mOid_Id = id;
morkPool* pool = this->GetSpaceStorePool();
morkRow* row = pool->NewRow(ev);
if ( row )
morkStore* store = mSpace_Store;
if ( store )
{
row->InitRow(ev, &oid, this, /*length*/ 0, pool);
if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) )
outRow = row;
else
pool->ZapRow(ev, row);
mdbOid oid;
oid.mOid_Scope = mSpace_Scope;
oid.mOid_Id = id;
morkPool* pool = this->GetSpaceStorePool();
morkRow* row = pool->NewRow(ev);
if ( row )
{
row->InitRow(ev, &oid, this, /*length*/ 0, pool);
if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) )
outRow = row;
else
pool->ZapRow(ev, row);
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' */
@ -81,7 +85,7 @@ class morkRowSpace : public morkSpace { //
// 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_u1 mSpace_Pad[ 2 ]; // pad to u4 alignment
public: // state is public because the entire Mork system is private
@ -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
@ -83,8 +91,11 @@ public: // dynamic type identification
// } ===== end morkNode methods =====
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,7 +714,10 @@ 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() )
{
@ -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
// 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.
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: // coping with any changes to store token slots above:
public: // setting dirty based on CanDirty:
// void SyncTokenIdChange(morkEnv* ev, const morkBookAtom* inAtom,
// const mdbOid* inOid);
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,7 +138,13 @@ 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,25 +416,87 @@ 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 )
{
// okay, anything else?
if ( mTable_RowMap->AddRow(ev, ioRow) )
{
// okay, anything else?
}
else
mTable_RowArray.CutSlot(ev, pos);
}
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,16 +109,66 @@ 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
virtual void CloseMorkNode(morkEnv* ev); // CloseTable() if open
@ -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,7 +246,8 @@ 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);
public: // typesafe refcounting inlines calling inherited morkNode methods
@ -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);
@ -145,10 +146,13 @@ public: // other thumb methods
public: // assorted thumb constructors
static morkThumb* Make_OpenFileStore(morkEnv* ev,
nsIMdbHeap* ioHeap,morkStore* ioStore);
nsIMdbHeap* ioHeap, morkStore* ioStore);
static morkThumb* Make_CompressCommit(morkEnv* ev,
nsIMdbHeap* ioHeap,morkStore* ioStore, mork_bool inDoCollect);
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,

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

Просмотреть файл

@ -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)
@ -128,6 +130,13 @@ public: // state is public because the entire Mork system is private
morkFile* mWriter_Bud; // strong ref to bud of mWriter_File
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,12 +158,19 @@ 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_u1 mWriter_Pad[ 3 ]; // for u4 alignment
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,10 +333,10 @@ public: // other writer methods
mork_token inValue);
// Note inCol should begin with '(' and end with '=', with col in between.
void StartDict(morkEnv* ev);
void StartDict(morkEnv* ev);
void EndDict(morkEnv* ev);
void StartTable(morkEnv* ev, morkTable* ioTable);
void StartTable(morkEnv* ev, morkTable* ioTable);
void EndTable(morkEnv* ev);
public: // typesafe refcounting inlines calling inherited morkNode 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);
}
}
@ -555,7 +630,7 @@ orkinFactory::OpenFileStore( // open an existing database
if ( thumb )
{
outThumb = orkinThumb::MakeThumb(ev, thumb);
thumb->CutStrongRef(ev);
thumb->CutStrongRef(ev);
}
}
store->CutStrongRef(ev); // always cut ref (handle has its own ref)
@ -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;
mork_bool doCollect = morkBool_kFalse;
morkThumb* thumb = morkThumb::Make_CompressCommit(ev, heap, store, doCollect);
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();
}
@ -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);
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 -----