Back to index

lightning-sunbird  0.9+nobinonly
morkStore.h
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifndef _MORKSTORE_
00039 #define _MORKSTORE_ 1
00040 
00041 #ifndef _MORK_
00042 #include "mork.h"
00043 #endif
00044 
00045 #ifndef _MORKOBJECT_
00046 #include "morkObject.h"
00047 #endif
00048 
00049 #ifndef _MORKNODEMAP_
00050 #include "morkNodeMap.h"
00051 #endif
00052 
00053 #ifndef _MORKPOOL_
00054 #include "morkPool.h"
00055 #endif
00056 
00057 #ifndef _MORKZONE_
00058 #include "morkZone.h"
00059 #endif
00060 
00061 #ifndef _MORKATOM_
00062 #include "morkAtom.h"
00063 #endif
00064 
00065 #ifndef _MORKROWSPACE_
00066 #include "morkRowSpace.h"
00067 #endif
00068 
00069 #ifndef _MORKATOMSPACE_
00070 #include "morkAtomSpace.h"
00071 #endif
00072 
00073 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00074 
00075 #define morkDerived_kPort  /*i*/ 0x7054 /* ascii 'pT' */
00076 
00077 #define morkDerived_kStore  /*i*/ 0x7354 /* ascii 'sT' */
00078 
00079 /*| kGroundColumnSpace: we use the 'column space' as the default scope
00080 **| for grounding column name IDs, and this is also the default scope for
00081 **| all other explicitly tokenized strings.
00082 |*/
00083 #define morkStore_kGroundColumnSpace 'c' /* for mStore_GroundColumnSpace*/
00084 #define morkStore_kColumnSpaceScope ((mork_scope) 'c') /*kGroundColumnSpace*/
00085 #define morkStore_kValueSpaceScope ((mork_scope) 'v')
00086 #define morkStore_kStreamBufSize (8 * 1024) /* okay buffer size */
00087 
00088 #define morkStore_kReservedColumnCount 0x20 /* for well-known columns */
00089 
00090 #define morkStore_kNoneToken ((mork_token) 'n')
00091 #define morkStore_kFormColumn ((mork_column) 'f')
00092 #define morkStore_kAtomScopeColumn ((mork_column) 'a')
00093 #define morkStore_kRowScopeColumn ((mork_column) 'r')
00094 #define morkStore_kMetaScope ((mork_scope) 'm')
00095 #define morkStore_kKindColumn ((mork_column) 'k')
00096 #define morkStore_kStatusColumn ((mork_column) 's')
00097 
00098 /*| morkStore: 
00099 |*/
00100 class morkStore :  public morkObject, public nsIMdbStore {
00101 
00102 public: // state is public because the entire Mork system is private
00103 
00104   NS_DECL_ISUPPORTS_INHERITED
00105 
00106   morkEnv*        mPort_Env;      // non-refcounted env which created port
00107   morkFactory*    mPort_Factory;  // weak ref to suite factory
00108   nsIMdbHeap*     mPort_Heap;     // heap in which this port allocs objects
00109   
00110 // { ===== begin morkNode interface =====
00111 public: // morkNode virtual methods
00112   
00113   void ClosePort(morkEnv* ev); // called by CloseMorkNode();
00114 
00115 public: // dynamic type identification
00116   mork_bool IsPort() const
00117   { return IsNode() && mNode_Derived == morkDerived_kPort; }
00118 // } ===== end morkNode methods =====
00119 
00120 public: // other port methods
00121 
00122   // { ----- begin attribute methods -----
00123 //  NS_IMETHOD IsFrozenMdbObject(nsIMdbEnv* ev, mdb_bool* outIsReadonly);
00124   // same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port.
00125   // } ----- end attribute methods -----
00126 
00127   // { ----- begin factory methods -----
00128 //  NS_IMETHOD GetMdbFactory(nsIMdbEnv* ev, nsIMdbFactory** acqFactory); 
00129   // } ----- end factory methods -----
00130 
00131   // { ----- begin ref counting for well-behaved cyclic graphs -----
00132   NS_IMETHOD GetWeakRefCount(nsIMdbEnv* ev, // weak refs
00133     mdb_count* outCount);  
00134   NS_IMETHOD GetStrongRefCount(nsIMdbEnv* ev, // strong refs
00135     mdb_count* outCount);
00136 
00137   NS_IMETHOD AddWeakRef(nsIMdbEnv* ev);
00138   NS_IMETHOD AddStrongRef(nsIMdbEnv* ev);
00139 
00140   NS_IMETHOD CutWeakRef(nsIMdbEnv* ev);
00141   NS_IMETHOD CutStrongRef(nsIMdbEnv* ev);
00142   
00143   NS_IMETHOD CloseMdbObject(nsIMdbEnv* ev); // called at strong refs zero
00144   NS_IMETHOD IsOpenMdbObject(nsIMdbEnv* ev, mdb_bool* outOpen);
00145   // } ----- end ref counting -----
00146   
00147 // } ===== end nsIMdbObject methods =====
00148 
00149 // { ===== begin nsIMdbPort methods =====
00150 
00151   // { ----- begin attribute methods -----
00152   NS_IMETHOD GetIsPortReadonly(nsIMdbEnv* ev, mdb_bool* outBool);
00153   NS_IMETHOD GetIsStore(nsIMdbEnv* ev, mdb_bool* outBool);
00154   NS_IMETHOD GetIsStoreAndDirty(nsIMdbEnv* ev, mdb_bool* outBool);
00155 
00156   NS_IMETHOD GetUsagePolicy(nsIMdbEnv* ev, 
00157     mdbUsagePolicy* ioUsagePolicy);
00158 
00159   NS_IMETHOD SetUsagePolicy(nsIMdbEnv* ev, 
00160     const mdbUsagePolicy* inUsagePolicy);
00161   // } ----- end attribute methods -----
00162 
00163   // { ----- begin memory policy methods -----  
00164   NS_IMETHOD IdleMemoryPurge( // do memory management already scheduled
00165     nsIMdbEnv* ev, // context
00166     mdb_size* outEstimatedBytesFreed); // approximate bytes actually freed
00167 
00168   NS_IMETHOD SessionMemoryPurge( // request specific footprint decrease
00169     nsIMdbEnv* ev, // context
00170     mdb_size inDesiredBytesFreed, // approximate number of bytes wanted
00171     mdb_size* outEstimatedBytesFreed); // approximate bytes actually freed
00172 
00173   NS_IMETHOD PanicMemoryPurge( // desperately free all possible memory
00174     nsIMdbEnv* ev, // context
00175     mdb_size* outEstimatedBytesFreed); // approximate bytes actually freed
00176   // } ----- end memory policy methods -----
00177 
00178   // { ----- begin filepath methods -----
00179   NS_IMETHOD GetPortFilePath(
00180     nsIMdbEnv* ev, // context
00181     mdbYarn* outFilePath, // name of file holding port content
00182     mdbYarn* outFormatVersion); // file format description
00183 
00184   NS_IMETHOD GetPortFile(
00185     nsIMdbEnv* ev, // context
00186     nsIMdbFile** acqFile); // acquire file used by port or store
00187   // } ----- end filepath methods -----
00188 
00189   // { ----- begin export methods -----
00190   NS_IMETHOD BestExportFormat( // determine preferred export format
00191     nsIMdbEnv* ev, // context
00192     mdbYarn* outFormatVersion); // file format description
00193 
00194   NS_IMETHOD
00195   CanExportToFormat( // can export content in given specific format?
00196     nsIMdbEnv* ev, // context
00197     const char* inFormatVersion, // file format description
00198     mdb_bool* outCanExport); // whether ExportSource() might succeed
00199 
00200   NS_IMETHOD ExportToFormat( // export content in given specific format
00201     nsIMdbEnv* ev, // context
00202     // const char* inFilePath, // the file to receive exported content
00203     nsIMdbFile* ioFile, // destination abstract file interface
00204     const char* inFormatVersion, // file format description
00205     nsIMdbThumb** acqThumb); // acquire thumb for incremental export
00206   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
00207   // then the export will be finished.
00208 
00209   // } ----- end export methods -----
00210 
00211   // { ----- begin token methods -----
00212   NS_IMETHOD TokenToString( // return a string name for an integer token
00213     nsIMdbEnv* ev, // context
00214     mdb_token inToken, // token for inTokenName inside this port
00215     mdbYarn* outTokenName); // the type of table to access
00216   
00217   NS_IMETHOD StringToToken( // return an integer token for scope name
00218     nsIMdbEnv* ev, // context
00219     const char* inTokenName, // Latin1 string to tokenize if possible
00220     mdb_token* outToken); // token for inTokenName inside this port
00221     
00222   // String token zero is never used and never supported. If the port
00223   // is a mutable store, then StringToToken() to create a new
00224   // association of inTokenName with a new integer token if possible.
00225   // But a readonly port will return zero for an unknown scope name.
00226 
00227   NS_IMETHOD QueryToken( // like StringToToken(), but without adding
00228     nsIMdbEnv* ev, // context
00229     const char* inTokenName, // Latin1 string to tokenize if possible
00230     mdb_token* outToken); // token for inTokenName inside this port
00231   
00232   // QueryToken() will return a string token if one already exists,
00233   // but unlike StringToToken(), will not assign a new token if not
00234   // already in use.
00235 
00236   // } ----- end token methods -----
00237 
00238   // { ----- begin row methods -----  
00239   NS_IMETHOD HasRow( // contains a row with the specified oid?
00240     nsIMdbEnv* ev, // context
00241     const mdbOid* inOid,  // hypothetical row oid
00242     mdb_bool* outHasRow); // whether GetRow() might succeed
00243 
00244   NS_IMETHOD GetRowRefCount( // get number of tables that contain a row 
00245     nsIMdbEnv* ev, // context
00246     const mdbOid* inOid,  // hypothetical row oid
00247     mdb_count* outRefCount); // number of tables containing inRowKey 
00248     
00249   NS_IMETHOD GetRow( // access one row with specific oid
00250     nsIMdbEnv* ev, // context
00251     const mdbOid* inOid,  // hypothetical row oid
00252     nsIMdbRow** acqRow); // acquire specific row (or null)
00253 
00254   NS_IMETHOD FindRow(nsIMdbEnv* ev, // search for row with matching cell
00255     mdb_scope inRowScope,   // row scope for row ids
00256     mdb_column inColumn,   // the column to search (and maintain an index)
00257     const mdbYarn* inTargetCellValue, // cell value for which to search
00258     mdbOid* outRowOid, // out row oid on match (or {0,-1} for no match)
00259     nsIMdbRow** acqRow); // acquire matching row (or nil for no match)
00260                          // can be null if you only want the oid
00261   // FindRow() searches for one row that has a cell in column inColumn with
00262   // a contained value with the same form (i.e. charset) and is byte-wise
00263   // identical to the blob described by yarn inTargetCellValue.  Both content
00264   // and form of the yarn must be an exact match to find a matching row.
00265   //
00266   // (In other words, both a yarn's blob bytes and form are significant.  The
00267   // form is not expected to vary in columns used for identity anyway.  This
00268   // is intended to make the cost of FindRow() cheaper for MDB implementors,
00269   // since any cell value atomization performed internally must necessarily
00270   // make yarn form significant in order to avoid data loss in atomization.)
00271   //
00272   // FindRow() can lazily create an index on attribute inColumn for all rows
00273   // with that attribute in row space scope inRowScope, so that subsequent
00274   // calls to FindRow() will perform faster.  Such an index might or might
00275   // not be persistent (but this seems desirable if it is cheap to do so).
00276   // Note that lazy index creation in readonly DBs is not very feasible.
00277   //
00278   // This FindRow() interface assumes that attribute inColumn is effectively
00279   // an alternative means of unique identification for a row in a rowspace,
00280   // so correct behavior is only guaranteed when no duplicates for this col
00281   // appear in the given set of rows.  (If more than one row has the same cell
00282   // value in this column, no more than one will be found; and cutting one of
00283   // two duplicate rows can cause the index to assume no other such row lives
00284   // in the row space, so future calls return nil for negative search results
00285   // even though some duplicate row might still live within the rowspace.)
00286   //
00287   // In other words, the FindRow() implementation is allowed to assume simple
00288   // hash tables mapping unqiue column keys to associated row values will be
00289   // sufficient, where any duplication is not recorded because only one copy
00290   // of a given key need be remembered.  Implementors are not required to sort
00291   // all rows by the specified column.
00292   // } ----- end row methods -----
00293 
00294   // { ----- begin table methods -----  
00295   NS_IMETHOD HasTable( // supports a table with the specified oid?
00296     nsIMdbEnv* ev, // context
00297     const mdbOid* inOid,  // hypothetical table oid
00298     mdb_bool* outHasTable); // whether GetTable() might succeed
00299     
00300   NS_IMETHOD GetTable( // access one table with specific oid
00301     nsIMdbEnv* ev, // context
00302     const mdbOid* inOid,  // hypothetical table oid
00303     nsIMdbTable** acqTable); // acquire specific table (or null)
00304   
00305   NS_IMETHOD HasTableKind( // supports a table of the specified type?
00306     nsIMdbEnv* ev, // context
00307     mdb_scope inRowScope, // rid scope for row ids
00308     mdb_kind inTableKind, // the type of table to access
00309     mdb_count* outTableCount, // current number of such tables
00310     mdb_bool* outSupportsTable); // whether GetTableKind() might succeed
00311         
00312   NS_IMETHOD GetTableKind( // access one (random) table of specific type
00313     nsIMdbEnv* ev, // context
00314     mdb_scope inRowScope,      // row scope for row ids
00315     mdb_kind inTableKind,      // the type of table to access
00316     mdb_count* outTableCount, // current number of such tables
00317     mdb_bool* outMustBeUnique, // whether port can hold only one of these
00318     nsIMdbTable** acqTable);       // acquire scoped collection of rows
00319     
00320   NS_IMETHOD
00321   GetPortTableCursor( // get cursor for all tables of specific type
00322     nsIMdbEnv* ev, // context
00323     mdb_scope inRowScope, // row scope for row ids
00324     mdb_kind inTableKind, // the type of table to access
00325     nsIMdbPortTableCursor** acqCursor); // all such tables in the port
00326   // } ----- end table methods -----
00327 
00328 
00329   // { ----- begin commit methods -----
00330 
00331   NS_IMETHOD ShouldCompress( // store wastes at least inPercentWaste?
00332     nsIMdbEnv* ev, // context
00333     mdb_percent inPercentWaste, // 0..100 percent file size waste threshold
00334     mdb_percent* outActualWaste, // 0..100 percent of file actually wasted
00335     mdb_bool* outShould); // true when about inPercentWaste% is wasted
00336   // ShouldCompress() returns true if the store can determine that the file
00337   // will shrink by an estimated percentage of inPercentWaste% (or more) if
00338   // CompressCommit() is called, because that percentage of the file seems
00339   // to be recoverable free space.  The granularity is only in terms of 
00340   // percentage points, and any value over 100 is considered equal to 100.
00341   //
00342   // If a store only has an approximate idea how much space might be saved
00343   // during a compress, then a best guess should be made.  For example, the
00344   // Mork implementation might keep track of how much file space began with
00345   // text content before the first updating transaction, and then consider
00346   // all content following the start of the first transaction as potentially
00347   // wasted space if it is all updates and not just new content.  (This is
00348   // a safe assumption in the sense that behavior will stabilize on a low
00349   // estimate of wastage after a commit removes all transaction updates.)
00350   //
00351   // Some db formats might attempt to keep a very accurate reckoning of free
00352   // space size, so a very accurate determination can be made.  But other db
00353   // formats might have difficulty determining size of free space, and might
00354   // require some lengthy calculation to answer.  This is the reason for
00355   // passing in the percentage threshold of interest, so that such lengthy
00356   // computations can terminate early as soon as at least inPercentWaste is
00357   // found, so that the entire file need not be groveled when unnecessary.
00358   // However, we hope implementations will always favor fast but imprecise
00359   // heuristic answers instead of extremely slow but very precise answers.
00360   //
00361   // If the outActualWaste parameter is non-nil, it will be used to return
00362   // the actual estimated space wasted as a percentage of file size.  (This
00363   // parameter is provided so callers need not call repeatedly with altered
00364   // inPercentWaste values to isolate the actual wastage figure.)  Note the
00365   // actual wastage figure returned can exactly equal inPercentWaste even
00366   // when this grossly underestimates the real figure involved, if the db
00367   // finds it very expensive to determine the extent of wastage after it is
00368   // known to at least exceed inPercentWaste.  Note we expect that whenever
00369   // outShould returns true, that outActualWaste returns >= inPercentWaste.
00370   //
00371   // The effect of different inPercentWaste values is not very uniform over
00372   // the permitted range.  For example, 50 represents 50% wastage, or a file
00373   // that is about double what it should be ideally.  But 99 represents 99%
00374   // wastage, or a file that is about ninety-nine times as big as it should
00375   // be ideally.  In the smaller direction, 25 represents 25% wastage, or
00376   // a file that is only 33% larger than it should be ideally.
00377   //
00378   // Callers can determine what policy they want to use for considering when
00379   // a file holds too much wasted space, and express this as a percentage
00380   // of total file size to pass as in the inPercentWaste parameter.  A zero
00381   // likely returns always trivially true, and 100 always trivially false.
00382   // The great majority of callers are expected to use values from 25 to 75,
00383   // since most plausible thresholds for compressing might fall between the
00384   // extremes of 133% of ideal size and 400% of ideal size.  (Presumably the
00385   // larger a file gets, the more important the percentage waste involved, so
00386   // a sliding scale for compress thresholds might use smaller numbers for
00387   // much bigger file sizes.)
00388   
00389   // } ----- end commit methods -----
00390 
00391 // } ===== end nsIMdbPort methods =====
00392 
00393 // { ===== begin nsIMdbStore methods =====
00394 
00395   // { ----- begin table methods -----
00396   NS_IMETHOD NewTable( // make one new table of specific type
00397     nsIMdbEnv* ev, // context
00398     mdb_scope inRowScope,    // row scope for row ids
00399     mdb_kind inTableKind,    // the type of table to access
00400     mdb_bool inMustBeUnique, // whether store can hold only one of these
00401     const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
00402     nsIMdbTable** acqTable);     // acquire scoped collection of rows
00403     
00404   NS_IMETHOD NewTableWithOid( // make one new table of specific type
00405     nsIMdbEnv* ev, // context
00406     const mdbOid* inOid,   // caller assigned oid
00407     mdb_kind inTableKind,    // the type of table to access
00408     mdb_bool inMustBeUnique, // whether store can hold only one of these
00409     const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying 
00410     nsIMdbTable** acqTable);     // acquire scoped collection of rows
00411   // } ----- end table methods -----
00412 
00413   // { ----- begin row scope methods -----
00414   NS_IMETHOD RowScopeHasAssignedIds(nsIMdbEnv* ev,
00415     mdb_scope inRowScope,   // row scope for row ids
00416     mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
00417     mdb_bool* outStoreAssigned); // nonzero if store db assigned specified
00418 
00419   NS_IMETHOD SetCallerAssignedIds(nsIMdbEnv* ev,
00420     mdb_scope inRowScope,   // row scope for row ids
00421     mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
00422     mdb_bool* outStoreAssigned); // nonzero if store db assigned specified
00423 
00424   NS_IMETHOD SetStoreAssignedIds(nsIMdbEnv* ev,
00425     mdb_scope inRowScope,   // row scope for row ids
00426     mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
00427     mdb_bool* outStoreAssigned); // nonzero if store db assigned specified
00428   // } ----- end row scope methods -----
00429 
00430   // { ----- begin row methods -----
00431   NS_IMETHOD NewRowWithOid(nsIMdbEnv* ev, // new row w/ caller assigned oid
00432     const mdbOid* inOid,   // caller assigned oid
00433     nsIMdbRow** acqRow); // create new row
00434 
00435   NS_IMETHOD NewRow(nsIMdbEnv* ev, // new row with db assigned oid
00436     mdb_scope inRowScope,   // row scope for row ids
00437     nsIMdbRow** acqRow); // create new row
00438   // Note this row must be added to some table or cell child before the
00439   // store is closed in order to make this row persist across sesssions.
00440 
00441   // } ----- end row methods -----
00442 
00443   // { ----- begin inport/export methods -----
00444   NS_IMETHOD ImportContent( // import content from port
00445     nsIMdbEnv* ev, // context
00446     mdb_scope inRowScope, // scope for rows (or zero for all?)
00447     nsIMdbPort* ioPort, // the port with content to add to store
00448     nsIMdbThumb** acqThumb); // acquire thumb for incremental import
00449   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
00450   // then the import will be finished.
00451 
00452   NS_IMETHOD ImportFile( // import content from port
00453     nsIMdbEnv* ev, // context
00454     nsIMdbFile* ioFile, // the file with content to add to store
00455     nsIMdbThumb** acqThumb); // acquire thumb for incremental import
00456   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
00457   // then the import will be finished.
00458   // } ----- end inport/export methods -----
00459 
00460   // { ----- begin hinting methods -----
00461   NS_IMETHOD
00462   ShareAtomColumnsHint( // advise re shared column content atomizing
00463     nsIMdbEnv* ev, // context
00464     mdb_scope inScopeHint, // zero, or suggested shared namespace
00465     const mdbColumnSet* inColumnSet); // cols desired tokenized together
00466 
00467   NS_IMETHOD
00468   AvoidAtomColumnsHint( // advise column with poor atomizing prospects
00469     nsIMdbEnv* ev, // context
00470     const mdbColumnSet* inColumnSet); // cols with poor atomizing prospects
00471   // } ----- end hinting methods -----
00472 
00473   // { ----- begin commit methods -----
00474   NS_IMETHOD SmallCommit( // save minor changes if convenient and uncostly
00475     nsIMdbEnv* ev); // context
00476   
00477   NS_IMETHOD LargeCommit( // save important changes if at all possible
00478     nsIMdbEnv* ev, // context
00479     nsIMdbThumb** acqThumb); // acquire thumb for incremental commit
00480   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
00481   // then the commit will be finished.  Note the store is effectively write
00482   // locked until commit is finished or canceled through the thumb instance.
00483   // Until the commit is done, the store will report it has readonly status.
00484 
00485   NS_IMETHOD SessionCommit( // save all changes if large commits delayed
00486     nsIMdbEnv* ev, // context
00487     nsIMdbThumb** acqThumb); // acquire thumb for incremental commit
00488   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
00489   // then the commit will be finished.  Note the store is effectively write
00490   // locked until commit is finished or canceled through the thumb instance.
00491   // Until the commit is done, the store will report it has readonly status.
00492 
00493   NS_IMETHOD
00494   CompressCommit( // commit and make db physically smaller if possible
00495     nsIMdbEnv* ev, // context
00496     nsIMdbThumb** acqThumb); // acquire thumb for incremental commit
00497   // Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
00498   // then the commit will be finished.  Note the store is effectively write
00499   // locked until commit is finished or canceled through the thumb instance.
00500   // Until the commit is done, the store will report it has readonly status.
00501   
00502   // } ----- end commit methods -----
00503 
00504 // } ===== end nsIMdbStore methods =====
00505 
00506 public: // typesafe refcounting inlines calling inherited morkNode methods
00507   static void SlotWeakPort(morkPort* me,
00508     morkEnv* ev, morkPort** ioSlot)
00509   { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
00510   
00511   static void SlotStrongPort(morkPort* me,
00512     morkEnv* ev, morkPort** ioSlot)
00513   { morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
00514 // public: // slots inherited from morkPort (meant to inform only)
00515   // nsIMdbHeap*     mNode_Heap;
00516   // mork_able    mNode_Mutable; // can this node be modified?
00517   // mork_load    mNode_Load;    // is this node clean or dirty?
00518   // mork_base    mNode_Base;    // must equal morkBase_kNode
00519   // mork_derived mNode_Derived; // depends on specific node subclass
00520   // mork_access  mNode_Access;  // kOpen, kClosing, kShut, or kDead
00521   // mork_usage   mNode_Usage;   // kHeap, kStack, kMember, kGlobal, kNone
00522   // mork_uses    mNode_Uses;    // refcount for strong refs
00523   // mork_refs    mNode_Refs;    // refcount for strong refs + weak refs
00524  
00525   // morkEnv*        mPort_Env;      // non-refcounted env which created port
00526   // morkFactory*    mPort_Factory;  // weak ref to suite factory
00527   // nsIMdbHeap*     mPort_Heap;     // heap in which this port allocs objects
00528 
00529 public: // state is public because the entire Mork system is private
00530 
00531 // mStore_OidAtomSpace might be unnecessary; I don't remember why I wanted it.
00532   morkAtomSpace*   mStore_OidAtomSpace;   // ground atom space for oids
00533   morkAtomSpace*   mStore_GroundAtomSpace; // ground atom space for scopes
00534   morkAtomSpace*   mStore_GroundColumnSpace; // ground column space for scopes
00535 
00536   nsIMdbFile*      mStore_File; // the file containing Mork text
00537   morkStream*      mStore_InStream; // stream using file used by the builder
00538   morkBuilder*     mStore_Builder; // to parse Mork text and build structures 
00539 
00540   morkStream*      mStore_OutStream; // stream using file used by the writer
00541   
00542   morkRowSpaceMap  mStore_RowSpaces;  // maps mork_scope -> morkSpace
00543   morkAtomSpaceMap mStore_AtomSpaces; // maps mork_scope -> morkSpace
00544   
00545   morkZone         mStore_Zone;
00546   
00547   morkPool         mStore_Pool;
00548 
00549   // we alloc a max size book atom to reuse space for atom map key searches:
00550   // morkMaxBookAtom  mStore_BookAtom; // staging area for atom map searches
00551   
00552   morkFarBookAtom  mStore_FarBookAtom; // staging area for atom map searches
00553   
00554   // GroupIdentity should be one more than largest seen in a parsed db file:
00555   mork_gid         mStore_CommitGroupIdentity; // transaction ID number
00556   
00557   // group positions are used to help compute PercentOfStoreWasted():
00558   mork_pos         mStore_FirstCommitGroupPos; // start of first group
00559   mork_pos         mStore_SecondCommitGroupPos; // start of second group
00560   // If the first commit group is very near the start of the file (say less
00561   // than 512 bytes), then we might assume the file started nearly empty and
00562   // that most of the first group is not wasted.  In that case, the pos of
00563   // the second commit group might make a better estimate of the start of
00564   // transaction space that might represent wasted file space.  That's why
00565   // we support fields for both first and second commit group positions.
00566   //
00567   // We assume that a zero in either group pos means that the slot has not
00568   // yet been given a valid value, since the file will always start with a
00569   // tag, and a commit group cannot actually start at position zero.
00570   //
00571   // Either or both the first or second commit group positions might be
00572   // supplied by either morkWriter (while committing) or morkBuilder (while
00573   // parsing), since either reading or writing the file might encounter the
00574   // first transaction groups which came into existence either in the past
00575   // or in the very recent present.
00576   
00577   mork_bool        mStore_CanAutoAssignAtomIdentity;
00578   mork_bool        mStore_CanDirty; // changes imply the store becomes dirty?
00579   mork_u1          mStore_CanWriteIncremental; // compress not required?
00580   mork_u1          mStore_Pad; // for u4 alignment
00581   
00582   // mStore_CanDirty should be FALSE when parsing a file while building the
00583   // content going into the store, because such data structure modifications
00584   // are actuallly in sync with the file.  So content read from a file must
00585   // be clean with respect to the file.  After a file is finished parsing,
00586   // the mStore_CanDirty slot should become TRUE, so that any additional
00587   // changes at runtime cause structures to be marked dirty with respect to
00588   // the file which must later be updated with changes during a commit.
00589   //
00590   // It might also make sense to set mStore_CanDirty to FALSE while a commit
00591   // is in progress, lest some internal transformations make more content
00592   // appear dirty when it should not.  So anyone modifying content during a
00593   // commit should think about the intended significance regarding dirty.
00594 
00595 public: // more specific dirty methods for store:
00596   void SetStoreDirty() { this->SetNodeDirty(); }
00597   void SetStoreClean() { this->SetNodeClean(); }
00598   
00599   mork_bool IsStoreClean() const { return this->IsNodeClean(); }
00600   mork_bool IsStoreDirty() const { return this->IsNodeDirty(); }
00601  
00602 public: // setting dirty based on CanDirty:
00603  
00604   void MaybeDirtyStore()
00605   { if ( mStore_CanDirty ) this->SetStoreDirty(); }
00606   
00607 public: // space waste analysis
00608 
00609   mork_percent PercentOfStoreWasted(morkEnv* ev);
00610  
00611 public: // setting store and all subspaces canDirty:
00612  
00613   void SetStoreAndAllSpacesCanDirty(morkEnv* ev, mork_bool inCanDirty);
00614 
00615 public: // building an atom inside mStore_FarBookAtom from a char* string
00616 
00617   morkFarBookAtom* StageAliasAsFarBookAtom(morkEnv* ev,
00618     const morkMid* inMid, morkAtomSpace* ioSpace, mork_cscode inForm);
00619 
00620   morkFarBookAtom* StageYarnAsFarBookAtom(morkEnv* ev,
00621     const mdbYarn* inYarn, morkAtomSpace* ioSpace);
00622 
00623   morkFarBookAtom* StageStringAsFarBookAtom(morkEnv* ev,
00624     const char* inString, mork_cscode inForm, morkAtomSpace* ioSpace);
00625 
00626 public: // determining whether incremental writing is a good use of time:
00627 
00628   mork_bool DoPreferLargeOverCompressCommit(morkEnv* ev);
00629   // true when mStore_CanWriteIncremental && store has file large enough 
00630 
00631 public: // lazy creation of members and nested row or atom spaces
00632 
00633   morkAtomSpace*   LazyGetOidAtomSpace(morkEnv* ev);
00634   morkAtomSpace*   LazyGetGroundAtomSpace(morkEnv* ev);
00635   morkAtomSpace*   LazyGetGroundColumnSpace(morkEnv* ev);
00636 
00637   morkStream*      LazyGetInStream(morkEnv* ev);
00638   morkBuilder*     LazyGetBuilder(morkEnv* ev); 
00639   void             ForgetBuilder(morkEnv* ev); 
00640 
00641   morkStream*      LazyGetOutStream(morkEnv* ev);
00642   
00643   morkRowSpace*    LazyGetRowSpace(morkEnv* ev, mdb_scope inRowScope);
00644   morkAtomSpace*   LazyGetAtomSpace(morkEnv* ev, mdb_scope inAtomScope);
00645  
00646 // { ===== begin morkNode interface =====
00647 public: // morkNode virtual methods
00648   virtual void CloseMorkNode(morkEnv* ev); // CloseStore() only if open
00649   virtual ~morkStore(); // assert that CloseStore() executed earlier
00650   
00651 public: // morkStore construction & destruction
00652   morkStore(morkEnv* ev, const morkUsage& inUsage,
00653      nsIMdbHeap* ioNodeHeap, // the heap (if any) for this node instance
00654      morkFactory* inFactory, // the factory for this
00655      nsIMdbHeap* ioPortHeap  // the heap to hold all content in the port
00656      );
00657   void CloseStore(morkEnv* ev); // called by CloseMorkNode();
00658 
00659 private: // copying is not allowed
00660   morkStore(const morkStore& other);
00661   morkStore& operator=(const morkStore& other);
00662 
00663 public: // dynamic type identification
00664   morkEnv*  CanUseStore(nsIMdbEnv* mev, mork_bool inMutable, mdb_err* outErr) const;
00665    mork_bool IsStore() const
00666   { return IsNode() && mNode_Derived == morkDerived_kStore; }
00667 // } ===== end morkNode methods =====
00668 
00669 public: // typing
00670   static void NonStoreTypeError(morkEnv* ev);
00671   static void NilStoreFileError(morkEnv* ev);
00672   static void CannotAutoAssignAtomIdentityError(morkEnv* ev);
00673   
00674 public: //  store utilties
00675   
00676   morkAtom* YarnToAtom(morkEnv* ev, const mdbYarn* inYarn, PRBool createIfMissing = PR_TRUE);
00677   morkAtom* AddAlias(morkEnv* ev, const morkMid& inMid,
00678     mork_cscode inForm);
00679 
00680 public: // other store methods
00681 
00682   void RenumberAllCollectableContent(morkEnv* ev);
00683 
00684   nsIMdbStore* AcquireStoreHandle(morkEnv* ev); // mObject_Handle
00685 
00686   morkPool* StorePool() { return &mStore_Pool; }
00687 
00688   mork_bool OpenStoreFile(morkEnv* ev, // return value equals ev->Good()
00689     mork_bool inFrozen,
00690     // const char* inFilePath,
00691     nsIMdbFile* ioFile, // db abstract file interface
00692     const mdbOpenPolicy* inOpenPolicy);
00693 
00694   mork_bool CreateStoreFile(morkEnv* ev, // return value equals ev->Good()
00695     // const char* inFilePath,
00696     nsIMdbFile* ioFile, // db abstract file interface
00697     const mdbOpenPolicy* inOpenPolicy);
00698     
00699   morkAtom* CopyAtom(morkEnv* ev, const morkAtom* inAtom);
00700   // copy inAtom (from some other store) over to this store
00701     
00702   mork_token CopyToken(morkEnv* ev, mdb_token inToken, morkStore* inStore);
00703   // copy inToken from inStore over to this store
00704     
00705   mork_token BufToToken(morkEnv* ev, const morkBuf* inBuf);
00706   mork_token StringToToken(morkEnv* ev, const char* inTokenName);
00707   mork_token QueryToken(morkEnv* ev, const char* inTokenName);
00708   void TokenToString(morkEnv* ev, mdb_token inToken, mdbYarn* outTokenName);
00709   
00710   mork_bool MidToOid(morkEnv* ev, const morkMid& inMid,
00711      mdbOid* outOid);
00712   mork_bool OidToYarn(morkEnv* ev, const mdbOid& inOid, mdbYarn* outYarn);
00713   mork_bool MidToYarn(morkEnv* ev, const morkMid& inMid,
00714      mdbYarn* outYarn);
00715 
00716   morkBookAtom* MidToAtom(morkEnv* ev, const morkMid& inMid);
00717   morkRow* MidToRow(morkEnv* ev, const morkMid& inMid);
00718   morkTable* MidToTable(morkEnv* ev, const morkMid& inMid);
00719   
00720   morkRow* OidToRow(morkEnv* ev, const mdbOid* inOid);
00721   // OidToRow() finds old row with oid, or makes new one if not found.
00722 
00723   morkTable* OidToTable(morkEnv* ev, const mdbOid* inOid,
00724     const mdbOid* inOptionalMetaRowOid);
00725   // OidToTable() finds old table with oid, or makes new one if not found.
00726   
00727   static void SmallTokenToOneByteYarn(morkEnv* ev, mdb_token inToken,
00728     mdbYarn* outYarn);
00729   
00730   mork_bool HasTableKind(morkEnv* ev, mdb_scope inRowScope, 
00731     mdb_kind inTableKind, mdb_count* outTableCount);
00732   
00733   morkTable* GetTableKind(morkEnv* ev, mdb_scope inRowScope, 
00734     mdb_kind inTableKind, mdb_count* outTableCount,
00735     mdb_bool* outMustBeUnique);
00736 
00737   morkRow* FindRow(morkEnv* ev, mdb_scope inScope, mdb_column inColumn,
00738     const mdbYarn* inTargetCellValue);
00739   
00740   morkRow* GetRow(morkEnv* ev, const mdbOid* inOid);
00741   morkTable* GetTable(morkEnv* ev, const mdbOid* inOid);
00742     
00743   morkTable* NewTable(morkEnv* ev, mdb_scope inRowScope,
00744     mdb_kind inTableKind, mdb_bool inMustBeUnique,
00745     const mdbOid* inOptionalMetaRowOid);
00746 
00747   morkPortTableCursor* GetPortTableCursor(morkEnv* ev, mdb_scope inRowScope,
00748     mdb_kind inTableKind) ;
00749 
00750   morkRow* NewRowWithOid(morkEnv* ev, const mdbOid* inOid);
00751   morkRow* NewRow(morkEnv* ev, mdb_scope inRowScope);
00752 
00753   morkThumb* MakeCompressCommitThumb(morkEnv* ev, mork_bool inDoCollect);
00754 
00755 public: // commit related methods
00756 
00757   mork_bool MarkAllStoreContentDirty(morkEnv* ev);
00758   // MarkAllStoreContentDirty() visits every object in the store and marks 
00759   // them dirty, including every table, row, cell, and atom.  The return
00760   // equals ev->Good(), to show whether any error happened.  This method is
00761   // intended for use in the beginning of a "compress commit" which writes
00762   // all store content, whether dirty or not.  We dirty everything first so
00763   // that later iterations over content can mark things clean as they are
00764   // written, and organize the process of serialization so that objects are
00765   // written only at need (because of being dirty).
00766 
00767 public: // typesafe refcounting inlines calling inherited morkNode methods
00768   static void SlotWeakStore(morkStore* me,
00769     morkEnv* ev, morkStore** ioSlot)
00770   { morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
00771   
00772   static void SlotStrongStore(morkStore* me,
00773     morkEnv* ev, morkStore** ioSlot)
00774   { 
00775     morkStore* store = *ioSlot;
00776     if ( me != store )
00777     {
00778       if ( store )
00779       {
00780         // what if this nulls out the ev and causes asserts?
00781         // can we move this after the CutStrongRef()?
00782         *ioSlot = 0;
00783         store->Release();
00784       }
00785       if ( me && me->AddRef() )
00786         *ioSlot = me;
00787     }
00788   }
00789 };
00790 
00791 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00792 
00793 #endif /* _MORKSTORE_ */
00794