1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef _MDB_
7 # include "mdb.h"
8 #endif
9
10 #ifndef _MORK_
11 # include "mork.h"
12 #endif
13
14 #ifndef _MORKNODE_
15 # include "morkNode.h"
16 #endif
17
18 #ifndef _MORKMAP_
19 # include "morkMap.h"
20 #endif
21
22 #ifndef _MORKSPACE_
23 # include "morkSpace.h"
24 #endif
25
26 #ifndef _MORKNODEMAP_
27 # include "morkNodeMap.h"
28 #endif
29
30 #ifndef _MORKROWMAP_
31 # include "morkRowMap.h"
32 #endif
33
34 #ifndef _MORKENV_
35 # include "morkEnv.h"
36 #endif
37
38 #ifndef _MORKROWSPACE_
39 # include "morkRowSpace.h"
40 #endif
41
42 #ifndef _MORKPOOL_
43 # include "morkPool.h"
44 #endif
45
46 #ifndef _MORKSTORE_
47 # include "morkStore.h"
48 #endif
49
50 #ifndef _MORKTABLE_
51 # include "morkTable.h"
52 #endif
53
54 #ifndef _MORKROW_
55 # include "morkRow.h"
56 #endif
57
58 #ifndef _MORKATOMMAP_
59 # include "morkAtomMap.h"
60 #endif
61
62 #ifndef _MORKROWOBJECT_
63 # include "morkRowObject.h"
64 #endif
65
66 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
67
68 // ````` ````` ````` ````` `````
69 // { ===== begin morkNode interface =====
70
CloseMorkNode(morkEnv * ev)71 /*public virtual*/ void morkRowSpace::CloseMorkNode(
72 morkEnv* ev) // CloseRowSpace() only if open
73 {
74 if (this->IsOpenNode()) {
75 this->MarkClosing();
76 this->CloseRowSpace(ev);
77 this->MarkShut();
78 }
79 }
80
81 /*public virtual*/
~morkRowSpace()82 morkRowSpace::~morkRowSpace() // assert CloseRowSpace() executed earlier
83 {
84 MORK_ASSERT(this->IsShutNode());
85 }
86
87 /*public non-poly*/
morkRowSpace(morkEnv * ev,const morkUsage & inUsage,mork_scope inScope,morkStore * ioStore,nsIMdbHeap * ioHeap,nsIMdbHeap * ioSlotHeap)88 morkRowSpace::morkRowSpace(morkEnv* ev, const morkUsage& inUsage,
89 mork_scope inScope, morkStore* ioStore,
90 nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
91 : morkSpace(ev, inUsage, inScope, ioStore, ioHeap, ioSlotHeap),
92 mRowSpace_SlotHeap(ioSlotHeap),
93 mRowSpace_Rows(ev, morkUsage::kMember, (nsIMdbHeap*)0, ioSlotHeap,
94 morkRowSpace_kStartRowMapSlotCount),
95 mRowSpace_Tables(ev, morkUsage::kMember, (nsIMdbHeap*)0, ioSlotHeap),
96 mRowSpace_NextTableId(1),
97 mRowSpace_NextRowId(1)
98
99 ,
100 mRowSpace_IndexCount(0) {
101 morkAtomRowMap** cache = mRowSpace_IndexCache;
102 morkAtomRowMap** cacheEnd = cache + morkRowSpace_kPrimeCacheSize;
103 while (cache < cacheEnd)
104 *cache++ = 0; // put nil into every slot of cache table
105
106 if (ev->Good()) {
107 if (ioSlotHeap) {
108 mNode_Derived = morkDerived_kRowSpace;
109
110 // the morkSpace base constructor handles any dirty propagation
111 } else
112 ev->NilPointerError();
113 }
114 }
115
CloseRowSpace(morkEnv * ev)116 /*public non-poly*/ void morkRowSpace::CloseRowSpace(
117 morkEnv* ev) // called by CloseMorkNode();
118 {
119 if (this->IsNode()) {
120 morkAtomRowMap** cache = mRowSpace_IndexCache;
121 morkAtomRowMap** cacheEnd = cache + morkRowSpace_kPrimeCacheSize;
122 --cache; // prepare for preincrement:
123 while (++cache < cacheEnd) {
124 if (*cache) morkAtomRowMap::SlotStrongAtomRowMap(0, ev, cache);
125 }
126
127 mRowSpace_Tables.CloseMorkNode(ev);
128
129 morkStore* store = mSpace_Store;
130 if (store) this->CutAllRows(ev, &store->mStore_Pool);
131
132 mRowSpace_Rows.CloseMorkNode(ev);
133 this->CloseSpace(ev);
134 } else
135 this->NonNodeError(ev);
136 }
137
138 // } ===== end morkNode methods =====
139 // ````` ````` ````` ````` `````
140
NonRowSpaceTypeError(morkEnv * ev)141 /*static*/ void morkRowSpace::NonRowSpaceTypeError(morkEnv* ev) {
142 ev->NewError("non morkRowSpace");
143 }
144
ZeroKindError(morkEnv * ev)145 /*static*/ void morkRowSpace::ZeroKindError(morkEnv* ev) {
146 ev->NewError("zero table kind");
147 }
148
ZeroScopeError(morkEnv * ev)149 /*static*/ void morkRowSpace::ZeroScopeError(morkEnv* ev) {
150 ev->NewError("zero row scope");
151 }
152
ZeroTidError(morkEnv * ev)153 /*static*/ void morkRowSpace::ZeroTidError(morkEnv* ev) {
154 ev->NewError("zero table ID");
155 }
156
MinusOneRidError(morkEnv * ev)157 /*static*/ void morkRowSpace::MinusOneRidError(morkEnv* ev) {
158 ev->NewError("row ID is -1");
159 }
160
161 ///*static*/ void
162 // morkRowSpace::ExpectAutoIdOnlyError(morkEnv* ev)
163 //{
164 // ev->NewError("zero row ID");
165 //}
166
167 ///*static*/ void
168 // morkRowSpace::ExpectAutoIdNeverError(morkEnv* ev)
169 //{
170 //}
171
CutAllRows(morkEnv * ev,morkPool * ioPool)172 mork_num morkRowSpace::CutAllRows(morkEnv* ev, morkPool* ioPool) {
173 if (this->IsRowSpaceClean()) this->MaybeDirtyStoreAndSpace();
174
175 #ifdef MORK_ENABLE_ZONE_ARENAS
176 MORK_USED_2(ev, ioPool);
177 return 0;
178 #else /*MORK_ENABLE_ZONE_ARENAS*/
179 mork_num outSlots = mRowSpace_Rows.MapFill();
180 morkZone* zone = &mSpace_Store->mStore_Zone;
181 morkRow* r = 0; // old key row in the map
182 mork_change* c = 0;
183
184 # ifdef MORK_ENABLE_PROBE_MAPS
185 morkRowProbeMapIter i(ev, &mRowSpace_Rows);
186 # else /*MORK_ENABLE_PROBE_MAPS*/
187 morkRowMapIter i(ev, &mRowSpace_Rows);
188 # endif /*MORK_ENABLE_PROBE_MAPS*/
189
190 for (c = i.FirstRow(ev, &r); c && ev->Good(); c = i.NextRow(ev, &r)) {
191 if (r) {
192 if (r->IsRow()) {
193 if (r->mRow_Object) {
194 morkRowObject::SlotWeakRowObject((morkRowObject*)0, ev,
195 &r->mRow_Object);
196 }
197 ioPool->ZapRow(ev, r, zone);
198 } else
199 r->NonRowTypeWarning(ev);
200 } else
201 ev->NilPointerError();
202
203 # ifdef MORK_ENABLE_PROBE_MAPS
204 // cut nothing from the map
205 # else /*MORK_ENABLE_PROBE_MAPS*/
206 i.CutHereRow(ev, /*key*/ (morkRow**)0);
207 # endif /*MORK_ENABLE_PROBE_MAPS*/
208 }
209
210 return outSlots;
211 #endif /*MORK_ENABLE_ZONE_ARENAS*/
212 }
213
FindTableByKind(morkEnv * ev,mork_kind inTableKind)214 morkTable* morkRowSpace::FindTableByKind(morkEnv* ev, mork_kind inTableKind) {
215 if (inTableKind) {
216 #ifdef MORK_BEAD_OVER_NODE_MAPS
217
218 morkTableMapIter i(ev, &mRowSpace_Tables);
219 morkTable* table = i.FirstTable(ev);
220 for (; table && ev->Good(); table = i.NextTable(ev))
221 #else /*MORK_BEAD_OVER_NODE_MAPS*/
222 mork_tid* key = 0; // nil pointer to suppress key access
223 morkTable* table = 0; // old table in the map
224
225 mork_change* c = 0;
226 morkTableMapIter i(ev, &mRowSpace_Tables);
227 for (c = i.FirstTable(ev, key, &table); c && ev->Good();
228 c = i.NextTable(ev, key, &table))
229 #endif /*MORK_BEAD_OVER_NODE_MAPS*/
230 {
231 if (table->mTable_Kind == inTableKind) return table;
232 }
233 } else
234 this->ZeroKindError(ev);
235
236 return (morkTable*)0;
237 }
238
NewTableWithTid(morkEnv * ev,mork_tid inTid,mork_kind inTableKind,const mdbOid * inOptionalMetaRowOid)239 morkTable* morkRowSpace::NewTableWithTid(
240 morkEnv* ev, mork_tid inTid, mork_kind inTableKind,
241 const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
242 {
243 morkTable* outTable = 0;
244 morkStore* store = mSpace_Store;
245
246 if (inTableKind && store) {
247 mdb_bool mustBeUnique = morkBool_kFalse;
248 nsIMdbHeap* heap = store->mPort_Heap;
249 morkTable* table = new (*heap, ev)
250 morkTable(ev, morkUsage::kHeap, heap, store, heap, this,
251 inOptionalMetaRowOid, inTid, inTableKind, mustBeUnique);
252 if (table) {
253 if (mRowSpace_Tables.AddTable(ev, table)) {
254 outTable = table;
255 if (mRowSpace_NextTableId <= inTid) mRowSpace_NextTableId = inTid + 1;
256 }
257
258 if (this->IsRowSpaceClean() && store->mStore_CanDirty)
259 this->MaybeDirtyStoreAndSpace(); // morkTable does already
260 }
261 } else if (store)
262 this->ZeroKindError(ev);
263 else
264 this->NilSpaceStoreError(ev);
265
266 return outTable;
267 }
268
NewTable(morkEnv * ev,mork_kind inTableKind,mdb_bool inMustBeUnique,const mdbOid * inOptionalMetaRowOid)269 morkTable* morkRowSpace::NewTable(
270 morkEnv* ev, mork_kind inTableKind, mdb_bool inMustBeUnique,
271 const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
272 {
273 morkTable* outTable = 0;
274 morkStore* store = mSpace_Store;
275
276 if (inTableKind && store) {
277 if (inMustBeUnique) // need to look for existing table first?
278 outTable = this->FindTableByKind(ev, inTableKind);
279
280 if (!outTable && ev->Good()) {
281 mork_tid id = this->MakeNewTableId(ev);
282 if (id) {
283 nsIMdbHeap* heap = mSpace_Store->mPort_Heap;
284 morkTable* table = new (*heap, ev)
285 morkTable(ev, morkUsage::kHeap, heap, mSpace_Store, heap, this,
286 inOptionalMetaRowOid, id, inTableKind, inMustBeUnique);
287 if (table) {
288 if (mRowSpace_Tables.AddTable(ev, table))
289 outTable = table;
290 else
291 table->Release();
292
293 if (this->IsRowSpaceClean() && store->mStore_CanDirty)
294 this->MaybeDirtyStoreAndSpace(); // morkTable does already
295 }
296 }
297 }
298 } else if (store)
299 this->ZeroKindError(ev);
300 else
301 this->NilSpaceStoreError(ev);
302
303 return outTable;
304 }
305
MakeNewTableId(morkEnv * ev)306 mork_tid morkRowSpace::MakeNewTableId(morkEnv* ev) {
307 mork_tid outTid = 0;
308 mork_tid id = mRowSpace_NextTableId;
309 mork_num count = 9; // try up to eight times
310
311 while (!outTid && --count) // still trying to find an unused table ID?
312 {
313 if (!mRowSpace_Tables.GetTable(ev, id))
314 outTid = id;
315 else {
316 MORK_ASSERT(morkBool_kFalse); // alert developer about ID problems
317 ++id;
318 }
319 }
320
321 mRowSpace_NextTableId = id + 1;
322 return outTid;
323 }
324
325 #define MAX_AUTO_ID (morkRow_kMinusOneRid - 2)
MakeNewRowId(morkEnv * ev)326 mork_rid morkRowSpace::MakeNewRowId(morkEnv* ev) {
327 mork_rid outRid = 0;
328 mork_rid id = mRowSpace_NextRowId;
329 mork_num count = 9; // try up to eight times
330 mdbOid oid;
331 oid.mOid_Scope = this->SpaceScope();
332
333 // still trying to find an unused row ID?
334 while (!outRid && --count && id <= MAX_AUTO_ID) {
335 oid.mOid_Id = id;
336 if (!mRowSpace_Rows.GetOid(ev, &oid))
337 outRid = id;
338 else {
339 MORK_ASSERT(morkBool_kFalse); // alert developer about ID problems
340 ++id;
341 }
342 }
343
344 if (id < MAX_AUTO_ID) mRowSpace_NextRowId = id + 1;
345 return outRid;
346 }
347
make_index(morkEnv * ev,mork_column inCol)348 morkAtomRowMap* morkRowSpace::make_index(morkEnv* ev, mork_column inCol) {
349 morkAtomRowMap* outMap = 0;
350 nsIMdbHeap* heap = mRowSpace_SlotHeap;
351 if (heap) // have expected heap for allocations?
352 {
353 morkAtomRowMap* map =
354 new (*heap, ev) morkAtomRowMap(ev, morkUsage::kHeap, heap, heap, inCol);
355
356 if (map) // able to create new map index?
357 {
358 if (ev->Good()) // no errors during construction?
359 {
360 #ifdef MORK_ENABLE_PROBE_MAPS
361 morkRowProbeMapIter i(ev, &mRowSpace_Rows);
362 #else /*MORK_ENABLE_PROBE_MAPS*/
363 morkRowMapIter i(ev, &mRowSpace_Rows);
364 #endif /*MORK_ENABLE_PROBE_MAPS*/
365 mork_change* c = 0;
366 morkRow* row = 0;
367 mork_aid aidKey = 0;
368
369 for (c = i.FirstRow(ev, &row); c && ev->Good();
370 c = i.NextRow(ev, &row)) // another row in space?
371 {
372 aidKey = row->GetCellAtomAid(ev, inCol);
373 if (aidKey) // row has indexed attribute?
374 map->AddAid(ev, aidKey, row); // include in map
375 }
376 }
377 if (ev->Good()) // no errors constructing index?
378 outMap = map; // return from function
379 else
380 map->CutStrongRef(ev); // discard map on error
381 }
382 } else
383 ev->NilPointerError();
384
385 return outMap;
386 }
387
ForceMap(morkEnv * ev,mork_column inCol)388 morkAtomRowMap* morkRowSpace::ForceMap(morkEnv* ev, mork_column inCol) {
389 morkAtomRowMap* outMap = this->FindMap(ev, inCol);
390
391 if (!outMap && ev->Good()) // no such existing index?
392 {
393 if (mRowSpace_IndexCount < morkRowSpace_kMaxIndexCount) {
394 morkAtomRowMap* map = this->make_index(ev, inCol);
395 if (map) // created a new index for col?
396 {
397 mork_count wrap = 0; // count times wrap-around occurs
398 morkAtomRowMap** slot = mRowSpace_IndexCache; // table
399 morkAtomRowMap** end = slot + morkRowSpace_kPrimeCacheSize;
400 slot += (inCol % morkRowSpace_kPrimeCacheSize); // hash
401 while (*slot) // empty slot not yet found?
402 {
403 if (++slot >= end) // wrap around?
404 {
405 slot = mRowSpace_IndexCache; // back to table start
406 if (++wrap > 1) // wrapped more than once?
407 {
408 ev->NewError("no free cache slots"); // disaster
409 break; // end while loop
410 }
411 }
412 }
413 if (ev->Good()) // everything went just fine?
414 {
415 ++mRowSpace_IndexCount; // note another new map
416 *slot = map; // install map in the hash table
417 outMap = map; // return the new map from function
418 } else
419 map->CutStrongRef(ev); // discard map on error
420 }
421 } else
422 ev->NewError("too many indexes"); // why so many indexes?
423 }
424 return outMap;
425 }
426
FindMap(morkEnv * ev,mork_column inCol)427 morkAtomRowMap* morkRowSpace::FindMap(morkEnv* ev, mork_column inCol) {
428 if (mRowSpace_IndexCount && ev->Good()) {
429 mork_count wrap = 0; // count times wrap-around occurs
430 morkAtomRowMap** slot = mRowSpace_IndexCache; // table
431 morkAtomRowMap** end = slot + morkRowSpace_kPrimeCacheSize;
432 slot += (inCol % morkRowSpace_kPrimeCacheSize); // hash
433 morkAtomRowMap* map = *slot;
434 while (map) // another used slot to examine?
435 {
436 if (inCol == map->mAtomRowMap_IndexColumn) // found col?
437 return map;
438 if (++slot >= end) // wrap around?
439 {
440 slot = mRowSpace_IndexCache;
441 if (++wrap > 1) // wrapped more than once?
442 return (morkAtomRowMap*)0; // stop searching
443 }
444 map = *slot;
445 }
446 }
447 return (morkAtomRowMap*)0;
448 }
449
FindRow(morkEnv * ev,mork_column inCol,const mdbYarn * inYarn)450 morkRow* morkRowSpace::FindRow(morkEnv* ev, mork_column inCol,
451 const mdbYarn* inYarn) {
452 morkRow* outRow = 0;
453
454 // if yarn hasn't been atomized, there can't be a corresponding row,
455 // so pass in false to not create the row - should help history bloat
456 morkAtom* atom = mSpace_Store->YarnToAtom(ev, inYarn, false);
457 if (atom) // have or created an atom corresponding to input yarn?
458 {
459 mork_aid atomAid = atom->GetBookAtomAid();
460 if (atomAid) // atom has an identity for use in hash table?
461 {
462 morkAtomRowMap* map = this->ForceMap(ev, inCol);
463 if (map) // able to find or create index for col?
464 {
465 outRow = map->GetAid(ev, atomAid); // search for row
466 }
467 }
468 }
469
470 return outRow;
471 }
472
NewRowWithOid(morkEnv * ev,const mdbOid * inOid)473 morkRow* morkRowSpace::NewRowWithOid(morkEnv* ev, const mdbOid* inOid) {
474 morkRow* outRow = mRowSpace_Rows.GetOid(ev, inOid);
475 MORK_ASSERT(outRow == 0);
476 if (!outRow && ev->Good()) {
477 morkStore* store = mSpace_Store;
478 if (store) {
479 morkPool* pool = this->GetSpaceStorePool();
480 morkRow* row = pool->NewRow(ev, &store->mStore_Zone);
481 if (row) {
482 row->InitRow(ev, inOid, this, /*length*/ 0, pool);
483
484 if (ev->Good() && mRowSpace_Rows.AddRow(ev, row)) {
485 outRow = row;
486 mork_rid rid = inOid->mOid_Id;
487 if (mRowSpace_NextRowId <= rid) mRowSpace_NextRowId = rid + 1;
488 } else
489 pool->ZapRow(ev, row, &store->mStore_Zone);
490
491 if (this->IsRowSpaceClean() && store->mStore_CanDirty)
492 this->MaybeDirtyStoreAndSpace(); // InitRow() does already
493 }
494 } else
495 this->NilSpaceStoreError(ev);
496 }
497 return outRow;
498 }
499
NewRow(morkEnv * ev)500 morkRow* morkRowSpace::NewRow(morkEnv* ev) {
501 morkRow* outRow = 0;
502 if (ev->Good()) {
503 mork_rid id = this->MakeNewRowId(ev);
504 if (id) {
505 morkStore* store = mSpace_Store;
506 if (store) {
507 mdbOid oid;
508 oid.mOid_Scope = this->SpaceScope();
509 oid.mOid_Id = id;
510 morkPool* pool = this->GetSpaceStorePool();
511 morkRow* row = pool->NewRow(ev, &store->mStore_Zone);
512 if (row) {
513 row->InitRow(ev, &oid, this, /*length*/ 0, pool);
514
515 if (ev->Good() && mRowSpace_Rows.AddRow(ev, row))
516 outRow = row;
517 else
518 pool->ZapRow(ev, row, &store->mStore_Zone);
519
520 if (this->IsRowSpaceClean() && store->mStore_CanDirty)
521 this->MaybeDirtyStoreAndSpace(); // InitRow() does already
522 }
523 } else
524 this->NilSpaceStoreError(ev);
525 }
526 }
527 return outRow;
528 }
529
530 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
531
~morkRowSpaceMap()532 morkRowSpaceMap::~morkRowSpaceMap() {}
533
morkRowSpaceMap(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,nsIMdbHeap * ioSlotHeap)534 morkRowSpaceMap::morkRowSpaceMap(morkEnv* ev, const morkUsage& inUsage,
535 nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
536 : morkNodeMap(ev, inUsage, ioHeap, ioSlotHeap) {
537 if (ev->Good()) mNode_Derived = morkDerived_kRowSpaceMap;
538 }
539
540 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
541