summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/db/mork/morkWriter.h
blob: 7e716bec6a8e82ffaedc7e8d09cd189668e25998 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef _MORKWRITER_
#define _MORKWRITER_ 1

#ifndef _MORK_
#  include "mork.h"
#endif

#ifndef _MORKNODE_
#  include "morkNode.h"
#endif

#ifndef _MORKMAP_
#  include "morkMap.h"
#endif

#ifndef _MORKROWMAP_
#  include "morkRowMap.h"
#endif

#ifndef _MORKTABLE_
#  include "morkTable.h"
#endif

#ifndef _MORKATOMMAP_
#  include "morkAtomMap.h"
#endif

#ifndef _MORKATOMSPACE_
#  include "morkAtomSpace.h"
#endif

#ifndef _MORKROWSPACE_
#  include "morkRowSpace.h"
#endif

#ifndef _MORKSTREAM_
#  include "morkStream.h"
#endif

// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789

/* buffer size for stream */
#define morkWriter_kStreamBufSize /*i*/ (16 * 1024)

#define morkDerived_kWriter /*i*/ 0x5772 /* ascii 'Wr' */

#define morkWriter_kPhaseNothingDone 0   /* nothing has yet been done */
#define morkWriter_kPhaseDirtyAllDone 1  /* DirtyAll() is done */
#define morkWriter_kPhasePutHeaderDone 2 /* PutHeader() is done */

#define morkWriter_kPhaseRenumberAllDone 3 /* RenumberAll() is done */

#define morkWriter_kPhaseStoreAtomSpaces 4   /*mWriter_StoreAtomSpacesIter*/
#define morkWriter_kPhaseAtomSpaceAtomAids 5 /*mWriter_AtomSpaceAtomAidsIter*/

#define morkWriter_kPhaseStoreRowSpacesTables 6 /*mWriter_StoreRowSpacesIter*/
#define morkWriter_kPhaseRowSpaceTables 7       /*mWriter_RowSpaceTablesIter*/
#define morkWriter_kPhaseTableRowArray 8        /*mWriter_TableRowArrayPos */

#define morkWriter_kPhaseStoreRowSpacesRows 9 /*mWriter_StoreRowSpacesIter*/
#define morkWriter_kPhaseRowSpaceRows 10      /*mWriter_RowSpaceRowsIter*/

#define morkWriter_kPhaseContentDone 11 /* all content written */
#define morkWriter_kPhaseWritingDone 12 /* everything has been done */

#define morkWriter_kCountNumberOfPhases 13 /* part of mWrite_TotalCount */

#define morkWriter_kMaxColumnNameSize 128 /* longest writable col name */

#define morkWriter_kMaxIndent 66 /* default value for mWriter_MaxIndent */
#define morkWriter_kMaxLine 78   /* default value for mWriter_MaxLine */

#define morkWriter_kYarnEscapeSlop 4 /* guess average yarn escape overhead */

#define morkWriter_kTableMetaCellDepth 4      /* */
#define morkWriter_kTableMetaCellValueDepth 6 /* */

#define morkWriter_kDictMetaCellDepth 4      /* */
#define morkWriter_kDictMetaCellValueDepth 6 /* */

#define morkWriter_kDictAliasDepth 2      /* */
#define morkWriter_kDictAliasValueDepth 4 /* */

#define morkWriter_kRowDepth 2          /* */
#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)
#define morkWriter_kFileHeader "// <!-- <mdb:mork:z v=\"1.4\"/> -->"

class morkWriter : public morkNode {  // row iterator

  // public: // slots inherited from morkObject (meant to inform only)
  // nsIMdbHeap*     mNode_Heap;
  // mork_able    mNode_Mutable; // can this node be modified?
  // mork_load    mNode_Load;    // is this node clean or dirty?
  // 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_uses    mNode_Uses;    // refcount for strong refs
  // mork_refs    mNode_Refs;    // refcount for strong refs + weak refs

 public:  // state is public because the entire Mork system is private
  morkStore* mWriter_Store;      // weak ref to committing store
  nsIMdbFile* mWriter_File;      // strong ref to store's file
  nsIMdbFile* 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

  mork_size mWriter_LineSize;   // length of current line being written
  mork_size mWriter_MaxIndent;  // line size forcing a line break
  mork_size mWriter_MaxLine;    // line size forcing a value continuation

  mork_cscode mWriter_TableForm;      // current charset metainfo
  mork_scope mWriter_TableAtomScope;  // current atom scope
  mork_scope mWriter_TableRowScope;   // current row scope
  mork_kind mWriter_TableKind;        // current table kind

  mork_cscode mWriter_RowForm;      // current charset metainfo
  mork_scope mWriter_RowAtomScope;  // current atom scope
  mork_scope mWriter_RowScope;      // current row scope

  mork_cscode mWriter_DictForm;      // current charset metainfo
  mork_scope mWriter_DictAtomScope;  // current atom scope

  mork_bool mWriter_NeedDirtyAll;  // need to call DirtyAll()
  mork_bool mWriter_Incremental;   // opposite of mWriter_NeedDirtyAll
  mork_bool mWriter_DidStartDict;  // true when a dict has been started
  mork_bool mWriter_DidEndDict;    // true when a dict has been ended

  mork_bool mWriter_SuppressDirtyRowNewline;  // for table meta rows
  mork_bool mWriter_DidStartGroup;  // true when a group has been started
  mork_bool mWriter_DidEndGroup;    // true when a group has been ended
  mork_u1 mWriter_Phase;            // status of writing process

  mork_bool mWriter_BeVerbose;  // driven by env and table verbose settings:
  // mWriter_BeVerbose equals ( ev->mEnv_BeVerbose || table->IsTableVerbose() )

  mork_u1 mWriter_Pad[3];  // for u4 alignment

  mork_pos mWriter_TableRowArrayPos;  // index into mTable_RowArray

  char mWriter_SafeNameBuf[(morkWriter_kMaxColumnNameSize * 2) + 4];
  // Note: extra four bytes in ColNameBuf means we can always append to yarn

  char mWriter_ColNameBuf[morkWriter_kMaxColumnNameSize + 4];
  // Note: extra four bytes in ColNameBuf means we can always append to yarn

  mdbYarn mWriter_ColYarn;  // a yarn to describe space in ColNameBuf:
  // mYarn_Buf == mWriter_ColNameBuf, mYarn_Size ==
  // morkWriter_kMaxColumnNameSize

  mdbYarn mWriter_SafeYarn;  // a yarn to describe space in ColNameBuf:
  // mYarn_Buf == mWriter_SafeNameBuf, mYarn_Size == (kMaxColumnNameSize * 2)

  morkAtomSpaceMapIter mWriter_StoreAtomSpacesIter;  // for mStore_AtomSpaces
  morkAtomAidMapIter mWriter_AtomSpaceAtomAidsIter;  // for AtomSpace_AtomAids

  morkRowSpaceMapIter mWriter_StoreRowSpacesIter;  // for mStore_RowSpaces
  morkTableMapIter mWriter_RowSpaceTablesIter;     // for mRowSpace_Tables

#ifdef MORK_ENABLE_PROBE_MAPS
  morkRowProbeMapIter mWriter_RowSpaceRowsIter;  // for mRowSpace_Rows
#else                                            /*MORK_ENABLE_PROBE_MAPS*/
  morkRowMapIter mWriter_RowSpaceRowsIter;  // for mRowSpace_Rows
#endif                                           /*MORK_ENABLE_PROBE_MAPS*/

  // { ===== begin morkNode interface =====
 public:                                             // morkNode virtual methods
  virtual void CloseMorkNode(morkEnv* ev) override;  // CloseWriter()
  virtual ~morkWriter();  // assert that close executed earlier

 public:  // morkWriter construction & destruction
  morkWriter(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
             morkStore* ioStore, nsIMdbFile* ioFile, nsIMdbHeap* ioSlotHeap);
  void CloseWriter(morkEnv* ev);  // called by CloseMorkNode();

 private:  // copying is not allowed
  morkWriter(const morkWriter& other);
  morkWriter& operator=(const morkWriter& other);

 public:  // dynamic type identification
  mork_bool IsWriter() const {
    return IsNode() && mNode_Derived == morkDerived_kWriter;
  }
  // } ===== end morkNode methods =====

 public:  // typing & errors
  static void NonWriterTypeError(morkEnv* ev);
  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);

 public:  // inlines
  mork_bool DidStartDict() const { return mWriter_DidStartDict; }
  mork_bool DidEndDict() const { return mWriter_DidEndDict; }

  void IndentAsNeeded(morkEnv* ev, mork_size inDepth) {
    if (mWriter_LineSize > mWriter_MaxIndent)
      mWriter_LineSize = mWriter_Stream->PutIndent(ev, inDepth);
  }

  void IndentOverMaxLine(morkEnv* ev, mork_size inPendingSize,
                         mork_size inDepth) {
    if (mWriter_LineSize + inPendingSize > mWriter_MaxLine)
      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

  mork_bool IsWritingDone() const  // don't call WriteMore() any longer?
  {
    return mWriter_Phase == morkWriter_kPhaseWritingDone;
  }

 public:  // marking all content dirty
  mork_bool DirtyAll(morkEnv* ev);
  // DirtyAll() visits every store sub-object and marks
  // them dirty, including every table, row, cell, and atom.  The return
  // equals ev->Good(), to show whether any error happened.  This method is
  // intended for use in the beginning of a "compress commit" which writes
  // all store content, whether dirty or not.  We dirty everything first so
  // that later iterations over content can mark things clean as they are
  // written, and organize the process of serialization so that objects are
  // 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);
  mork_bool OnPutHeaderDone(morkEnv* ev);

  mork_bool OnRenumberAllDone(morkEnv* ev);

  mork_bool OnStoreAtomSpaces(morkEnv* ev);
  mork_bool OnAtomSpaceAtomAids(morkEnv* ev);

  mork_bool OnStoreRowSpacesTables(morkEnv* ev);
  mork_bool OnRowSpaceTables(morkEnv* ev);
  mork_bool OnTableRowArray(morkEnv* ev);

  mork_bool OnStoreRowSpacesRows(morkEnv* ev);
  mork_bool OnRowSpaceRows(morkEnv* ev);

  mork_bool OnContentDone(morkEnv* ev);
  mork_bool OnWritingDone(morkEnv* ev);

 public:  // writing dict items first pass
  mork_bool PutTableDict(morkEnv* ev, morkTable* ioTable);
  mork_bool PutRowDict(morkEnv* ev, morkRow* ioRow);

 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
  mork_bool IsYarnAllValue(const mdbYarn* inYarn);

  mork_size WriteYarn(morkEnv* ev, const mdbYarn* inYarn);
  // return number of atom bytes written on the current line (which
  // implies that escaped line breaks will make the size value smaller
  // than the entire yarn's size, since only part goes on a last line).

  mork_size WriteAtom(morkEnv* ev, const morkAtom* inAtom);
  // return number of atom bytes written on the current line (which
  // implies that escaped line breaks will make the size value smaller
  // than the entire atom's size, since only part goes on a last line).

  void WriteAllStoreTables(morkEnv* ev);
  void WriteAtomSpaceAsDict(morkEnv* ev, morkAtomSpace* ioSpace);

  void WriteTokenToTokenMetaCell(morkEnv* ev, mork_token inCol,
                                 mork_token inValue);
  void WriteStringToTokenDictCell(morkEnv* ev, const char* inCol,
                                  mork_token inValue);
  // Note inCol should begin with '(' and end with '=', with col in between.

  void StartDict(morkEnv* ev);
  void EndDict(morkEnv* ev);

  void StartTable(morkEnv* ev, morkTable* ioTable);
  void EndTable(morkEnv* ev);

 public:  // typesafe refcounting inlines calling inherited morkNode methods
  static void SlotWeakWriter(morkWriter* me, morkEnv* ev, morkWriter** ioSlot) {
    morkNode::SlotWeakNode((morkNode*)me, ev, (morkNode**)ioSlot);
  }

  static void SlotStrongWriter(morkWriter* me, morkEnv* ev,
                               morkWriter** ioSlot) {
    morkNode::SlotStrongNode((morkNode*)me, ev, (morkNode**)ioSlot);
  }
};

// 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789

#endif /* _MORKTABLEROWCURSOR_ */