1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1999
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 #define _MORKWRITER_ 1
54 #include "morkRowMap.h"
58 #include "morkTable.h"
62 #include "morkAtomMap.h"
65 #ifndef _MORKATOMSPACE_
66 #include "morkAtomSpace.h"
69 #ifndef _MORKROWSPACE_
70 #include "morkRowSpace.h"
74 #include "morkStream.h"
77 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
80 #define morkWriter_kStreamBufSize /*i*/ (16 * 1024) /* buffer size for stream */
82 #define morkDerived_kWriter /*i*/ 0x5772 /* ascii 'Wr' */
84 #define morkWriter_kPhaseNothingDone 0 /* nothing has yet been done */
85 #define morkWriter_kPhaseDirtyAllDone 1 /* DirtyAll() is done */
86 #define morkWriter_kPhasePutHeaderDone 2 /* PutHeader() is done */
88 #define morkWriter_kPhaseRenumberAllDone 3 /* RenumberAll() is done */
90 #define morkWriter_kPhaseStoreAtomSpaces 4 /*mWriter_StoreAtomSpacesIter*/
91 #define morkWriter_kPhaseAtomSpaceAtomAids 5 /*mWriter_AtomSpaceAtomAidsIter*/
93 #define morkWriter_kPhaseStoreRowSpacesTables 6 /*mWriter_StoreRowSpacesIter*/
94 #define morkWriter_kPhaseRowSpaceTables 7 /*mWriter_RowSpaceTablesIter*/
95 #define morkWriter_kPhaseTableRowArray 8 /*mWriter_TableRowArrayPos */
97 #define morkWriter_kPhaseStoreRowSpacesRows 9 /*mWriter_StoreRowSpacesIter*/
98 #define morkWriter_kPhaseRowSpaceRows 10 /*mWriter_RowSpaceRowsIter*/
100 #define morkWriter_kPhaseContentDone 11 /* all content written */
101 #define morkWriter_kPhaseWritingDone 12 /* everthing has been done */
103 #define morkWriter_kCountNumberOfPhases 13 /* part of mWrite_TotalCount */
105 #define morkWriter_kMaxColumnNameSize 128 /* longest writable col name */
107 #define morkWriter_kMaxIndent 66 /* default value for mWriter_MaxIndent */
108 #define morkWriter_kMaxLine 78 /* default value for mWriter_MaxLine */
110 #define morkWriter_kYarnEscapeSlop 4 /* guess average yarn escape overhead */
112 #define morkWriter_kTableMetaCellDepth 4 /* */
113 #define morkWriter_kTableMetaCellValueDepth 6 /* */
115 #define morkWriter_kDictMetaCellDepth 4 /* */
116 #define morkWriter_kDictMetaCellValueDepth 6 /* */
118 #define morkWriter_kDictAliasDepth 2 /* */
119 #define morkWriter_kDictAliasValueDepth 4 /* */
121 #define morkWriter_kRowDepth 2 /* */
122 #define morkWriter_kRowCellDepth 4 /* */
123 #define morkWriter_kRowCellValueDepth 6 /* */
125 #define morkWriter_kGroupBufSize 64 /* */
127 // v=1.1 retired on 23-Mar-99 (for metainfo one char column names)
128 // v=1.2 retired on 20-Apr-99 (for ":c" suffix on table kind hex refs)
129 // v=1.3 retired on 20-Apr-99 (for 1CE:m instead of ill-formed 1CE:^6D)
130 #define morkWriter_kFileHeader "// <!-- <mdb:mork:z v=\"1.4\"/> -->"
132 class morkWriter
: public morkNode
{ // row iterator
134 // public: // slots inherited from morkObject (meant to inform only)
135 // nsIMdbHeap* mNode_Heap;
136 // mork_able mNode_Mutable; // can this node be modified?
137 // mork_load mNode_Load; // is this node clean or dirty?
138 // mork_base mNode_Base; // must equal morkBase_kNode
139 // mork_derived mNode_Derived; // depends on specific node subclass
140 // mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
141 // mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
142 // mork_uses mNode_Uses; // refcount for strong refs
143 // mork_refs mNode_Refs; // refcount for strong refs + weak refs
145 public: // state is public because the entire Mork system is private
147 morkStore
* mWriter_Store
; // weak ref to committing store
148 nsIMdbFile
* mWriter_File
; // strong ref to store's file
149 nsIMdbFile
* mWriter_Bud
; // strong ref to bud of mWriter_File
150 morkStream
* mWriter_Stream
; // strong ref to stream on bud file
151 nsIMdbHeap
* mWriter_SlotHeap
; // strong ref to slot heap
153 // GroupIdentity should be based on mStore_CommitGroupIdentity:
154 mork_gid mWriter_CommitGroupIdentity
; // transaction ID number
156 // GroupBuf holds a hex version of mWriter_CommitGroupIdentity:
157 char mWriter_GroupBuf
[ morkWriter_kGroupBufSize
];
158 mork_fill mWriter_GroupBufFill
; // actual bytes in GroupBuf
160 mork_count mWriter_TotalCount
; // count of all things to be written
161 mork_count mWriter_DoneCount
; // count of things already written
163 mork_size mWriter_LineSize
; // length of current line being written
164 mork_size mWriter_MaxIndent
; // line size forcing a line break
165 mork_size mWriter_MaxLine
; // line size forcing a value continuation
167 mork_cscode mWriter_TableForm
; // current charset metainfo
168 mork_scope mWriter_TableAtomScope
; // current atom scope
169 mork_scope mWriter_TableRowScope
; // current row scope
170 mork_kind mWriter_TableKind
; // current table kind
172 mork_cscode mWriter_RowForm
; // current charset metainfo
173 mork_scope mWriter_RowAtomScope
; // current atom scope
174 mork_scope mWriter_RowScope
; // current row scope
176 mork_cscode mWriter_DictForm
; // current charset metainfo
177 mork_scope mWriter_DictAtomScope
; // current atom scope
179 mork_bool mWriter_NeedDirtyAll
; // need to call DirtyAll()
180 mork_bool mWriter_Incremental
; // opposite of mWriter_NeedDirtyAll
181 mork_bool mWriter_DidStartDict
; // true when a dict has been started
182 mork_bool mWriter_DidEndDict
; // true when a dict has been ended
184 mork_bool mWriter_SuppressDirtyRowNewline
; // for table meta rows
185 mork_bool mWriter_DidStartGroup
; // true when a group has been started
186 mork_bool mWriter_DidEndGroup
; // true when a group has been ended
187 mork_u1 mWriter_Phase
; // status of writing process
189 mork_bool mWriter_BeVerbose
; // driven by env and table verbose settings:
190 // mWriter_BeVerbose equals ( ev->mEnv_BeVerbose || table->IsTableVerbose() )
192 mork_u1 mWriter_Pad
[ 3 ]; // for u4 alignment
194 mork_pos mWriter_TableRowArrayPos
; // index into mTable_RowArray
196 char mWriter_SafeNameBuf
[ (morkWriter_kMaxColumnNameSize
* 2) + 4 ];
197 // Note: extra four bytes in ColNameBuf means we can always append to yarn
199 char mWriter_ColNameBuf
[ morkWriter_kMaxColumnNameSize
+ 4 ];
200 // Note: extra four bytes in ColNameBuf means we can always append to yarn
202 mdbYarn mWriter_ColYarn
; // a yarn to describe space in ColNameBuf:
203 // mYarn_Buf == mWriter_ColNameBuf, mYarn_Size == morkWriter_kMaxColumnNameSize
205 mdbYarn mWriter_SafeYarn
; // a yarn to describe space in ColNameBuf:
206 // mYarn_Buf == mWriter_SafeNameBuf, mYarn_Size == (kMaxColumnNameSize * 2)
208 morkAtomSpaceMapIter mWriter_StoreAtomSpacesIter
; // for mStore_AtomSpaces
209 morkAtomAidMapIter mWriter_AtomSpaceAtomAidsIter
; // for AtomSpace_AtomAids
211 morkRowSpaceMapIter mWriter_StoreRowSpacesIter
; // for mStore_RowSpaces
212 morkTableMapIter mWriter_RowSpaceTablesIter
; // for mRowSpace_Tables
214 #ifdef MORK_ENABLE_PROBE_MAPS
215 morkRowProbeMapIter mWriter_RowSpaceRowsIter
; // for mRowSpace_Rows
216 #else /*MORK_ENABLE_PROBE_MAPS*/
217 morkRowMapIter mWriter_RowSpaceRowsIter
; // for mRowSpace_Rows
218 #endif /*MORK_ENABLE_PROBE_MAPS*/
220 // { ===== begin morkNode interface =====
221 public: // morkNode virtual methods
222 virtual void CloseMorkNode(morkEnv
* ev
); // CloseWriter()
223 virtual ~morkWriter(); // assert that close executed earlier
225 public: // morkWriter construction & destruction
226 morkWriter(morkEnv
* ev
, const morkUsage
& inUsage
,
227 nsIMdbHeap
* ioHeap
, morkStore
* ioStore
, nsIMdbFile
* ioFile
,
228 nsIMdbHeap
* ioSlotHeap
);
229 void CloseWriter(morkEnv
* ev
); // called by CloseMorkNode();
231 private: // copying is not allowed
232 morkWriter(const morkWriter
& other
);
233 morkWriter
& operator=(const morkWriter
& other
);
235 public: // dynamic type identification
236 mork_bool
IsWriter() const
237 { return IsNode() && mNode_Derived
== morkDerived_kWriter
; }
238 // } ===== end morkNode methods =====
240 public: // typing & errors
241 static void NonWriterTypeError(morkEnv
* ev
);
242 static void NilWriterStoreError(morkEnv
* ev
);
243 static void NilWriterBudError(morkEnv
* ev
);
244 static void NilWriterStreamError(morkEnv
* ev
);
245 static void NilWriterFileError(morkEnv
* ev
);
246 static void UnsupportedPhaseError(morkEnv
* ev
);
248 public: // utitlities
249 void ChangeRowForm(morkEnv
* ev
, mork_cscode inNewForm
);
250 void ChangeDictForm(morkEnv
* ev
, mork_cscode inNewForm
);
251 void ChangeDictAtomScope(morkEnv
* ev
, mork_scope inScope
);
254 mork_bool
DidStartDict() const { return mWriter_DidStartDict
; }
255 mork_bool
DidEndDict() const { return mWriter_DidEndDict
; }
257 void IndentAsNeeded(morkEnv
* ev
, mork_size inDepth
)
259 if ( mWriter_LineSize
> mWriter_MaxIndent
)
260 mWriter_LineSize
= mWriter_Stream
->PutIndent(ev
, inDepth
);
263 void IndentOverMaxLine(morkEnv
* ev
,
264 mork_size inPendingSize
, mork_size inDepth
)
266 if ( mWriter_LineSize
+ inPendingSize
> mWriter_MaxLine
)
267 mWriter_LineSize
= mWriter_Stream
->PutIndent(ev
, inDepth
);
270 public: // delayed construction
272 void MakeWriterStream(morkEnv
* ev
); // give writer a suitable stream
274 public: // iterative/asynchronous writing
276 mork_bool
WriteMore(morkEnv
* ev
); // call until IsWritingDone() is true
278 mork_bool
IsWritingDone() const // don't call WriteMore() any longer?
279 { return mWriter_Phase
== morkWriter_kPhaseWritingDone
; }
281 public: // marking all content dirty
282 mork_bool
DirtyAll(morkEnv
* ev
);
283 // DirtyAll() visits every store sub-object and marks
284 // them dirty, including every table, row, cell, and atom. The return
285 // equals ev->Good(), to show whether any error happened. This method is
286 // intended for use in the beginning of a "compress commit" which writes
287 // all store content, whether dirty or not. We dirty everything first so
288 // that later iterations over content can mark things clean as they are
289 // written, and organize the process of serialization so that objects are
290 // written only at need (because of being dirty). Note the method can
291 // stop early when any error happens, since this will abort any commit.
293 public: // group commit transactions
295 mork_bool
StartGroup(morkEnv
* ev
);
296 mork_bool
CommitGroup(morkEnv
* ev
);
297 mork_bool
AbortGroup(morkEnv
* ev
);
299 public: // phase methods
300 mork_bool
OnNothingDone(morkEnv
* ev
);
301 mork_bool
OnDirtyAllDone(morkEnv
* ev
);
302 mork_bool
OnPutHeaderDone(morkEnv
* ev
);
304 mork_bool
OnRenumberAllDone(morkEnv
* ev
);
306 mork_bool
OnStoreAtomSpaces(morkEnv
* ev
);
307 mork_bool
OnAtomSpaceAtomAids(morkEnv
* ev
);
309 mork_bool
OnStoreRowSpacesTables(morkEnv
* ev
);
310 mork_bool
OnRowSpaceTables(morkEnv
* ev
);
311 mork_bool
OnTableRowArray(morkEnv
* ev
);
313 mork_bool
OnStoreRowSpacesRows(morkEnv
* ev
);
314 mork_bool
OnRowSpaceRows(morkEnv
* ev
);
316 mork_bool
OnContentDone(morkEnv
* ev
);
317 mork_bool
OnWritingDone(morkEnv
* ev
);
319 public: // writing dict items first pass
320 mork_bool
PutTableDict(morkEnv
* ev
, morkTable
* ioTable
);
321 mork_bool
PutRowDict(morkEnv
* ev
, morkRow
* ioRow
);
323 public: // writing node content second pass
324 mork_bool
PutTable(morkEnv
* ev
, morkTable
* ioTable
);
325 mork_bool
PutRow(morkEnv
* ev
, morkRow
* ioRow
);
326 mork_bool
PutRowCells(morkEnv
* ev
, morkRow
* ioRow
);
327 mork_bool
PutVerboseRowCells(morkEnv
* ev
, morkRow
* ioRow
);
329 mork_bool
PutCell(morkEnv
* ev
, morkCell
* ioCell
, mork_bool inWithVal
);
330 mork_bool
PutVerboseCell(morkEnv
* ev
, morkCell
* ioCell
, mork_bool inWithVal
);
332 mork_bool
PutTableChange(morkEnv
* ev
, const morkTableChange
* inChange
);
334 public: // other writer methods
336 mork_bool
IsYarnAllValue(const mdbYarn
* inYarn
);
338 mork_size
WriteYarn(morkEnv
* ev
, const mdbYarn
* inYarn
);
339 // return number of atom bytes written on the current line (which
340 // implies that escaped line breaks will make the size value smaller
341 // than the entire yarn's size, since only part goes on a last line).
343 mork_size
WriteAtom(morkEnv
* ev
, const morkAtom
* inAtom
);
344 // return number of atom bytes written on the current line (which
345 // implies that escaped line breaks will make the size value smaller
346 // than the entire atom's size, since only part goes on a last line).
348 void WriteAllStoreTables(morkEnv
* ev
);
349 void WriteAtomSpaceAsDict(morkEnv
* ev
, morkAtomSpace
* ioSpace
);
351 void WriteTokenToTokenMetaCell(morkEnv
* ev
, mork_token inCol
,
353 void WriteStringToTokenDictCell(morkEnv
* ev
, const char* inCol
,
355 // Note inCol should begin with '(' and end with '=', with col in between.
357 void StartDict(morkEnv
* ev
);
358 void EndDict(morkEnv
* ev
);
360 void StartTable(morkEnv
* ev
, morkTable
* ioTable
);
361 void EndTable(morkEnv
* ev
);
363 public: // typesafe refcounting inlines calling inherited morkNode methods
364 static void SlotWeakWriter(morkWriter
* me
,
365 morkEnv
* ev
, morkWriter
** ioSlot
)
366 { morkNode::SlotWeakNode((morkNode
*) me
, ev
, (morkNode
**) ioSlot
); }
368 static void SlotStrongWriter(morkWriter
* me
,
369 morkEnv
* ev
, morkWriter
** ioSlot
)
370 { morkNode::SlotStrongNode((morkNode
*) me
, ev
, (morkNode
**) ioSlot
); }
373 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
375 #endif /* _MORKTABLEROWCURSOR_ */