home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / yacl-012.zip / io / slotfile.cxx < prev    next >
C/C++ Source or Header  |  1995-04-06  |  25KB  |  855 lines

  1.  
  2.  
  3.  
  4.  
  5. /*
  6.  *
  7.  *          Copyright (C) 1994, M. A. Sridhar
  8.  *  
  9.  *
  10.  *     This software is Copyright M. A. Sridhar, 1994. You are free
  11.  *     to copy, modify or distribute this software  as you see fit,
  12.  *     and to use  it  for  any  purpose, provided   this copyright
  13.  *     notice and the following   disclaimer are included  with all
  14.  *     copies.
  15.  *
  16.  *                        DISCLAIMER
  17.  *
  18.  *     The author makes no warranties, either expressed or implied,
  19.  *     with respect  to  this  software, its  quality, performance,
  20.  *     merchantability, or fitness for any particular purpose. This
  21.  *     software is distributed  AS IS.  The  user of this  software
  22.  *     assumes all risks  as to its quality  and performance. In no
  23.  *     event shall the author be liable for any direct, indirect or
  24.  *     consequential damages, even if the  author has been  advised
  25.  *     as to the possibility of such damages.
  26.  *
  27.  */
  28.  
  29.  
  30.  
  31. // This may look like C code, but it is really -*- C++ -*-
  32.  
  33.  
  34.  
  35. #if defined(__GNUC__)
  36. #pragma implementation
  37. #endif
  38.  
  39. #include "base/binding.h"
  40. #include "base/bitset.h"
  41. #include "base/bytestrm.h"
  42. #include "io/slotfile.h"
  43.  
  44.  
  45. #define NEW_OP new
  46.  
  47. // Notes on the SlottedFile implementation:
  48. // 
  49. // The  slotted file is viewed  as a tree  with three levels: the root, its
  50. // children and its  grandchildren. The  root  has 2**14 =  16384 children,
  51. // among which the  the leftmost 2**12 = 4096  are actual records, and  the
  52. // remaining are bitmaps (instances of  CL_BitSet), called block    bitmaps.
  53. // At  the root are  stored  two bitmaps, each  containing  16384 bits: the
  54. // fullMap, in which a bit is on if the corresponding child  of the root is
  55. // full, and  the nonemptyMap, in which  a bit is  on  if the corresponding
  56. // child  of the root is  not empty. Note  that every element in the bitset
  57. // fullMap also  occurs in nonemptyMap.    The former bitset is  useful for
  58. // fast allocation, while the latter is useful for fast iteration.
  59. // 
  60. // This tree is stored in pre-order on the disk file.
  61.  
  62.  
  63.  
  64. #define ROOT_WIDTH  14           // 2**(ROOT_WIDTH) is the number of
  65.                                  // children of the root; thus ROOT_WIDTH is
  66.                                  // the number of bits needed to specify a
  67.                                  // block bitmap
  68. #define WIDTH       16           // #bits needed for specifying a
  69.                                  // record in a block
  70.  
  71. #define RECORDS_PER_BLOCK  (((ulong) 1) << WIDTH)
  72.                                  // #records in a block
  73.  
  74. #define UNUSED_BITS 4096         // #children of the root that are records
  75.                                  // and not blocks.
  76.  
  77. // CL_SlottedFileHandle has the following layout:
  78. //
  79. //    ---------------------------------------------------------------
  80. //    |01|<------   Block bitmap # ------>|<-- Record # in block -->|
  81. //    ---------------------------------------------------------------
  82. //        ^                                ^                       ^
  83. //      Bit 29                           Bit 15                  Bit 0
  84. //
  85. // The 1 in bit 30 is to ensure that every handle is nonzero.
  86. //
  87.  
  88.  
  89. class CL_SlottedFileHeader: public CL_Object {
  90.  
  91.     // This is a private class encapsulating the header of a SlottedFile.
  92. public:
  93.     CL_SlottedFileHeader ();
  94.     
  95.     ~CL_SlottedFileHeader () {};
  96.     
  97.     long StorableFormWidth () const;
  98.     
  99.     bool ReadFrom (const CL_Stream&);
  100.     
  101.     bool WriteTo (CL_Stream&) const;
  102.     
  103.     static long StoreWidth (); // Provided for the purpose of efficiency 
  104.  
  105.     const char* ClassName () const {return "CL_SlottedFileHeader";};
  106.  
  107.     void operator= (const CL_SlottedFileHeader& hdr);
  108.  
  109.     void operator= (const CL_Object& o)
  110.         {*this = (const CL_SlottedFileHeader&) o;};
  111.  
  112.     // Instance data:
  113.     CL_BitSet fullMap;
  114.     CL_BitSet nonemptyMap;
  115.     long allocCount; // #allocated slots in the file
  116.     long slotSize;   // Size of each slot, in bytes
  117.     short userHeaderSize;
  118. };
  119.  
  120. void CL_SlottedFileHeader::operator= (const CL_SlottedFileHeader& hdr)
  121. {
  122.     fullMap        = hdr.fullMap;
  123.     nonemptyMap    = hdr.nonemptyMap;
  124.     allocCount     = hdr.allocCount;
  125.     slotSize       = hdr.slotSize;
  126.     userHeaderSize = hdr.userHeaderSize;
  127. }
  128.  
  129. long CL_SlottedFileHeader::StoreWidth ()
  130. {
  131.     static long width = -1;
  132.     if (width == -1) {
  133.         CL_SlottedFileHeader hdr;
  134.         width = hdr.StorableFormWidth();
  135.     }
  136.     return width;
  137. }
  138.  
  139.  
  140.  
  141. CL_SlottedFileHeader::CL_SlottedFileHeader ()
  142. : fullMap (1L << ROOT_WIDTH), nonemptyMap (1L << ROOT_WIDTH)
  143. {
  144.     userHeaderSize = 0;
  145. }
  146.  
  147. long CL_SlottedFileHeader::StorableFormWidth() const
  148. {
  149.     return sizeof (short) + 2*sizeof (long) + 2*fullMap.StorableFormWidth();
  150. }
  151.  
  152. bool CL_SlottedFileHeader::WriteTo (CL_Stream& s) const
  153. {
  154.     return s.Write (userHeaderSize) && s.Write (allocCount) && s.Write
  155.         (slotSize) && fullMap.WriteTo (s) && nonemptyMap.WriteTo (s);
  156. }
  157.  
  158. bool CL_SlottedFileHeader::ReadFrom (const CL_Stream& s)
  159. {
  160.     return s.Read (userHeaderSize) && s.Read (allocCount) && s.Read
  161.         (slotSize) && fullMap.ReadFrom (s) && nonemptyMap.ReadFrom (s);
  162. }    
  163.  
  164.  
  165.  
  166. // ------------------------ IO_Iter structure ---------------------
  167. // 
  168. // struct IO_Iter {
  169. //     IO_Iter () : _rootIter (root), _blockIter (block) {};
  170. //     CL_BitSet root, block;
  171. //     CL_BitSetIterator _rootIter, _blockIter;
  172. //     short _blockIndex;
  173. // };
  174.  
  175.  
  176.  
  177. /* ---------------------- Handle manipulation functions ------------- */
  178.  
  179. inline CL_SlottedFileHandle __MakeHandle (long record_no,
  180.                                           long block_map_index)
  181. {
  182.     return record_no | (((ulong) block_map_index) <<  WIDTH)
  183.         | (((ulong) 1) << (ROOT_WIDTH + WIDTH));
  184. }
  185.  
  186. inline long __RecordNumber (CL_SlottedFileHandle h)
  187. {
  188.     return ((((ulong) 1) << WIDTH) - 1) & h;
  189. }
  190.  
  191. inline long __BlockMapIndex (CL_SlottedFileHandle h)
  192. {
  193.     return (h  >> WIDTH) & ((((ulong) 1) << ROOT_WIDTH) - 1);
  194. }
  195.  
  196.  
  197.  
  198.  
  199.  
  200. /* ------------------------ CL_SlottedFile methods --------------------- */
  201.  
  202.  
  203. CL_SlottedFile::CL_SlottedFile (CL_Stream& s, bool report)
  204. : _file (s), _reportErrors (report)
  205. {
  206.     _header = new CL_SlottedFileHeader;
  207. }
  208.  
  209. /* ------------------------------------------------------------------ */
  210.  
  211. CL_SlottedFile::~CL_SlottedFile ()
  212. {
  213.     if (_header) {
  214.         delete _header;
  215.     }
  216. }
  217.  
  218.  
  219. /* ------------------------------------------------------------------ */
  220.  
  221. CL_SlottedFileHandle CL_SlottedFile::AllocateSlot ()
  222. {
  223.     if (!PrepareToChange())
  224.         return 0;
  225.     CL_SlottedFileHandle h =  _GetSlot ();
  226.     Notify();
  227.     return h;
  228. }
  229.  
  230. /* ------------------------------------------------------------------ */
  231.  
  232. CL_SlottedFileHandle CL_SlottedFile::AddRecord (uchar* record)
  233. {
  234.     if (!PrepareToChange())
  235.         return 0;
  236.     CL_SlottedFileHandle h = _GetSlot ();
  237.     if (h)
  238.         if (!_file.Write (_RecordOffset (h), record, _slotSize))
  239.             _DoError ("AddRecord", h);
  240.     Notify ();
  241.     return h;
  242. }
  243.  
  244.  
  245. /* ------------------------------------------------------------------ */
  246.  
  247.  
  248. bool CL_SlottedFile::IsValid (CL_SlottedFileHandle h) const
  249. {
  250.     if (!_ReadHeader (*_header)) {
  251.         _DoError ("IsValid: header read");
  252.         return FALSE;
  253.     }
  254.     long rec   = __RecordNumber (h);
  255.     long index = __BlockMapIndex (h);
  256.     if (index < UNUSED_BITS) {
  257.         ulong hi_bits = h & (3L << (WIDTH + ROOT_WIDTH));
  258.         return (rec == index)
  259.             && (hi_bits == (1L << (WIDTH + ROOT_WIDTH)))
  260.             && _header->fullMap.Includes (rec);
  261.     }
  262.     CL_BitSet block_map;
  263.     if (!_file.Read (_BlockBitmapOffset (index), block_map)) {
  264.         _DoError ("IsValid: block map read");
  265.         return FALSE;
  266.     }
  267.     return block_map.Includes (rec);
  268. }
  269.  
  270.  
  271. /* ------------------------------------------------------------------ */
  272.  
  273. long CL_SlottedFile::SlotsAllocated () const
  274. {
  275.     if (!_ReadHeader (*_header)) {
  276.         _DoError ("SlotsAllocated: header read");
  277.         return 0;
  278.     }
  279.     return _header->allocCount;
  280. }
  281.  
  282.  
  283. /* ------------------------------------------------------------------ */
  284.  
  285.  
  286. bool CL_SlottedFile::RetrieveRecord (CL_SlottedFileHandle h,
  287.                                      uchar* record) const
  288. {
  289.     if (!IsValid (h))
  290.         return FALSE;
  291.     if (_file.Read (_RecordOffset (h), record, _slotSize) != _slotSize) {
  292.         _DoError ("RetrieveRecord: record read failed", h);
  293.         return FALSE;
  294.     }
  295.     return TRUE;
  296. }
  297.  
  298.  
  299. /* ------------------------------------------------------------------ */
  300.  
  301.  
  302. bool CL_SlottedFile::ModifyRecord (CL_SlottedFileHandle h,
  303.                                    uchar* record)
  304. {
  305.     if (!PrepareToChange())
  306.         return FALSE;
  307.     if (!IsValid (h))
  308.         return FALSE;
  309.     if (!_file.Write (_RecordOffset (h), record, _slotSize)) {
  310.         _DoError ("ModifyRecord: record write failed", h);
  311.         return FALSE;
  312.     }
  313.     Notify ();
  314.     return TRUE;
  315. }
  316.  
  317.  
  318.  
  319.  
  320. /* ------------------------------------------------------------------ */
  321.  
  322.  
  323.  
  324. bool CL_SlottedFile::DeleteRecord (CL_SlottedFileHandle handle)
  325.     // Free a previously-allocated slot
  326. {
  327.     if (!PrepareToChange())
  328.         return FALSE;
  329.     ulong hi_bits = handle & (3L << (WIDTH + ROOT_WIDTH));
  330.     if (hi_bits != (1L << (WIDTH + ROOT_WIDTH)))
  331.         return FALSE;
  332.     long rec = __RecordNumber (handle);
  333.     long index = __BlockMapIndex (handle);
  334.     long new_file_size = -1L; // Will be changed appropriately if the file
  335.                               // needs to be truncated
  336.     CL_BitSet block_map;
  337.     if (!_ReadHeader (*_header))
  338.         return FALSE;
  339.     if (index < UNUSED_BITS) {
  340.         // The index specifies a record, not a bitmap
  341.         _header->fullMap.Remove (index);
  342.         _header->nonemptyMap.Remove (index);
  343.         if (_header->nonemptyMap.IsEmpty()) {
  344.             // There are no more records in the file after this deletion
  345.             new_file_size = CL_SlottedFileHeader::StoreWidth();
  346.         }
  347.         else {
  348.             long l = _header->nonemptyMap.Largest();
  349.             if (l < index) {
  350.                 // We're deleting the record at the end of the file
  351.                 new_file_size = _BlockBitmapOffset (l) + _slotSize;
  352.             }
  353.         }
  354.     }
  355.     else {
  356.         // The index specifies a bitmap
  357.         CL_Offset block_offset = _BlockBitmapOffset (index);
  358.         long file_size = _file.Size();
  359.         if (block_offset < 0 || block_offset >= file_size)
  360.             return FALSE;
  361.         if (!_file.Read (block_offset, block_map)) {
  362.             _DoError ("DeleteRecord: Level-1 map read failed");
  363.             return FALSE;
  364.         }
  365.         block_map.Remove (rec);
  366.         _header->fullMap.Remove (index);
  367.         register long rec_end = _RecordOffset (handle) + _slotSize;
  368.         if (block_map.IsEmpty()) {
  369.             _header->nonemptyMap.Remove (index);
  370.             if (file_size <= rec_end) {
  371.                 // We're removing the only allocated record in the block
  372.                 new_file_size = block_offset;
  373.             }
  374.         }
  375.         else {
  376.             if (file_size <= rec_end) {
  377.                 // We're removing the record at the end of the file
  378.                 new_file_size = rec_end - _slotSize;
  379.             }
  380.         }
  381.         if (new_file_size != block_offset &&
  382.             !_file.Write (block_offset, block_map)) {
  383.             _DoError ("DeleteRecord: block map write failed", handle);
  384.             return FALSE;
  385.         }
  386.     }
  387.     _header->allocCount--;
  388.     if (!_WriteHeader (*_header))
  389.         return FALSE;
  390.     if (new_file_size != -1L && !_file.ChangeSize (new_file_size)) {
  391.         _DoError ("DeleteRecord: ChangeSize failed");
  392.         return FALSE;
  393.     }
  394.     Notify ();
  395.     return TRUE;
  396. }
  397.  
  398.  
  399.  
  400. /* ------------------------------------------------------------------ */
  401. bool CL_SlottedFile::ReadHeader (uchar* header) const
  402. {
  403.     return (_userHeaderSize > 0)
  404.         ? _file.Read (CL_SlottedFileHeader::StoreWidth(), header,
  405.                       _userHeaderSize)
  406.         : FALSE;
  407. }
  408.  
  409.         
  410.  
  411. // Write the parameter into the user-defined header. Returns
  412. // TRUE on success, FALSE on i/o error.
  413. bool CL_SlottedFile::WriteHeader (uchar* header)
  414. {
  415.     return (_userHeaderSize > 0)
  416.         ? _file.Write (CL_SlottedFileHeader::StoreWidth(), header,
  417.                        _userHeaderSize)
  418.         : FALSE;
  419. }
  420.  
  421.  
  422.  
  423.  
  424.  
  425.  
  426. CL_SlottedFileHandle CL_SlottedFile::FirstRecord (uchar* record) const
  427. {
  428.     if (!_ReadHeader (*_header)) {
  429.         _DoError ("FirstRecord: header read");
  430.         return 0;
  431.     }
  432.     if (_header->allocCount <= 0)
  433.         return 0;
  434.     long index = _header->nonemptyMap.Smallest ();
  435.     CL_SlottedFileHandle ret;
  436.     if (index < UNUSED_BITS) 
  437.         ret = __MakeHandle (index, index);
  438.     else {
  439.         CL_BitSet block_map;
  440.         if (!_file.Read (_BlockBitmapOffset (index), block_map)) {
  441.             _DoError ("FirstRecord:  block bitmap read", 0);
  442.             return 0;
  443.         }
  444.         ret = __MakeHandle (block_map.Smallest(), index);
  445.     }
  446.     return RetrieveRecord (ret, record) ? ret : 0;
  447.     
  448. }
  449.  
  450. CL_SlottedFileHandle CL_SlottedFile::NextRecord (CL_SlottedFileHandle h,
  451.                                                  uchar* record) const
  452. {
  453.     if (!_ReadHeader (*_header)) {
  454.         _DoError ("NextRecord: header read");
  455.         return 0;
  456.     }
  457.     long rec   = __RecordNumber (h);
  458.     long index = __BlockMapIndex (h);
  459.  
  460.     CL_Offset offset = _BlockBitmapOffset (index);
  461.     if (offset >= _file.Size()) {
  462.         return 0; 
  463.     }
  464.     CL_BitSet block_map;
  465.     CL_SlottedFileHandle ret;
  466.     if (rec >= UNUSED_BITS) {
  467.         // The given handle is that of a record in some block; read its map
  468.         if (!_file.Read (offset, block_map)) {
  469.             _DoError ("_NextRecord:  block bitmap read", 0);
  470.             return 0;
  471.         }
  472.         long rec2 = block_map.Successor (rec);
  473.         if (rec2 >= 0) {
  474.             ret = __MakeHandle (rec2,  index);
  475.             return RetrieveRecord (ret, record) ? ret : 0;
  476.         }
  477.         // No more allocated records in the block; fall through...
  478.     }
  479.     long l = _header->nonemptyMap.Successor (index);
  480.     if (l < 0)
  481.         return 0L;
  482.     if (l < UNUSED_BITS)
  483.         ret = __MakeHandle (l, l);
  484.     else {
  485.         if (!_file.Read (_BlockBitmapOffset (l), block_map)) {
  486.             _DoError ("_NextRecord:  block bitmap read 2", 0);
  487.             return 0;
  488.         }
  489.         ret = __MakeHandle (block_map.Smallest(), l);
  490.     }
  491.     return RetrieveRecord (ret, record) ? ret : 0;
  492. }
  493.  
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500. /* ------------------------------------------------------------------ */
  501.  
  502.  
  503.  
  504. // Protected methods:
  505.  
  506. static long __BlockMapWidth ()
  507. {
  508.     static long width = -1;
  509.     if (width == -1) {
  510.         CL_BitSet  block_map (RECORDS_PER_BLOCK);
  511.         width = block_map.StorableFormWidth ();
  512.     }
  513.     return width;
  514. }
  515.  
  516.  
  517. /* ------------------------------------------------------------------ */
  518.  
  519. CL_Offset CL_SlottedFile::_BlockBitmapOffset (ushort index) const
  520. {
  521.     long n = CL_SlottedFileHeader::StoreWidth() + _userHeaderSize;
  522.     if (index < UNUSED_BITS) {
  523.         // We're talking about a record, not a bitmap
  524.         return  n + index * _slotSize;
  525.     }
  526.     return n + UNUSED_BITS * _slotSize
  527.         + (index - UNUSED_BITS) * (__BlockMapWidth() +
  528.                                    RECORDS_PER_BLOCK * _slotSize);
  529. }
  530.  
  531.  
  532. /* ------------------------------------------------------------------ */
  533.  
  534.  
  535. CL_Offset        CL_SlottedFile::_RecordOffset
  536.     (CL_SlottedFileHandle h) const
  537. {
  538.     long n = __BlockMapIndex(h);
  539.     CL_Offset offset = _BlockBitmapOffset (n);
  540.     if (n >= UNUSED_BITS) {
  541.         CL_BitSet block_map (RECORDS_PER_BLOCK);
  542.         offset += _slotSize * __RecordNumber (h)
  543.             + block_map.StorableFormWidth();
  544.     }
  545.     return offset;
  546. }
  547.  
  548.  
  549. /* ------------------------------------------------------------------ */
  550.  
  551.  
  552.  
  553. CL_SlottedFileHandle CL_SlottedFile::_GetSlot ()
  554. {
  555.     if (!_ReadHeader (*_header)) {
  556.         _DoError ("_GetSlot: header read", 0);
  557.         return 0;
  558.     }
  559.     if (_header->fullMap.IsUniversal ()) {
  560.         // No more slots available!
  561.         return 0;
  562.     }
  563.  
  564.     long index = _header->fullMap.SmallestNonMember ();
  565.     long record_no;
  566.     if (index <  UNUSED_BITS) {
  567.         // We're allocating in the low end of the file
  568.         record_no = index;
  569.         _header->fullMap.Add (index);
  570.         _header->nonemptyMap.Add (index);
  571.     }
  572.     else {
  573.         // We're allocating in the high end
  574.         CL_Offset offset = _BlockBitmapOffset (index);
  575.         if (offset >= _file.Size()) {
  576.             // File too small, create the level-1 map
  577.             CL_BitSet block_map (RECORDS_PER_BLOCK);
  578.             block_map.Add (0);
  579.             if (!_file.Write (offset, block_map)) {
  580.                 _DoError ("_GetSlot: block_map write", 0);
  581.                 return 0;
  582.             }
  583.             record_no = 0;
  584.             _header->nonemptyMap.Add (index);
  585.         }
  586.         else {
  587.             // File large enough, level-1 map exists
  588.             CL_BitSet block_map;
  589.             if (!_file.Read (offset, block_map)) {
  590.                 _DoError ("_GetSlot:  block bitmap read", 0);
  591.                 return 0;
  592.             }
  593. #ifdef ERROR_CHECKS
  594.             if (block_map.IsUniversal ()) {
  595.                 // Something wrong
  596.                 CL_Error::Warning ("_GetSlot: internal error: block_map full");
  597.                 return 0;
  598.             }
  599. #endif
  600.             record_no = block_map.SmallestNonMember ();
  601.             block_map.Add (record_no);
  602.             if (!_file.Write (offset, block_map)) {
  603.                 _DoError ("_GetSlot: block_map write back", 0);
  604.                 return 0;
  605.             }
  606.             _header->nonemptyMap.Add (index);
  607.             if (block_map.IsUniversal ()) 
  608.                 _header->fullMap.Add (index);
  609.         }
  610.     }
  611.     _header->allocCount++;
  612.     if (!_WriteHeader (*_header)) {
  613.         _DoError ("_GetSlot: header write back", 0);
  614.         return 0;
  615.     }
  616.     CL_SlottedFileHandle h;
  617.     h = __MakeHandle (record_no, index);
  618.     return h;
  619. }
  620.  
  621. /* ------------------------------------------------------------------ */
  622.  
  623.  
  624. void CL_SlottedFile::_DoError (const char* caller,
  625.                                CL_SlottedFileHandle h) const
  626. {
  627.     if (_reportErrors)
  628.         CL_Error::Warning ("CL_SlottedFile::%s: handle %ld:"
  629.                            "I/O error %s", caller, h,
  630.                            _file.ErrorString().AsPtr());
  631. }
  632.     
  633.  
  634.  
  635.  
  636.  
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643.  
  644.  
  645. // ------------------------ CL_PrivateSlottedFile methods ----------------
  646.  
  647.  
  648.  
  649. CL_PrivateSlottedFile::CL_PrivateSlottedFile (const char* path, bool report)
  650.     : CL_SlottedFile ( * (_ourFile = new CL_BinaryFile (path)), report)
  651. {
  652.     if (!_header || !_ourFile)
  653.         return; // No memory
  654.     _weOwnIt = TRUE;
  655.     if (!_file.SeekTo (0) || !_header->ReadFrom (_file)) {
  656.         CL_Error::Fatal
  657.             ("CL_PrivateSlottedFile constructor: "
  658.              "file '%s' is not a slotted file", path);
  659.     }
  660.     _slotSize = _header->slotSize;
  661.     _userHeaderSize = _header->userHeaderSize;
  662. }
  663.  
  664.  
  665. /* ------------------------------------------------------------------ */
  666.  
  667.  
  668.  
  669. CL_PrivateSlottedFile::CL_PrivateSlottedFile
  670.     (const char* path, long record_size, short user_hdr, bool report)
  671.     : CL_SlottedFile (* (_ourFile =
  672.                          new CL_BinaryFile (path, TRUE)),
  673.                       report)
  674. {
  675.     if (!_header)
  676.         return; // No memory
  677.     _header->allocCount = 0;
  678.     _header->slotSize   = record_size;
  679.     _userHeaderSize = _header->userHeaderSize = user_hdr;
  680.     _slotSize      = record_size;
  681.     if (!_WriteHeader (*_header)) {
  682.         _DoError ("constructor: header write", 0);
  683.         return;
  684.     }
  685.     if (user_hdr > 0) {
  686.         CL_ByteString dummy (user_hdr);
  687.         WriteHeader (dummy);
  688.     }
  689.     _weOwnIt = TRUE;
  690. }
  691.  
  692.  
  693. /* ------------------------------------------------------------------ */
  694.  
  695. CL_PrivateSlottedFile::CL_PrivateSlottedFile (CL_Stream& file,
  696.                                               bool report)
  697. : CL_SlottedFile (file, report)
  698. {
  699.     _weOwnIt = FALSE;
  700.     _ourFile = NULL;
  701.     if (!_header)
  702.         return; // No memory
  703.     if (!_file.SeekTo (0) || !_header->ReadFrom (_file)) {
  704.         CL_Error::Fatal ("CL_PrivateSlottedFile constructor: "
  705.                          "stream is not a slotted file");
  706.     }
  707.     _slotSize = _header->slotSize;
  708.     _userHeaderSize = _header->userHeaderSize;
  709. }
  710.  
  711. /* ------------------------------------------------------------------ */
  712.  
  713. CL_PrivateSlottedFile::CL_PrivateSlottedFile (CL_Stream& file,
  714.                                               long record_size,
  715.                                               short user_hdr,
  716.                                               bool report)
  717. : CL_SlottedFile (file, report)
  718. {
  719.     _weOwnIt = FALSE;
  720.     _ourFile = NULL;
  721.     if (!_header)
  722.         return; // No memory
  723.     _header->allocCount = 0;
  724.     _header->slotSize   = record_size;
  725.     _slotSize           = record_size;
  726.     _userHeaderSize     = _header->userHeaderSize = user_hdr;
  727.     if (!_WriteHeader (*_header)) {
  728.         _DoError ("constructor: header write", 0);
  729.     }
  730. }
  731.  
  732.  
  733. /* ------------------------------------------------------------------ */
  734.  
  735. CL_PrivateSlottedFile::~CL_PrivateSlottedFile()
  736. {
  737.     if (!_file.SeekTo (0) || !_header->WriteTo (_file)) {
  738.         CL_Error::Warning ("CL_PrivateSlottedFile destructor: "
  739.                          "header write failed");
  740.     }
  741.     if (_weOwnIt)
  742.         delete _ourFile;
  743. }
  744.  
  745.  
  746. /* ------------------------------------------------------------------ */
  747.  
  748.  
  749. bool CL_PrivateSlottedFile::_ReadHeader (CL_SlottedFileHeader& hdr) const
  750. {
  751.     if (&hdr != _header)
  752.         hdr = *_header;
  753.     return (_header != NULL);
  754. }
  755.  
  756.  
  757.  
  758. /* ------------------------------------------------------------------ */
  759.  
  760. bool CL_PrivateSlottedFile::_WriteHeader (const CL_SlottedFileHeader&) const
  761. {
  762. //     if (_header != NULL && _file.SeekToBegin ()) {
  763. //         _file << (*_header);
  764. //         return TRUE;
  765. //     }
  766. //     return FALSE;
  767.     return TRUE;
  768. }
  769.  
  770.  
  771.  
  772.  
  773.  
  774.  
  775.  
  776.  
  777.  
  778.  
  779. CL_SlottedFileIterator::CL_SlottedFileIterator (const CL_SlottedFile& file)
  780. : _rootIter (_root), _blockIter (_block), _sfile (file)
  781. {
  782.     _header = new CL_SlottedFileHeader;
  783. }
  784.  
  785.  
  786. CL_SlottedFileIterator::CL_SlottedFileIterator
  787.     (const CL_SlottedFileIterator& iter)
  788. : _rootIter (_root), _blockIter (_block), _sfile (iter._sfile)
  789. {
  790.     _header = new CL_SlottedFileHeader;
  791. }
  792.  
  793. CL_SlottedFileIterator::~CL_SlottedFileIterator ()
  794. {
  795.     delete _header;
  796. }
  797.  
  798. void CL_SlottedFileIterator::Reset ()
  799. {
  800.     if (!_sfile._ReadHeader (*_header)) {
  801.         _sfile._DoError ("Reset: root bitmap read", 0);
  802.         return;
  803.     }
  804.     _root = _header->nonemptyMap;
  805.     _block.MakeEmpty ();
  806.     _rootIter.Reset ();
  807.     _blockIter.Reset ();
  808.     _blockIndex = -1;
  809. }
  810.  
  811.  
  812. CL_SlottedFileHandle CL_SlottedFileIterator::Next (uchar* record)
  813. {
  814.     // At the end of execution of this method, _blockIndex will be the
  815.     // block-map index of the record being returned (or the record index
  816.     // itself, if the value is less than UNUSED_BITS).
  817.     CL_SlottedFileHandle ret_val;
  818.     short rec_no;
  819.     if (!_blockIter.More()) {
  820.         if (!_rootIter.More()) {
  821.             // Iteration finished
  822.             return 0;
  823.         }
  824.         _blockIndex = _rootIter.Next();
  825.         if (_blockIndex < UNUSED_BITS)
  826.             rec_no = _blockIndex;
  827.         else {
  828.             if (!_sfile._file.Read (_sfile._BlockBitmapOffset (_blockIndex),
  829.                                     _block)) {
  830.                 _sfile._DoError ("Next: level-1 map read failed");
  831.                 return 0;
  832.             }
  833.             _blockIter.Reset ();
  834.             rec_no = _blockIter.Next();
  835.         }
  836.     }
  837.     else
  838.         rec_no = _blockIter.Next();
  839.     long slot_size = _sfile._slotSize;
  840.     ret_val = __MakeHandle (rec_no, _blockIndex);
  841.     if (_sfile._file.Read (_sfile._RecordOffset (ret_val), record,
  842.                            slot_size) != 
  843.         slot_size) {
  844.         _sfile._DoError ("Next: record read failed", ret_val);
  845.         return 0;
  846.     }
  847.     return ret_val;
  848. }
  849.  
  850.  
  851.  
  852.  
  853.  
  854.  
  855.