home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / db02_bin.zip / manual.txt < prev    next >
Text File  |  1994-02-22  |  98KB  |  3,855 lines

  1.  
  2.  
  3.  
  4.  
  5. DiamondBase  Documentation
  6.  
  7.  
  8.                Version  0.2
  9.  
  10.  
  11.  
  12.                  Darren Platt
  13.  
  14.                Andrew Davison
  15.  
  16.                  Kevin Lentin
  17.  
  18.  
  19.  
  20.     darrenp@dibbler.cs.monash.edu.au
  21.  
  22.      davison@bruce.cs.monash.edu.au
  23.  
  24.       kevinl@bruce.cs.monash.edu.au
  25.  
  26.  
  27.  
  28.                January 18, 1994
  29.  
  30.  
  31.  
  32.  
  33. 2
  34.  
  35. DiamondBase_______________________________________________________________1_
  36.  
  37.  
  38.  
  39. 1    What Is DiamondBase ?
  40.  
  41.  
  42.  
  43. 1.1    Description
  44.  
  45.  
  46. DiamondBase is an implementation of a programmer's database. It supports the
  47.  
  48. basic relational model via a schema compiler and the C++ language. It has been
  49.  
  50. designed to make usage of the resulting relations simply, via object methods. It
  51.  
  52. was written by three students at Monash University Melbourne, Australia in their
  53.  
  54. spare time, because they are crazy, and have always harboured secret ambitions
  55.  
  56. to write a database.  Kevin's previously frustrated attempts met with Darren's
  57.  
  58. misguided notions that a database would make his PhD easier to write, and Andy
  59.  
  60. wanted a database for a bibliographic retrieval system called Bibel. And so the
  61.  
  62. three muskateers set off in search of adventure.
  63.  
  64.  
  65.  
  66. 1.2    Platforms
  67.  
  68.  
  69. DiamondBase has been compiled for Linux, Ultrix, SunOS 4.1.1 using GCC, for
  70.  
  71. Irix using GCC and CFRONT and OS/2 with the Borland Compiler. It has also
  72.  
  73. been successfully compiled and used on an Amiga using SASC, NeXT using GCC
  74.  
  75. and on an RS6000. It currently requires gnu-make for its makefile, but a generic
  76.  
  77. Makefile is provided.
  78.  
  79.  
  80.  
  81. 1.3    Distribution
  82.  
  83.  
  84. Read the Copyright message in the distribution.
  85.  
  86.  
  87.  
  88. 1.4    Limitations
  89.  
  90.  
  91. 1.4.1  Introduction
  92.  
  93.  
  94. This section is depressingly large at the moment. It outlines the areas where we
  95.  
  96. believe Diamondbase is currently deficient. This is by no means an exhaustive l*
  97.  *ist,
  98.  
  99. and we are open to suggestions for improvements. Having listed the deficiencies,
  100.  
  101. it should also be noted that there are no fixed plans to eliminate these defici*
  102.  *encies.
  103.  
  104.    Database extension is currently driven by the whims and requirements of the
  105.  
  106. authors. We are quite open to accepting extensions written by other people - so
  107.  
  108. submit that SQL parser as soon as you have written it.
  109.  
  110.  
  111.  
  112. 1.4.2  Limited Multi-User Support
  113.  
  114.  
  115. This is a pretty major restriction at the moment. You should ensure that only
  116.  
  117. one copy of your application is in use at any one time.
  118.  
  119. 2___________________________________________________What_Is_DiamondBase_?__
  120.  
  121.  
  122.  
  123.     Multi-user support is now available under Linux, Ultrix and Sunos.  In its
  124.  
  125. current incarnation it is setup to run under one user-id. It can very easily be*
  126.  * run
  127.  
  128. by multiple people. It must run on one machine.
  129.  
  130.     We believe the Irix port of this part of the product should be merely a com*
  131.  *pi-
  132.  
  133. lation issues. The Amiga and OS/2 versions may require more work. The OS/2
  134.  
  135. version should be available very soon.
  136.  
  137.  
  138.  
  139. 1.4.3   No multi-machine support
  140.  
  141.  
  142. The multi-user support uses shared memory segments and IPC communication. It
  143.  
  144. can therefore not be used over multiple machines. It can be moved from machine
  145.  
  146. to machine, but at any one time, all clients must be on the same machine as the
  147.  
  148. server.
  149.  
  150.     We have used the UNIX ndbm package to implement a multi-user database
  151.  
  152. by accepting connections on a socket and multi-threading the executable. There
  153.  
  154. is only one server process accessing the database but many clients can use it
  155.  
  156. concurrently. If you are interested in such code please let us know.
  157.  
  158.  
  159.  
  160. 1.4.4   No SQL
  161.  
  162.  
  163. I'm philosophical on this point. SQL isn't god's gift to query languages (It's *
  164.  *more
  165.  
  166. like satan's if the truth is to be known).  I would however like to add a query
  167.  
  168. language to DiamondBase at some stage, and SQL is certainly a standard choice.
  169.  
  170. The reliance on compiled code to do the comparison makes an interactive SQL
  171.  
  172. setup more difficult since it would have to second-guess the compiler's layout *
  173.  *for
  174.  
  175. data structures - or dynamically link the comparison code.
  176.  
  177.     Embedded SQL would be easier to implement. It would require a compiler to
  178.  
  179. preprocess the SQL (preferably not by extracting it from the C++ - but having
  180.  
  181. queries stored in separate text files) - and then generate C++ code to access t*
  182.  *he
  183.  
  184. objects in the right order.
  185.  
  186.  
  187.  
  188. 1.4.5   No duplicate indexes
  189.  
  190.  
  191. This is a nuisance as much as anything. All records must have a unique value for
  192.  
  193. each index. If you wish to effectively have duplicates, then you must supply an
  194.  
  195. extra field which makes them unique.
  196.  
  197.     So, for example, if you wish to index employees by age, then you would also
  198.  
  199. include employee number in the index.  Finding all the employees who are 12
  200.  
  201. years old then involves finding the first record with age=12 and id>=0. Continue
  202.  
  203. fetching the next record until age is not equal to 12.
  204.  
  205.     This approach is a bit messy and labour intensive, so we would like to perm*
  206.  *it
  207.  
  208. duplicates - if we can work out what it will do to the poor Btrees.
  209.  
  210.     The package does, however, support a unique type.  This is a long that is
  211.  
  212. assigned a value by DiamondBase and is guaranteed to be unique within the
  213.  
  214. DiamondBase_______________________________________________________________3_
  215.  
  216.  
  217.  
  218. relation.  Included in an index, it allows effectively for duplicate indexes wi*
  219.  *th
  220.  
  221. much better semantics.
  222.  
  223.  
  224.  
  225. 1.4.6  Recovery and Auditing
  226.  
  227.  
  228. The Btree indexes can be built from the data storage file if they become corrup*
  229.  *ted
  230.  
  231. - but no facility currently exists to do this. A record dump facility to dump t*
  232.  *he
  233.  
  234. records in the record store to a text file is currently available in the form o*
  235.  *f the
  236.  
  237. db2txt program. There is no auditing to keep track of all transactions that were
  238.  
  239. performed. This is not a high priority for us currently. If this is a high prio*
  240.  *rity
  241.  
  242. for you then please let us know how you would like it done.
  243.  
  244.  
  245.  
  246. 1.4.7  Static limits
  247.  
  248.  
  249. Various components of the database have static limits.  These are listed in the
  250.  
  251. table below along with a description and the file in which they are defined bel*
  252.  *ow.
  253.  
  254.      __________________________________________________________________
  255.      _ Name/Description                         _Value _Where          _
  256.      ___________________________________________________________________
  257.      _ MAX_QUERY                                _10    _defs.h          _
  258.      _                                         ________________________ _
  259.      _ The maximum number of queries that a bTree or dbObj will allow.  _
  260.      __________________________________________________________________ _
  261.      _ MAX_REG                                  _20    _dbase.h         _
  262.      _                                         ________________________ _
  263.      _ The maximum number of registrations that the dbObj will allow.   _
  264.      __________________________________________________________________ _
  265.      _ MAX_DB_INFO                              _20    _dbase.h         _
  266.      _                                         ________________________ _
  267.      _ The maximum number of relations that the dbObj will keep open.  _
  268.      ___________________________________________________________________
  269.      _ MAX_RELATIONS                            _20    _nserver.h       _
  270.      _                                         ________________________ _
  271.      _ The maximum number of relations that the nameserver can handle. _
  272.      ___________________________________________________________________
  273.      _ MAX_FIELDS_IN_INDEX                      _10    _idxinfo.h       _
  274.      _                                         ________________________ _
  275.      _ The maximum number of fields that an index is permitted to have.  _
  276.      __________________________________________________________________  _
  277.      _ MAX_NAME_LENGTH                          _300   _idxinfo.h       _
  278.      _                                         ________________________ _
  279.      _ The maximum length that an index name can be.                  _
  280.      ___________________________________________________________________
  281.      _ MAX_TRANS_AREA                           _4K    _dcdefs.h        _
  282.      _                                         ________________________ _
  283.      _ The maximum relation size for the multi version                   _
  284.      __________________________________________________________________  _
  285.  
  286.  
  287. 1.4.8  Fixed length records
  288.  
  289.  
  290. Records are currently of a fixed length determined at the creation of the relat*
  291.  *ion.
  292.  
  293. Support for variable length fields is available though the dbData and dbString
  294.  
  295. types.  The first is a generic binary object.  The second is a derivative which
  296.  
  297. behaves like a null terminated string. Details of these features are in Section*
  298.  * 5.
  299.  
  300. 4________________________________________________________Interface_Functions_
  301.  
  302.  
  303.  
  304. 2     Interface Functions
  305.  
  306.  
  307.  
  308. 2.1    Introduction
  309.  
  310.  
  311. This section describes the basic application functions available to the program-
  312.  
  313. mer. They are supplied as methods to the relation class generated by dsc.
  314.  
  315.  
  316.  
  317. 2.1.1   General functions
  318.  
  319.  
  320.     fflbool  ok(void)
  321.  
  322.  
  323.         -  Description
  324.  
  325.                Checks if last database operation was successful.
  326.  
  327.         -  Return codes
  328.  
  329.                true - successful operation
  330.  
  331.                false - unsuccessful operation
  332.  
  333.         -  Example
  334.  
  335.  
  336.            fred yourRel;
  337.  
  338.  
  339.  
  340.            yourRel.add();
  341.  
  342.  
  343.  
  344.            if  (!yourRel.ok()) -
  345.  
  346.                cerr << "An error occurred." << endl;
  347.  
  348.            "
  349.  
  350.  
  351.     fflvoid  perror(char  *description)
  352.  
  353.  
  354.         -  Description
  355.  
  356.                Prints a textual description of the last error code to cout -
  357.  
  358.                with some textual prefix which you supply.
  359.  
  360.         -  Example
  361.  
  362.  
  363.            fred yourRel;
  364.  
  365.  
  366.  
  367.            yourRel.id = 1234; // Which doesn't exist
  368.  
  369.            yourRel.get();
  370.  
  371.  
  372.  
  373.            if  (!yourRel.ok()) -
  374.  
  375.                    yourRel.perror("Getting a record:");
  376.  
  377.            "
  378.  
  379.  
  380.     fflvoid  stats(void)
  381.  
  382. DiamondBase_______________________________________________________________5_
  383.  
  384.  
  385.  
  386.         - Description
  387.  
  388.               Outputs the current database cache hit statistics to cout for
  389.  
  390.               this relation.
  391.  
  392.         - Example
  393.  
  394.  
  395.           yourReltype yourRel;
  396.  
  397.  
  398.  
  399.           yourRel.stats();
  400.  
  401.  
  402.  
  403.           Output..
  404.  
  405.  
  406.  
  407.           Record Server cache: 1669 attempts, 146 hits = 8.74775%
  408.  
  409.                    1523 writes and 1513 disposals
  410.  
  411.           Index 0 cache: 0 attempts, 0 hits = 0%
  412.  
  413.                    0 writes and 0 disposals
  414.  
  415.           Index 1 cache: 593 attempts, 454 hits = 76.5599%
  416.  
  417.                    139 writes and 129 disposals
  418.  
  419.           Index 2 cache: 3 attempts, 0 hits = 0%
  420.  
  421.                    3 writes and 0 disposals
  422.  
  423.  
  424.  
  425. 2.1.2  Database Manipulation functions
  426.  
  427.  
  428.    ffldbError add(void)
  429.  
  430.  
  431.         - Description
  432.  
  433.               Insert the current values for this relation into the database.
  434.  
  435.               Any fields which are of type unique will be assigned a unique
  436.  
  437.               field as the record is inserted.  The corresponding fields of
  438.  
  439.               the structure will reflect these assigned values upon return.
  440.  
  441.               The data in the object is not modified by the call (except the
  442.  
  443.               unique field).
  444.  
  445.         - Return codes
  446.  
  447.               db_ok - successful addition
  448.  
  449.               db_dup - addition of this record would create a duplicate record
  450.  
  451.               on one or more indexes.
  452.  
  453.               db_nopen - database isn't currently open.
  454.  
  455.         - Example
  456.  
  457.  
  458.           employee     newEmp;
  459.  
  460.  
  461.  
  462.           strcpy(newEmp.name,"Joe Bloggs");
  463.  
  464.           newExp.age = 12;
  465.  
  466. 6________________________________________________________Interface_Functions_
  467.  
  468.  
  469.  
  470.            switch(newExp.add()) -
  471.  
  472.                case db_ok: break;
  473.  
  474.                case db_dup:
  475.  
  476.                    cerr << "This employee already exists" << endl;
  477.  
  478.                    break;
  479.  
  480.                case db_nopen:
  481.  
  482.                    cerr << "Open the database first dummy" << endl;
  483.  
  484.            "
  485.  
  486.  
  487.     ffldbError begin(int indexNumber = 0)
  488.  
  489.  
  490.         -  Description
  491.  
  492.                A call to begin initiates a query - signalling an intention to
  493.  
  494.                retrieve one or more records from the database using a partic-
  495.  
  496.                ular index. Within a query, an implicit pointer is maintained
  497.  
  498.                to a position within an ordered index list.
  499.  
  500.                Whilst direct fetches with get may be executed without a
  501.  
  502.                begin/end pair - begin must be used with all relational retrieval
  503.  
  504.                operations.  If a previous begin is outstanding when this is
  505.  
  506.                called, the previous query is terminated. You should therefore
  507.  
  508.                not use get inside a begin/end pair of the same instance of a
  509.  
  510.                relation as the get will terminate the query.  If you use 2
  511.  
  512.                different instances of the relation, then it will work correctly
  513.  
  514.                as each has its own query.
  515.  
  516.                The following functions require a query and must therefore
  517.  
  518.                be executed within a begin/end pair.
  519.  
  520.                   extract
  521.  
  522.                   extractNext
  523.  
  524.                   extractPrev
  525.  
  526.                   find
  527.  
  528.                   first
  529.  
  530.                   last
  531.  
  532.                   next
  533.  
  534.                   peekNext
  535.  
  536.                   peekPrev
  537.  
  538.                   prev
  539.  
  540.                   seek
  541.  
  542.                   seekFirst
  543.  
  544.                   seekLast
  545.  
  546.                   write
  547.  
  548. DiamondBase_______________________________________________________________7_
  549.  
  550.  
  551.  
  552.         - Return codes
  553.  
  554.               db_ok - the query started correctly
  555.  
  556.               db_range - the supplied index is out of range
  557.  
  558.         - Example
  559.  
  560.  
  561.  
  562.           // Retrieve all employees' names.
  563.  
  564.           employee tempEmp;
  565.  
  566.  
  567.  
  568.           tempEmp.begin(dbIdx_name); // Initiate query
  569.  
  570.  
  571.  
  572.           for(tempEmp.first();tempEmp.ok();tempEmp.next()) -
  573.  
  574.               cout << tempEmp.name << endl;
  575.  
  576.           "
  577.  
  578.  
  579.  
  580.           // The same thing, using a while instead
  581.  
  582.  
  583.  
  584.           tempEmp.seekFirst();
  585.  
  586.  
  587.  
  588.           while(tempEmp.next() != db_eof) -
  589.  
  590.               cout << tempEmp.name << endl;
  591.  
  592.           "
  593.  
  594.  
  595.  
  596.           tempEmp.end();
  597.  
  598.  
  599.    ffldbError del(void)
  600.  
  601.  
  602.         - Description
  603.  
  604.               Delete the record matching the current values for the index
  605.  
  606.               from the database. The data in the object is not modified by
  607.  
  608.               the call.
  609.  
  610.         - Return codes
  611.  
  612.               db_ok - successful deletion
  613.  
  614.               db_nfound - Couldn't find record to delete it
  615.  
  616.         - Example
  617.  
  618.  
  619.           employee exEmp;
  620.  
  621.  
  622.  
  623.           exEmp.id = 1234; // Employee id to delete.
  624.  
  625.           exEmp.get(); // Fetch this employee.
  626.  
  627.           if (exEmp.ok()) -
  628.  
  629.               if (exEmp.del()==db_nfound) -
  630.  
  631. 8________________________________________________________Interface_Functions_
  632.  
  633.  
  634.  
  635.                    cout << "Couldn't find employee" << endl;
  636.  
  637.                "
  638.  
  639.            "
  640.  
  641.  
  642.     ffldbError end(void)
  643.  
  644.  
  645.         -  Description
  646.  
  647.                End the previously initiated query.  This is mainly for effi-
  648.  
  649.                ciency reasons, and to terminate any outstanding locks, since
  650.  
  651.                the next begin will automatically terminate the previous begin
  652.  
  653.                anyway.
  654.  
  655.         -  Return codes
  656.  
  657.                db_ok - no problems.
  658.  
  659.                db_noquery - there was no matching begin.
  660.  
  661.                db_range - query value was not in the valid range
  662.  
  663.         -  Example - see begin
  664.  
  665.  
  666.     ffldbError extract(void)
  667.  
  668.  
  669.         -  Description
  670.  
  671.                This call does a find on the supplied object and then locks the
  672.  
  673.                object if it is found. The record itself is locked, not the key
  674.  
  675.                being used, so accesses to the record through any key will fail.
  676.  
  677.                After an extract, any access of the record will return db_locked
  678.  
  679.                . If this access is an extract, an extract will not occur and the
  680.  
  681.                operation will be equivalent to a find. If the access is another
  682.  
  683.                read-type operation - then the data will be retrieved. If this
  684.  
  685.                access is a write, then it will fail.
  686.  
  687.                If the requested record does not exist, then the data in the
  688.  
  689.                object is not modified. In that situation, extract degenerates
  690.  
  691.                to a seek.
  692.  
  693.         -  Example
  694.  
  695.         -  Return codes
  696.  
  697.                db_nfound
  698.  
  699.                db_ok
  700.  
  701.                db_locked
  702.  
  703.  
  704.     ffldbError find(void)
  705.  
  706.  
  707.         -  Description
  708.  
  709. DiamondBase_______________________________________________________________9_
  710.  
  711.  
  712.  
  713.               Search for the index entry in the database. If the entry exists,
  714.  
  715.               then the query pointer is positioned at that point and the
  716.  
  717.               record is retrieved.  Otherwise, the pointer is moved to the
  718.  
  719.               following record, and that record is retrieved.
  720.  
  721.               Note that since the retrieval of that record involves a call to
  722.  
  723.               next, subsequent calls to next will not return this same record.
  724.  
  725.               If you wish to position the relation before a record without
  726.  
  727.               advancing the record pointer, use the seek family of functions
  728.  
  729.               instead.
  730.  
  731.         - Return codes
  732.  
  733.               db_ok - a matching record was found retrieved
  734.  
  735.               db_nfound - no matching record was found and the data for the
  736.  
  737.               next record was placed in the class.
  738.  
  739.               db_locked - the record was found and was locked. The data is still
  740.  
  741.               returned however.
  742.  
  743.               db_range - query value was not in the valid range
  744.  
  745.               db_noquery - query value was not valid
  746.  
  747.         - Example
  748.  
  749.  
  750.           employee exEmp;
  751.  
  752.  
  753.  
  754.           exEmp.id = 1234; // Employee id to find.
  755.  
  756.           exEmp.find(); // Fetch this employee.
  757.  
  758.  
  759.  
  760.    ffldbError first(void)
  761.  
  762.  
  763.         - Description
  764.  
  765.               The first function may only be executed from within a query
  766.  
  767.               (see begin).  It sets the query pointer to the first record and
  768.  
  769.               returns the record at that position if one exists.
  770.  
  771.               Note, that since first retrieves the first record, a subsequent
  772.  
  773.               call to next will not return that record. Instead, it will return
  774.  
  775.               the second record. See seekFirst.
  776.  
  777.         - Return codes
  778.  
  779.               db_nfound - there are no records in the database
  780.  
  781.               db_range - query value was not in the valid range
  782.  
  783.               db_noquery - query value was not valid
  784.  
  785.         - Example - see begin
  786.  
  787.  
  788.    ffldbError get(int idxNumber=0)
  789.  
  790. 10_______________________________________________________Interface_Functions_
  791.  
  792.  
  793.  
  794.         -  Description
  795.  
  796.                Retrieve a record from the database using explicit values for
  797.  
  798.                an index. This is the only retrieval function which does not
  799.  
  800.                need to be executed within a begin/end pair.  The function
  801.  
  802.                issues an implicit begin/end pair around this atomic opera-
  803.  
  804.                tion.
  805.  
  806.         -  Return codes
  807.  
  808.                db_ok - Record matching index value was found
  809.  
  810.                db_nfound - Record was not found
  811.  
  812.                db_range - the index specified was illegal
  813.  
  814.         -  Example
  815.  
  816.  
  817.            //
  818.  
  819.            // relation host_to_ip -
  820.  
  821.            //      char  hostname[100];
  822.  
  823.            //      char ip[16];
  824.  
  825.            //      index byIp    on ip;
  826.  
  827.            //      index byName on hostname;
  828.  
  829.            // "
  830.  
  831.            host_to_ip myLookup;
  832.  
  833.  
  834.  
  835.            strcpy(myLookup.hostname,"dibbler.cs.monash.edu.au");
  836.  
  837.  
  838.  
  839.            if (myLoopkup.get(dbIdx_byName)==db_ok) -
  840.  
  841.                cout << "IP=" << myLoopkup.ip << endl;
  842.  
  843.            " else -
  844.  
  845.                cout << "Not found" << endl;
  846.  
  847.            "
  848.  
  849.  
  850.     ffldbError last(void)
  851.  
  852.  
  853.         -  Description
  854.  
  855.                The last function may only be executed from within a query
  856.  
  857.                (see begin).  It sets the query pointer to the last record and
  858.  
  859.                returns the record at that position if one exists.
  860.  
  861.         -  Return codes
  862.  
  863.                db_ok - last record found and retrieved
  864.  
  865.                db_nfound - there were no records
  866.  
  867.                db_noquery - Last must be within a begin/end pair
  868.  
  869.         -  Example - see prev
  870.  
  871. DiamondBase_____________________________________________________________11_
  872.  
  873.  
  874.  
  875.    ffldbError next (void)
  876.  
  877.  
  878.         - Description
  879.  
  880.               This function may only be executed from within a query (see
  881.  
  882.               begin). It sets the query pointer to the next relation for the
  883.  
  884.               current query index and retrieves it if it exists.
  885.  
  886.         - Return codes
  887.  
  888.               db_ok - Next record is retrieved
  889.  
  890.               db_eof - No more following records
  891.  
  892.               db_noquery - Next was not executed within a begin/end pair
  893.  
  894.               db_locked - data retrieved but record locked by someone else
  895.  
  896.         - Example -see begin
  897.  
  898.  
  899.    ffldbError peekNext(void)
  900.  
  901.  
  902.         - Description
  903.  
  904.               Return next record if it exists, but do not advance the btree
  905.  
  906.               query pointer. Subsequent next, prev, peekNext and peekPrev
  907.  
  908.               calls will return values as if this call never occurred.
  909.  
  910.         - Return codes
  911.  
  912.               db_ok - Next record is read
  913.  
  914.               db_eof - No more following records
  915.  
  916.               db_noquery - Next was not executed within a begin/end pair
  917.  
  918.               db_range - query value was not in the valid range
  919.  
  920.               db_locked - data is retrieved but record is locked
  921.  
  922.         - Example
  923.  
  924.  
  925.  
  926.           // Given the records,
  927.  
  928.           // JONES,PERCY,PLATT and SMITH
  929.  
  930.  
  931.  
  932.           employee tempEmp;
  933.  
  934.  
  935.  
  936.           strcpy(tempEmp.name,"PLATT");
  937.  
  938.           tempEmp.begin(dbIdx_name); // Initiate query
  939.  
  940.           tempEmp.find(); // Fetches PLATT
  941.  
  942.  
  943.  
  944.           tempEmp.peekNext();
  945.  
  946.           cout << tempEmp.name << endl; // Prints SMITH
  947.  
  948. 12_______________________________________________________Interface_Functions_
  949.  
  950.  
  951.  
  952.            tempEmp.next();
  953.  
  954.            cout << tempEmp.name << endl; // Prints SMITH again
  955.  
  956.  
  957.  
  958.            tempEmp.end();
  959.  
  960.  
  961.     ffldbError peekPrev(void)
  962.  
  963.  
  964.         -  Description
  965.  
  966.                Return previous record if it exists, but do not move the btree
  967.  
  968.                query pointer. Subsequent next, prev, peekNext and peekPrev
  969.  
  970.                calls will return values as if this call never occurred.
  971.  
  972.         -  Return codes
  973.  
  974.                db_ok - Previous record is read
  975.  
  976.                db_eof - No more preceding records
  977.  
  978.                db_noquery - prev was not executed within a begin/end pair
  979.  
  980.                db_range - query value was not in the valid range
  981.  
  982.                db_locked - data is retrieved but record is locked
  983.  
  984.         -  Example
  985.  
  986.  
  987.  
  988.            // Given the records,
  989.  
  990.            // JONES,PERCY,PLATT and SMITH
  991.  
  992.  
  993.  
  994.            employee tempEmp;
  995.  
  996.  
  997.  
  998.            strcpy(tempEmp.name,"PLATT");
  999.  
  1000.            tempEmp.begin(dbIdx_name); // Initiate query
  1001.  
  1002.            tempEmp.find(); // Fetches PLATT
  1003.  
  1004.  
  1005.  
  1006.            // NB query pointer is now after PLATT
  1007.  
  1008.  
  1009.  
  1010.            tempEmp.peekPrev();
  1011.  
  1012.            cout << tempEmp.name << endl; // Prints PLATT !
  1013.  
  1014.  
  1015.  
  1016.            tempEmp.next();
  1017.  
  1018.            cout << tempEmp.name << endl; // Prints SMITH
  1019.  
  1020.  
  1021.  
  1022.            tempEmp.end();
  1023.  
  1024.  
  1025.     ffldbError prev(void)
  1026.  
  1027.  
  1028.         -  Description
  1029.  
  1030. DiamondBase_____________________________________________________________13_
  1031.  
  1032.  
  1033.  
  1034.               This function may only be executed from within a query (see
  1035.  
  1036.               begin). It sets the query pointer to the previous relation for
  1037.  
  1038.               the current query index and retrieves it if it exists.
  1039.  
  1040.         - Return codes
  1041.  
  1042.               db_ok - Previous record is retrieved
  1043.  
  1044.               db_eof - No more previous records
  1045.  
  1046.               db_noquery - Prev was not executed within a begin/end pair
  1047.  
  1048.               db_locked - data retrieved but record locked by someone else
  1049.  
  1050.         - Example
  1051.  
  1052.  
  1053.  
  1054.           // Retrieve all employees' names - but in reverse
  1055.  
  1056.           // order.
  1057.  
  1058.           employee tempEmp;
  1059.  
  1060.  
  1061.  
  1062.           tempEmp.begin(dbIdx_name); // Initiate query
  1063.  
  1064.  
  1065.  
  1066.           for(tempEmp.last();tempEmp.ok();tempEmp.prev()) -
  1067.  
  1068.               cout << tempEmp.name << endl;
  1069.  
  1070.           "
  1071.  
  1072.           tempEmp.end();
  1073.  
  1074.  
  1075.    ffldbError put(int idxNumber=0)
  1076.  
  1077.  
  1078.         - Description
  1079.  
  1080.               This function writes a record into the database regardless of
  1081.  
  1082.               its presence. If the record does not exist, this call does an add,
  1083.  
  1084.               otherwise it does a write. This call, like get does not require
  1085.  
  1086.               a query and, as such, contains an implicit begin/end pair. It
  1087.  
  1088.               can be used to write a record into the relation with no regard
  1089.  
  1090.               to the current contents.
  1091.  
  1092.         - Return codes
  1093.  
  1094.               db_ok - Record was successfully written
  1095.  
  1096.               db_dup - The record's keys partially clash with existing records
  1097.  
  1098.               db_range - the index specified was illegal
  1099.  
  1100.         - Example
  1101.  
  1102.  
  1103.  
  1104.           // relation host_to_ip -
  1105.  
  1106.           //      char  hostname[100];
  1107.  
  1108.           //      char ip[16];
  1109.  
  1110. 14_______________________________________________________Interface_Functions_
  1111.  
  1112.  
  1113.  
  1114.            //      index byIp    on ip;
  1115.  
  1116.            //      index byName on hostname;
  1117.  
  1118.            // "
  1119.  
  1120.            host_to_ip myLookup;
  1121.  
  1122.  
  1123.  
  1124.            strcpy(myLookup.hostname,"dibbler.cs.monash.edu.au");
  1125.  
  1126.            strcpy(myLookup.ip,"130.194.62.33");
  1127.  
  1128.  
  1129.  
  1130.            if (myLoopkup.put(dbIdx_byName)==db_ok) -
  1131.  
  1132.                cout << "Added successfullly" << endl;
  1133.  
  1134.            " else -
  1135.  
  1136.                cout << "Something went wrong" << endl;
  1137.  
  1138.            "
  1139.  
  1140.  
  1141.     ffldbError seek(void)
  1142.  
  1143.  
  1144.         -  Description
  1145.  
  1146.                Positions the query pointer using the values for the current
  1147.  
  1148.                query index.  The next record returned by a call to next or
  1149.  
  1150.                peekNext will be the record requested if it exists in the rela-
  1151.  
  1152.                tion, or the one that would follow it if it did exist.
  1153.  
  1154.         -  Return codes
  1155.  
  1156.                db_ok - The specific record was found.
  1157.  
  1158.                db_eof - No more preceding records
  1159.  
  1160.                db_noquery - prev was not executed within a begin/end pair
  1161.  
  1162.                db_range - query value was not in the valid range
  1163.  
  1164.                db_nfound - the specific record was not found.
  1165.  
  1166.         -  Example
  1167.  
  1168.  
  1169.     fflseekFirst
  1170.  
  1171.  
  1172.         -  Description
  1173.  
  1174.                Position the query pointer just before the first record for the
  1175.  
  1176.                current query index, so that the next record retrieved will
  1177.  
  1178.                be the first one. Like first, this call does not depend on the
  1179.  
  1180.                contents of the relation - it only moves to the beginning of
  1181.  
  1182.                the index.
  1183.  
  1184.         -  Return codes
  1185.  
  1186.         -  db_ok - The record was found.
  1187.  
  1188.         -  db_eof - No records
  1189.  
  1190.         -  db_noquery - seekFirst was not executed within a begin/end pair
  1191.  
  1192. DiamondBase_____________________________________________________________15_
  1193.  
  1194.  
  1195.  
  1196.         - db_range - query value was not in the valid range
  1197.  
  1198.         - Example
  1199.  
  1200.  
  1201.    ffldbError seekLast(void)
  1202.  
  1203.  
  1204.         - Description
  1205.  
  1206.               Position the query pointer just after the last record for the
  1207.  
  1208.               current query index, so that calling prev will retrieve the last
  1209.  
  1210.               record for that index.
  1211.  
  1212.         - Return codes
  1213.  
  1214.         - db_ok - The record was found.
  1215.  
  1216.         - db_eof - No records
  1217.  
  1218.         - db_noquery - seekLast was not executed within a begin/end pair
  1219.  
  1220.         - db_range - query value was not in the valid range
  1221.  
  1222.         - Example
  1223.  
  1224.  
  1225.    ffldbError write(void)
  1226.  
  1227.  
  1228.         - Description
  1229.  
  1230.               If all the keys are already present in the database and they all
  1231.  
  1232.               refer to the same record, then that record will be overwritten
  1233.  
  1234.               with the values in this class.  If all the keys are not present
  1235.  
  1236.               then the call fails.  The standard way to update a record is
  1237.  
  1238.               to perform an extract followed by a write.  If you wish to
  1239.  
  1240.               change one of the fields on which the record is indexed, then
  1241.  
  1242.               you must create a new record and copy the unchanged details
  1243.  
  1244.               from the old record to the new - followed by a deletion of the
  1245.  
  1246.               old record. This decision was made to considerably simplify
  1247.  
  1248.               the update mechanism within the database.
  1249.  
  1250.               If the write is being performed after an extract, then the keys
  1251.  
  1252.               are checked to ensure that they have not changed since the
  1253.  
  1254.               extract. If they have, then the write will fail. This last check
  1255.  
  1256.               is currently unimplemented.
  1257.  
  1258.         - Return codes
  1259.  
  1260.               db_ok - record was overwritten successfully
  1261.  
  1262.               db_dup - neither 0 nor all the indices matched
  1263.  
  1264.               db_range - query value was not in the valid range
  1265.  
  1266.               db_noquery - query value was not valid
  1267.  
  1268.               db_nfound - record is not already in the index
  1269.  
  1270.         - Example
  1271.  
  1272. 16_______________________________________________________Interface_Functions_
  1273.  
  1274.  
  1275.  
  1276. 2.1.3   Data Members
  1277.  
  1278.  
  1279. status
  1280.  
  1281.     Holds the return code from the last database operation.
  1282.  
  1283.     Error codes: db_ok ....
  1284.  
  1285. DiamondBase_____________________________________________________________17_
  1286.  
  1287.  
  1288.  
  1289. 3    Internals
  1290.  
  1291.  
  1292.  
  1293. 3.1    Introduction
  1294.  
  1295.  
  1296. As far as the big picture goes, you write a program which needs database func-
  1297.  
  1298. tions. You have used DSC to produce both the physical storage files, and some
  1299.  
  1300. compiler generated code which you link into your application.  You also link in
  1301.  
  1302. the diamond library which contains functions needed to perform the database
  1303.  
  1304. operations you execute as methods to DSC generated objects.
  1305.  
  1306.    This section of the manual describes how the internals of DiamondBase are
  1307.  
  1308. implemented.  We would like you to understand what is happening inside the
  1309.  
  1310. database - as this will aid you in debugging, reporting bugs within the database
  1311.  
  1312. code and suggesting improvements and changes.
  1313.  
  1314.  
  1315.  
  1316. 3.2    Typical application code
  1317.  
  1318.  
  1319.  
  1320. #include "myrel.h"
  1321.  
  1322.  
  1323.  
  1324. diamondBase theDiamondBase("config.db");
  1325.  
  1326.  
  1327.  
  1328. main()
  1329.  
  1330. -
  1331.  
  1332.     myRel theRel; // Attach stage          (a)
  1333.  
  1334.  
  1335.  
  1336.     theRel.begin();
  1337.  
  1338.     theRel.first();
  1339.  
  1340.     // Use theRel here.
  1341.  
  1342.  
  1343.  
  1344.     theRel.extract(); // Decide to update it.
  1345.  
  1346.     // Change some non-indexed member fields
  1347.  
  1348.  
  1349.  
  1350.     theRel.write(); // Put it back
  1351.  
  1352.     theRel.end();
  1353.  
  1354. "
  1355.  
  1356.  
  1357.  
  1358.    Note the appalling lack of error checking going on - utterly disgusting. The
  1359.  
  1360. definition for the 'myRel' class will inherit both a transfer area and a diaRel*
  1361.  * class.
  1362.  
  1363. The transfer area acts as a sub-struct with only data members which can be used
  1364.  
  1365. for memory transfers as records are stored and retrieved. The diaRel base class
  1366.  
  1367. has the necessary methods to implement the calls (eg first, next, write).
  1368.  
  1369.    Note that in the above example, the myRel instance was in scope for all of
  1370.  
  1371. main - it need not have been.  You can declare relations wherever you wish to
  1372.  
  1373. 18_________________________________________________________________Internals_
  1374.  
  1375.  
  1376.  
  1377. use them. Global relation instances are even permitted, provided you can ensure
  1378.  
  1379. that the theDiamondBase instance you declare is constructed first.
  1380.  
  1381.     Which brings me to the final point for this section - you must have an inst*
  1382.  *ance
  1383.  
  1384. of diamondBase called `theDiamondBase' at the global scope in your program.
  1385.  
  1386. We could have defined one ourselves in the library, but this way you get to name
  1387.  
  1388. the database configuration file.
  1389.  
  1390.  
  1391.  
  1392. 3.2.1   diaRel
  1393.  
  1394.  
  1395. There is one instance of diaRel in each user-defined relation class.  It imple-
  1396.  
  1397. ments the functions which are used to manipulate the database. diarel.h and
  1398.  
  1399. diarel.cc are fairly self explanatory. The constructor for diaRel attaches to t*
  1400.  *he
  1401.  
  1402. global theDiamondBase object and obtains a reference Id which is used in all
  1403.  
  1404. further correspondance up until the point where the class which inherits diaRel
  1405.  
  1406. has been destroyed.
  1407.  
  1408.     diaRel also inherits an object class. This has a number of pure virtual met*
  1409.  *hods
  1410.  
  1411. which the database ultimately uses to perform functions like fetching the data,
  1412.  
  1413. storing the data, extracting the key component of the data - comparing keys.
  1414.  
  1415. These functions are performed by DSC generated code and so a pointer to the
  1416.  
  1417. base object class is passed to theDiamondBase during attach in order to permit
  1418.  
  1419. this.
  1420.  
  1421.  
  1422.  
  1423. 3.2.2   diaGRel
  1424.  
  1425.  
  1426. The diaGRel (or Generic Relation) class can be used in place of a DSC generated
  1427.  
  1428. class to manipulate any relation you desire.  This can be used to write generic
  1429.  
  1430. relation browsers or such like. The use of the diaGRel class is described in de*
  1431.  *tail
  1432.  
  1433. in section 4.  diaGRel is used to implement the db2txt relation dumping utility,
  1434.  
  1435. and the server in the multi-user version.
  1436.  
  1437.  
  1438.  
  1439. 3.2.3   diamondBase
  1440.  
  1441.  
  1442. diamondBase has rather a large job.  It overseas all the classes which actually
  1443.  
  1444. manipulate the database. On construction it is supplied with a string which is a
  1445.  
  1446. path to the name server configuration file. This file is typically called "conf*
  1447.  *ig.db"
  1448.  
  1449. - although the default parameter is "ns.dbc".  This parameter is passed to the
  1450.  
  1451. base TNameServer class.
  1452.  
  1453.     As mentioned in the diaRel section, diamondBase handles incoming diaRel
  1454.  
  1455. connection requests - assigning a reference id to each new connection. A list of
  1456.  
  1457. such class clients is maintained.
  1458.  
  1459.     A list of active and recently deregistered relations is kept. Old relations*
  1460.  * are
  1461.  
  1462. kept to avoid unnecessary overhead when a relation class is repeatedly created
  1463.  
  1464. then destroyed. If multiple active diaRel classes are accessing the same relati*
  1465.  *on,
  1466.  
  1467. then only one relation is maintained for all of them.
  1468.  
  1469. DiamondBase_____________________________________________________________19_
  1470.  
  1471.  
  1472.  
  1473.    Each diaRel uses only one relation - and provides its name upon registration.
  1474.  
  1475. Failure to locate that database name using TNameServer is an error.
  1476.  
  1477.    Each relation has an associated pointer to a dbObj  through which all non
  1478.  
  1479. register/deregister operations are handled.
  1480.  
  1481.  
  1482.  
  1483. 3.2.4  TNameServer
  1484.  
  1485.  
  1486. This class uses the parameter supplied at construction time to open a file con-
  1487.  
  1488. taining entries in the form:
  1489.  
  1490.  
  1491.  
  1492. relationName=directory-path
  1493.  
  1494.  
  1495.  
  1496. This is simply used to provide some flexibility in the mappings from a relation
  1497.  
  1498. name onto the directory where it is actually stored.
  1499.  
  1500.    As an alternative, it is possible to pass the empty string ("") to diamondBa*
  1501.  *se
  1502.  
  1503. on construction and then the TNameServer will assume that all relations are in
  1504.  
  1505. the current directory. This is useful when using diaGRel.
  1506.  
  1507.  
  1508.  
  1509. 3.2.5  dbObj
  1510.  
  1511.  
  1512. One dbObj instance handles one relation.  For each index on that relation, the
  1513.  
  1514. dbObj maintains one bTree instance through which operations using that index
  1515.  
  1516. are performed.  It inherits an recServer base class which it uses to fetch the
  1517.  
  1518. actual data associated with a particular record. Actual operations on indices a*
  1519.  *re
  1520.  
  1521. perfromed by calling the appropriate method in a bTree.
  1522.  
  1523.    The dbObj maintains a set of active queries which each refer to a particular
  1524.  
  1525. bTree query.  Record locking occurs at the dbObj level to prevent two updates
  1526.  
  1527. occurring on the one record concurrently.
  1528.  
  1529.    The dbObj also collects information about the relation when it is first inst*
  1530.  *an-
  1531.  
  1532. tiated. This allows the diaGRel to find out all the information it needs about a
  1533.  
  1534. relation.
  1535.  
  1536.  
  1537.  
  1538. 3.2.6  bTree
  1539.  
  1540.  
  1541. The bTree is probably the most complicated object in the whole hierarchy (histo*
  1542.  *r-
  1543.  
  1544. ically it is was the first thing to be written). It manages the indexing of rec*
  1545.  *ords.
  1546.  
  1547. It manages its own queries, taking care to ensure that multiple queries reflect*
  1548.  * the
  1549.  
  1550. changes made to each other, whilst optimizing as much as possible for speed.
  1551.  
  1552.    It inherits a recServer to store the actual buckets. The actual implementati*
  1553.  *on
  1554.  
  1555. is essentially a B+ tree with pointers to allow sequential retrieval. At the mo*
  1556.  *ment,
  1557.  
  1558. buckets which drop to less than half full aren't merged with sibling buckets.
  1559.  
  1560. 20_________________________________________________________________Internals_
  1561.  
  1562.  
  1563.  
  1564.     Operations like fetching key data from the user class, setting key data, co*
  1565.  *m-
  1566.  
  1567. paring keys etc, are performed via calls to member functions in the object class
  1568.  
  1569. that is passed in.
  1570.  
  1571. DiamondBase_____________________________________________________________21_
  1572.  
  1573.  
  1574.  
  1575. 4    Generic Relations
  1576.  
  1577.  
  1578.  
  1579. 4.1    Introduction
  1580.  
  1581.  
  1582. The fact that DiamondBase is based upon the DSC relation compiler meant
  1583.  
  1584. initially that only those relations that had code compiled into an executable
  1585.  
  1586. could be accessed by that executable.
  1587.  
  1588.    This was seen as being too restrictive because it meant that no programs
  1589.  
  1590. could be written that acted upon an arbitrary relation. Since it was intended to
  1591.  
  1592. eventually write such programs as relation browsers and index rebuilders, it was
  1593.  
  1594. vital that a mechanism for accessing unknown relations be written.
  1595.  
  1596.  
  1597.  
  1598. 4.2    diaGRel
  1599.  
  1600.  
  1601. The diaGRel class accomplishes this. It is meant to be used in any situation wh*
  1602.  *ere
  1603.  
  1604. a DSC generated class would otherwise be used. It implements all functions that
  1605.  
  1606. the generated code does except that it is less efficient.
  1607.  
  1608.    This class is instantiated as a DSC generated class, except that its constru*
  1609.  *ctor
  1610.  
  1611. takes a string as a parameter which specifies the relation to use. This should *
  1612.  *be
  1613.  
  1614. the name of the files which make up the relation without their file extension.
  1615.  
  1616.  
  1617.  
  1618. 4.3    Use
  1619.  
  1620.  
  1621. Once instantiated, a diaGRel is used exactly as any DSC generated class is.
  1622.  
  1623.  
  1624.  
  1625. 4.4    Implementation
  1626.  
  1627.  
  1628. Initially, the diaGRel was written to open the relation file and read in the re*
  1629.  *cord
  1630.  
  1631. and key structure stored there. It would then do some pretty horrendous traver-
  1632.  
  1633. sals of this data to build up arrays of information about the relation.  These
  1634.  
  1635. arrays contain data in a form that makes implementing the methods required to
  1636.  
  1637. imitate a DSC generated class quick and efficient. This process is complicated *
  1638.  *by
  1639.  
  1640. the fact that relations and keys are reordered by DSC to put them in an order
  1641.  
  1642. that prevents alignment problems.
  1643.  
  1644.    Key access in a diaGRel is the main ineffciency of the class. This is because
  1645.  
  1646. much pointer arithmetic has to be done at runtime to extract relevant data. In
  1647.  
  1648. a DSC class this is done at compile time by the compiler by way of structure
  1649.  
  1650. references.
  1651.  
  1652.    Access to the relation data can be via one of two mechanisms.  Either the
  1653.  
  1654. diaGRel allocates a block of memory or a block of memory is given to it as
  1655.  
  1656. construction time. The latter has the benefit that you can inherit a stuct that*
  1657.  * is
  1658.  
  1659. in the relation and pass a cast to this to diaGRel thus allowing you to referen*
  1660.  *ce
  1661.  
  1662. 22_________________________________________________________Generic_Relations_
  1663.  
  1664.  
  1665.  
  1666. relation members by name. Without this, you only have access to the relation as
  1667.  
  1668. a block of memory.
  1669.  
  1670.  
  1671.  
  1672. struct BookRel -
  1673.  
  1674. char name[100];
  1675.  
  1676. char author[100];
  1677.  
  1678. long barcode;
  1679.  
  1680. "
  1681.  
  1682.  
  1683.  
  1684. class Book : public BookRel, public diaGRel -
  1685.  
  1686. public:
  1687.  
  1688. Book(void);
  1689.  
  1690. "
  1691.  
  1692.  
  1693.  
  1694. Book::Book(void) : diaGRel("book",(BookRel *)this);
  1695.  
  1696. -
  1697.  
  1698. "
  1699.  
  1700.  
  1701.  
  1702. diamondBase theDiamondBase("config.db");
  1703.  
  1704. main()
  1705.  
  1706. -
  1707.  
  1708. Book ARM;
  1709.  
  1710.  
  1711.  
  1712. strncpy(ARM.name,"Annotated C++ reference",sizeof ARM.name);
  1713.  
  1714. strncpy(ARM.author,"B. Stroustroup",sizeof ARM.author);
  1715.  
  1716. ARM.barcode = 11345654;
  1717.  
  1718.  
  1719.  
  1720. ARM.put();
  1721.  
  1722. "
  1723.  
  1724.  
  1725.  
  1726. 4.5    Performance
  1727.  
  1728.  
  1729. The above implementation worked correctly but inefficiently. The reason for this
  1730.  
  1731. was the necessity to open, read and disect the relation file on every instantia*
  1732.  *tion.
  1733.  
  1734. This meant that a process using a diaGRel instead of a DSC generated class took
  1735.  
  1736. more than 5 times as much system time to perform the same job. This was not
  1737.  
  1738. satisfactory.
  1739.  
  1740.     The solution to the above was to allow the dbObj to collect the data. This *
  1741.  *was
  1742.  
  1743. already being partially done there and the change involved setting up a struct *
  1744.  *to
  1745.  
  1746. hold all the data and moving a lot of code from the one class to the other. Now
  1747.  
  1748. DiamondBase_____________________________________________________________23_
  1749.  
  1750.  
  1751.  
  1752. the dbObj can return a pointer to this struct to the diaGRel via the diamondBas*
  1753.  *e,
  1754.  
  1755. through the attach method to the diaRel underneath the diaGRel (phew!).
  1756.  
  1757.    The above change meant that unless more than about 10 different relations
  1758.  
  1759. are used in a program, the data discussed above is assembled only once.  The
  1760.  
  1761. result is that the diaGRel takes about twice as much user time as the DSC
  1762.  
  1763. generated classes (about expected) and about 35-40% more system time (also
  1764.  
  1765. not a disappointing number).
  1766.  
  1767.    This raises interesting performance questions for database engine writers. U*
  1768.  *n-
  1769.  
  1770. less you either employ a system whereby you write self-modifying code, or you
  1771.  
  1772. link in generated code (as we do) - you are are forced to accept this overhead *
  1773.  *due
  1774.  
  1775. to interpreting your relation layout. It basically involves extra levels of ind*
  1776.  *irec-
  1777.  
  1778. tion during database access. One could envisage a system whereby the database
  1779.  
  1780. engine generates custom machine code in designated parts of its executable for
  1781.  
  1782. optimally handling each relation, and then loads it in when that relation is ne*
  1783.  *eded
  1784.  
  1785. - but the mess associated with that system is not warranted at this stage.
  1786.  
  1787. 24____________________________________________________Variable_Length_Fields_
  1788.  
  1789.  
  1790.  
  1791. 5     Variable Length Fields
  1792.  
  1793.  
  1794.  
  1795. 5.1    Introduction
  1796.  
  1797.  
  1798. A noted absence in early versions of DiamondBase was variable length records in
  1799.  
  1800. some form or another.
  1801.  
  1802.     Given the complexities of implementing a variable length record server, we
  1803.  
  1804. opted to instead provide variable length fields. This solution satisfies almost*
  1805.  * all
  1806.  
  1807. sensible known uses of length variation in a relation.
  1808.  
  1809.  
  1810.  
  1811. 5.2    dbData
  1812.  
  1813.  
  1814. To this end, two variable length field types are now available:  dbData  and
  1815.  
  1816. dbString. The dbString type is derived from dbData and so I will discuss dbData
  1817.  
  1818. first in detail.  dbData is a type that can be used to start arbitrary (possibly
  1819.  
  1820. binary) data of variable size.
  1821.  
  1822.     The following access methods are available.
  1823.  
  1824.  
  1825.     fflconstructors
  1826.  
  1827.  
  1828.         -  dbData: Construct from another dbData.
  1829.  
  1830.         -  char*:  Copy the string and make the size of the dbData equal to 1
  1831.  
  1832.            more than the string length.
  1833.  
  1834.         -  void*,long: Make the dbData the specified length and copy that much
  1835.  
  1836.            data in.
  1837.  
  1838.         -  void: Just creates an empty dbData.
  1839.  
  1840.  
  1841.     fflunsigned int len(void): Returns the current length of the dbData object.
  1842.  
  1843.  
  1844.     fflunsigned int setSize(unsigned int): Sets the size of the dbData object a*
  1845.  *nd
  1846.  
  1847.       returns the size set.  The result of this method differs from its paramet*
  1848.  *er
  1849.  
  1850.       only in dbString cases, see below.
  1851.  
  1852.  
  1853.     fflunsigned int getSize(void):  Returns the current size of the object.  No*
  1854.  *te
  1855.  
  1856.       that for dbString, size and length are different.
  1857.  
  1858.  
  1859.     fflchar* cat(char *): Adds a string onto the end of a dbData object. Returns
  1860.  
  1861.       a char* pointer to the data in hte dbData.
  1862.  
  1863.  
  1864.     fflchar* cat(dbData&): Similar but adds the contents of the dbData passed
  1865.  
  1866.       in.
  1867.  
  1868.  
  1869.     fflchar* cpy(char*):
  1870.  
  1871. DiamondBase_____________________________________________________________25_
  1872.  
  1873.  
  1874.  
  1875.    fflchar* cpy(dbData&): These two replace the contents of the dbData with
  1876.  
  1877.      the relavent data.
  1878.  
  1879.  
  1880.    fflvoid fill(char, unsigned int=0): Fills the dbData with the specified char*
  1881.  *ac-
  1882.  
  1883.      ter. If the second argument is passed then that many characters are filled
  1884.  
  1885.      in, otherwise the entire dbData is filled.
  1886.  
  1887.  
  1888.    fflvoid clr(void):
  1889.  
  1890.  
  1891.    fflvoid dispose(void): These both free any memory associated with the dbData
  1892.  
  1893.      and set it's content and length to 0.
  1894.  
  1895.  
  1896.    ffloperator char*:
  1897.  
  1898.  
  1899.    ffloperator void*: These return appropriate casts of the dbData object.
  1900.  
  1901.  
  1902.    ffloperator +(char*):
  1903.  
  1904.  
  1905.    ffloperator +(dbData&): These add the contents of their second operand onto
  1906.  
  1907.      the end of their first.
  1908.  
  1909.  
  1910.    ffloperator <<:
  1911.  
  1912.  
  1913.    ffloperator >>: Perform the appropriate stream operations.
  1914.  
  1915.  
  1916.    ffloperator []: Returns a reference to the appropriate char in the object or*
  1917.  * a
  1918.  
  1919.      reference to a dummy char if the paramter is out of range.
  1920.  
  1921.  
  1922.    ffloperator =(char*):
  1923.  
  1924.  
  1925.    ffloperator =(dbData&): These behave exactly as cpy.
  1926.  
  1927.  
  1928.    ffloperator +=(char*):
  1929.  
  1930.  
  1931.    ffloperator +=(dbData&): These behave exactly as cat.
  1932.  
  1933.  
  1934.  
  1935. 5.3    dbString
  1936.  
  1937.  
  1938. The dbString class was orginally written (and rewritten a few times) as the only
  1939.  
  1940. variable length type. When the more general dbData class was designed it became
  1941.  
  1942. clear that dbString should be a derived class from dbData. This is now how it
  1943.  
  1944. works.
  1945.  
  1946.    dbString behaves almost exactly as dbData does except that it is a null ter-
  1947.  
  1948. minated string.  This means that some of the resizing functions behave slightly
  1949.  
  1950. differently. In particular, the size of a dbString and the length of a dbString*
  1951.  * are
  1952.  
  1953. different things. The size is the amount of memory allocated to the internal ch*
  1954.  *ar
  1955.  
  1956. array and the length is the number of characters before the first null characte*
  1957.  *r.
  1958.  
  1959. 26____________________________________________________Variable_Length_Fields_
  1960.  
  1961.  
  1962.  
  1963.     The difference between size and length can be used to ensure that there is
  1964.  
  1965. enough space in a dbString to perform an operation. For instance, you may use
  1966.  
  1967. setSize to increase the size of a dbString before passing a char* cast of it to*
  1968.  * a
  1969.  
  1970. function which manipulates it (eg the library sprintf function). In this way, y*
  1971.  *ou
  1972.  
  1973. know there is enough space in the string to extend its length.
  1974.  
  1975.     The following are the differences in dbString.
  1976.  
  1977.  
  1978.     fflThe following functions behave differently either by using a differnet d*
  1979.  *efi-
  1980.  
  1981.       nition of length or by storing a 0 to truncate the string during size cha*
  1982.  *nges
  1983.  
  1984.       or adding (or otherwise taking into account) the extra 0 needed on the end
  1985.  
  1986.       of a string.
  1987.  
  1988.  
  1989.         -  unsigned int len(void)
  1990.  
  1991.         -  void setSize(unsigned int)
  1992.  
  1993.         -  char* cat()
  1994.  
  1995.         -  char* cpy()
  1996.  
  1997.         -  void fill(char c, unsigned int = 0)
  1998.  
  1999.         -  constructors: by passing a flag to dbData to indicate it is a string
  2000.  
  2001.  
  2002.  
  2003. 5.4    memServer
  2004.  
  2005.  
  2006. The memServer is the class that allows the variable length fields to be used wi*
  2007.  *th
  2008.  
  2009. diamondBase.  It does this by creating a new file with a .str extension to hold
  2010.  
  2011. the dbString and dbData records.
  2012.  
  2013.     The memServer file is laid out like a block of memory being manipulated by
  2014.  
  2015. an allocator such as malloc.  It manipulates used and empty blocks and joins
  2016.  
  2017. empty blocks should they lay adjacent to each other.  Blocks are alocated on a
  2018.  
  2019. first-fit basis.
  2020.  
  2021.     In order to able to access these fields normally in a relation, they must be
  2022.  
  2023. members of the relation.  In order to make it practical to store the relation in
  2024.  
  2025. a recServer, only longs are stored for each dbString or dbData. These longs are
  2026.  
  2027. offsets into the .str file maintained by the memServer. It is therefor necessar*
  2028.  *y to
  2029.  
  2030. have those longs stored in the relation structure so it can be written out effi*
  2031.  *ciently
  2032.  
  2033. by the recServer.
  2034.  
  2035.     The solution to the above dilema was to declare another struct to hold the
  2036.  
  2037. dbString and dbData members with the same names as given in the relation
  2038.  
  2039. file. The long offsets are stored in the main relation struct with slightly man*
  2040.  *gled
  2041.  
  2042. names. Both of these structs are inherited by the relation.
  2043.  
  2044.     In this way, users may reference their dbString and dbData references as th*
  2045.  *ey
  2046.  
  2047. are named even though only longs are stored in the relation struct.
  2048.  
  2049.     The dbObject makes sure that whenever there are dbString or dbData fields
  2050.  
  2051. in a relation, appropriate calls are made to memServer to keep them up to date.
  2052.  
  2053. DiamondBase_____________________________________________________________27_
  2054.  
  2055.  
  2056.  
  2057. Every time a record is read or written, the strings need to be similarly update*
  2058.  *d.
  2059.  
  2060. This gives a performance penalty compared to using char arrays to store strings
  2061.  
  2062. but this penalty has been optimised heavily to minimise this penalty.
  2063.  
  2064.    The memServer and its integration into the dbObject provide seamless use of
  2065.  
  2066. dbData and dbString fields in relations.
  2067.  
  2068. 28_________________________________________________Multiuser_DiamondBase___
  2069.  
  2070.  
  2071.  
  2072. 6     Multiuser DiamondBase
  2073.  
  2074.  
  2075.  
  2076. 6.0.1   Disclaimer
  2077.  
  2078.  
  2079. Warning: The multi user component of DiamondBase has only been completed
  2080.  
  2081. very recently, and is being released as an ALPHA version. There are many defi-
  2082.  
  2083. ciencies documented below (and goodness knows how many undocumented ones).
  2084.  
  2085. If you intend to use it, then read this carefully, and please give us feedback *
  2086.  *on
  2087.  
  2088. what you think, and any improvements you think are necessary.
  2089.  
  2090.  
  2091.  
  2092. 6.1    Introduction
  2093.  
  2094.  
  2095. The transition from single user to the multi-user version of DiamondBase has
  2096.  
  2097. been quite an adventure. We started by defining what we meant by "multi-user".
  2098.  
  2099. To an extent, the existing version already supports a level of concurrency in t*
  2100.  *hat
  2101.  
  2102. you can have multiple objects in your program which are all accessing the one
  2103.  
  2104. relation.  There is proper locking to ensure that they don't interfere with one
  2105.  
  2106. another.
  2107.  
  2108.     At a higher level however, you want multiple processes which may not even
  2109.  
  2110. be the same program, accessing the database concurrently without corrupting
  2111.  
  2112. the underlying files.  For this version, we have chosen to implement a system
  2113.  
  2114. which allows multiple processes on the one machine. The possibility exists for a
  2115.  
  2116. distributed database across a TCP network but that shall wait.
  2117.  
  2118.  
  2119.  
  2120. 6.2    What didn't work
  2121.  
  2122.  
  2123. The first attempt at a concurrent version of DiamondBase began at the bottom.
  2124.  
  2125. If the record management at the recServer level was given proper locking, then
  2126.  
  2127. all that sat on top of would behave transparently. This turned out to be about *
  2128.  *as
  2129.  
  2130. incorrect as is imaginable. For a start, cache coherence becomes a problem. The*
  2131.  *re
  2132.  
  2133. are also higher level structures like B-Trees, for which, simply locking a smal*
  2134.  *l part
  2135.  
  2136. is totally inappropriate.  As the changes propagated up the code hierarchy and
  2137.  
  2138. the changes to the bottom layer multiplied, this was abandoned.  Andy wisely
  2139.  
  2140. smiled, having predicted this from the start.
  2141.  
  2142.     Having explored its "rear end" if you like, we next commenced with oral
  2143.  
  2144. surgery.  Putting a layer near the top, between the schema generated code and
  2145.  
  2146. the database engine would allow the two to exist in separate applications quite
  2147.  
  2148. happily.  This worked much more nicely, with the engine left unchanged, and
  2149.  
  2150. some surgery at the level of the diamondBase and diaRel objects. There was a
  2151.  
  2152. problem however. Having all the comparison code compiled into the application
  2153.  
  2154. makes for a very fast single user version (and I would still recommend it unless
  2155.  
  2156. you really need concurrent behavior).  However, it meant that the server still
  2157.  
  2158. DiamondBase_____________________________________________________________29_
  2159.  
  2160.  
  2161.  
  2162. needed to convey the object callbacks to the application with the appropriate
  2163.  
  2164. data.
  2165.  
  2166.    After quite a bit of coding, and the odd kernel IPC fix or two for linux,
  2167.  
  2168. we had a running version which was only 11 times slower than the uni version.
  2169.  
  2170. Disgusted, I decided that for this, and other reasons, we would have to interpr*
  2171.  *et
  2172.  
  2173. the relation layout and do the comparisons within the server, only talking to t*
  2174.  *he
  2175.  
  2176. application when it issued a request, and to supply the reply. The diaGRel class
  2177.  
  2178. was born to permit generalized access so the server could get to any relation, *
  2179.  *and
  2180.  
  2181. the communications protocol emasculated to handle the smaller command set.
  2182.  
  2183.  
  2184.  
  2185. 6.3    The architecture
  2186.  
  2187.  
  2188. This version uses shared memory segments between the server and the application
  2189.  
  2190. processes to transfer records, and a message queue shared between all processes*
  2191.  * to
  2192.  
  2193. communicate requests and intentions. Incoming messages on a very low message
  2194.  
  2195. number signify attach requests from applications.
  2196.  
  2197.    The connection protocol is as follows:
  2198.  
  2199.  
  2200.    fflClient sends an attach request as a message with id 2, and its pid.
  2201.  
  2202.  
  2203.    fflServer creates /tmp/diamond.pid and a shared memory segment to go with
  2204.  
  2205.      it. It then sends a message on BASE_RESP + pid
  2206.  
  2207.  
  2208.    fflClient attaches to the new shared memory area.
  2209.  
  2210.  
  2211.    Further transactions are performed as follows:
  2212.  
  2213.  
  2214.    fflCopy the relations data into the shared memory segment
  2215.  
  2216.  
  2217.    fflSend message with transaction details on BASE_REQ. Initial versions had
  2218.  
  2219.      pid added to this but this caused clients with lower pid's to be given pre*
  2220.  *f-
  2221.  
  2222.      erential treatment. Now the pid is embodied in the message.
  2223.  
  2224.  
  2225.    fflServer reads message and gets the database engine to perform the trans-
  2226.  
  2227.      action after copying the data from the shared area into a diaGRel object
  2228.  
  2229.      which is carrying out the database requests on behalf of the client.
  2230.  
  2231.  
  2232.    fflServer copies resultant relation into transfer area and sends reply messa*
  2233.  *ge
  2234.  
  2235.      on BASE_RESP + pid
  2236.  
  2237.  
  2238.    Transactions consist of database transaction ids along with associated index
  2239.  
  2240. numbers, new object attach requests, object detach notification messages and ap-
  2241.  
  2242. plication detach messages. The reference Id numbers handed out by the database
  2243.  
  2244. engine are mapped onto "fake" diaGRel objects which do all the work in the en-
  2245.  
  2246. gine on behalf of the client's diaRel objects.  Two lists are maintained to tra*
  2247.  *ck
  2248.  
  2249. the attached client applications and their attached objects. Having the diaGRel
  2250.  
  2251. functionality makes the whole process quite simple.
  2252.  
  2253. 30_________________________________________________Multiuser_DiamondBase___
  2254.  
  2255.  
  2256.  
  2257. 6.4    Performance
  2258.  
  2259.  
  2260. Was not terribly disappointing.  It was never going to be faster than the uni
  2261.  
  2262. version, but you have to keep in mind some potential gains from having a separa*
  2263.  *te
  2264.  
  2265. server:
  2266.  
  2267.  
  2268.  
  2269.     fflKilling application programs won't jeopardize database integrity
  2270.  
  2271.  
  2272.     fflRetrieved data is in a single pooled cache increasing efficiency
  2273.  
  2274.  
  2275.     fflThe possibility exists to prevent direct access to the database files.
  2276.  
  2277.  
  2278.  
  2279.                     ___________________________________
  2280.                     _      Test _User  _System _ Total  _
  2281.                     ___________________________________ _
  2282.                     _       Uni _27.9  _ 8.0   _ 35.9  _
  2283.                     ____________________________________
  2284.                     _ Multi (1) _     _        _       _
  2285.                     _           _     _        _       _
  2286.                     _    server _23.19 _ 11.8   _50.19  _
  2287.                     _           _      _        _       _
  2288.                     _     client _10.0  _5.2   _       _
  2289.                     ____________________________________
  2290.                     _ Multi (2) _     _        _       _
  2291.                     _           _     _        _       _
  2292.                     _    Server _49.0  _ 22.3   _104.23 _
  2293.                     _           _      _        _       _
  2294.                     _   client A _11.0  _22.3   _      _
  2295.                     _            _      _       _      _
  2296.                     _   client B1_0.83 _ 5.5   _       _
  2297.                     ____________________________________
  2298.  
  2299.  
  2300.  
  2301.             Table 1: Performance figures for multi and uni versions
  2302.  
  2303.  
  2304.  
  2305.     From the above figures, the multi version is approximately 40% slower than
  2306.  
  2307. the uni version - which can largely be attributed to the fact that the server i*
  2308.  *s in-
  2309.  
  2310. terpreting the record comparisons. Note that for the two client test, the datab*
  2311.  *ase
  2312.  
  2313. is essentially doing twice the work. Running the two tests under the uni version
  2314.  
  2315. takes twice the figure quoted for the uni version.  If you really want high per-
  2316.  
  2317. formance concurrent database management for specialized applications, it would
  2318.  
  2319. be theoretically possible to compile the comparison code into a specialized ser*
  2320.  *ver
  2321.  
  2322. which can just do the record comparisons you need.
  2323.  
  2324.     The other thing to note on the performance front is that we have not opti-
  2325.  
  2326. mized the code at all (ie -O6) - there is reason to believe that this could imp*
  2327.  *rove
  2328.  
  2329. things. We have not profiled the multi stuff at all, so there are many potential
  2330.  
  2331. improvements in performance there. The next release will be a little more fleet
  2332.  
  2333. footed on that front I expect.
  2334.  
  2335.  
  2336.  
  2337. 6.5    Compiling the Concurrent version
  2338.  
  2339.  
  2340. The target multi exists in the Makefile.  Typing gmake multi after you make
  2341.  
  2342. already built the main system will perform the multi compilation.  The target
  2343.  
  2344. DiamondBase_____________________________________________________________31_
  2345.  
  2346.  
  2347.  
  2348. will build the dbmulti library, and the jeweler server process. It has been tes*
  2349.  *ted
  2350.  
  2351. under SunOS 4.1.1, Ultrix IRIX and Linux. There are some prototypes for the
  2352.  
  2353. IPC system calls which seem to be woefully under prototyped on non Linux
  2354.  
  2355. systems. It should theoretically work on any UN*X system which supports IPC
  2356.  
  2357. (interprocess communication) - although my experience so far suggests that IPC
  2358.  
  2359. is about as standard as curses so I am prepared for bug reports.
  2360.  
  2361.  
  2362.  
  2363. 6.6    Testing the concurrent version
  2364.  
  2365.  
  2366. I will distribute a small application called bump. It creates 5000 records, int*
  2367.  *er-
  2368.  
  2369. spersing requests for old records in the addition calls, and ensuring their int*
  2370.  *egrity.
  2371.  
  2372. It takes a parameter indicating a range. If you are running more than one, you
  2373.  
  2374. should specify parameters about 10,000 apart. I have run up to 8 of them con-
  2375.  
  2376. currently under SunOS, and Linux. Note that if you are running more than one
  2377.  
  2378. - you should provide parameters spaced at 10000 and run no test twice without
  2379.  
  2380. first creating an empty database, otherwise duplicate records will result and t*
  2381.  *he
  2382.  
  2383. test code will fail. Running more than 9 processes at once causes the tests to *
  2384.  *fail
  2385.  
  2386. due to limits within the server (which can be changed if desired).
  2387.  
  2388.  
  2389.  
  2390. 6.7    Using the Concurrent version
  2391.  
  2392.  
  2393. One of the issues we would still like to address more thoroughly is that of er-
  2394.  
  2395. gonomics from a programming point of view. Ideally, we would like to minimize
  2396.  
  2397. the pain of the transition between a uni-database and a concurrent one, to that*
  2398.  * of
  2399.  
  2400. linking with a separate library. We still believe that this can be achieved, bu*
  2401.  *t at
  2402.  
  2403. the moment, it is necessary to recompile your application with the preprocessor
  2404.  
  2405. symbol 'MULTI' defined. You must also link with the libraries dbmulti and dia-
  2406.  
  2407. mond in that order, rather than just diamond. Upon execution, your application
  2408.  
  2409. will attempt to connect to a running server in order to perform its transactions
  2410.  
  2411. rather than doing the accesses directly. So, to reiterate the steps:
  2412.  
  2413.  
  2414.  
  2415.    fflMake sure that your code includes diarel.h rather than dbase.h to get at
  2416.  
  2417.      any database definitions.
  2418.  
  2419.  
  2420.    fflPut -DMULTI into your application CFLAGS
  2421.  
  2422.  
  2423.    fflLink your application with -ldbmulti -ldiamond
  2424.  
  2425.  
  2426.    fflEnsure that the server process jeweler is running.
  2427.  
  2428.  
  2429.  
  2430.    Note: This version of the code creates all rendezvous points with octal per-
  2431.  
  2432. mission 600, meaning that the client and server must be run by the same user.
  2433.  
  2434. The permissions can be edited to suit your taste.  The whole area of security
  2435.  
  2436. management needs careful examination.
  2437.  
  2438. 32_________________________________________________Multiuser_DiamondBase___
  2439.  
  2440.  
  2441.  
  2442.     The ergonomics of files used to manage the connection are also less than
  2443.  
  2444. satisfactory at the moment.  Any relation which you wish to use via a server
  2445.  
  2446. process must be in the server.db file in the directory in which the server proc*
  2447.  *ess
  2448.  
  2449. jeweler is run. This file is in the same format as the relation file whose name*
  2450.  * is
  2451.  
  2452. normally passed to the diamondBase object in the uni-version.
  2453.  
  2454.     The server and client processes initially make their rendezvous via message
  2455.  
  2456. passing, and the filename used to make the connection is gibraltar. (It seemed *
  2457.  *like
  2458.  
  2459. a solid place to build a database - sorry). Currently, both the server and clie*
  2460.  *nt
  2461.  
  2462. library code look in the current directory for this file.  It must therefore ex*
  2463.  *ist -
  2464.  
  2465. although its contents are irrelevant for the running of the server. The server *
  2466.  *itself
  2467.  
  2468. creates the file when it is run. It also constrains the clients to run from the*
  2469.  * same
  2470.  
  2471. directory as the server. This is messy and we will endeavor to rectify it. If y*
  2472.  *ou
  2473.  
  2474. have strong opinions on how databases, servers and clients should be managed
  2475.  
  2476. system-wide, we would love to hear from you.
  2477.  
  2478.     So, in order to run an application/server pair:
  2479.  
  2480.  
  2481.     fflcreate a file server.db listing your relations
  2482.  
  2483.  
  2484.     fflrun jeweler (optionally in the background)
  2485.  
  2486.  
  2487.     fflrun your application in the same directory
  2488.  
  2489.  
  2490.     When you wish to shut the server down, either send it an interrupt message
  2491.  
  2492. (press control-C), or kill -SIGTERM the process. The server process will output
  2493.  
  2494. some messages on either stdout or stderr, so you may wish to log these to a fil*
  2495.  *e -
  2496.  
  2497. they contain some useful information like diagnostics when relation names can't
  2498.  
  2499. be looked up.
  2500.  
  2501.     If there are clients still attached, then you will have to wait until those*
  2502.  * clients
  2503.  
  2504. are gone before the server will shut itself down.
  2505.  
  2506.  
  2507.  
  2508. 6.8    Caveats - PLEASE READ THIS CAREFULLY.
  2509.  
  2510.  
  2511. This is the section where I warn you about the nasty issues/problems which are
  2512.  
  2513. still out there and not dealt with. As mentioned above, there are many ergonomic
  2514.  
  2515. issues which we will address as we write some more concurrent applications.  I
  2516.  
  2517. will list some other problems which I am aware of.  I will try to fix the more
  2518.  
  2519. serious ones at least - but there are just so many little potential problems th*
  2520.  *at
  2521.  
  2522. this may take a while. There has been some pressure to get this out and testable
  2523.  
  2524. as soon as possible. My little list of problems follows:
  2525.  
  2526.  
  2527.     fflVariable length strings and memory aren't supported yet. [I expect to ha*
  2528.  *ve
  2529.  
  2530.       these working very soon. Kev]
  2531.  
  2532.  
  2533.     fflThere is no configuration management, utilities to shut the server down,
  2534.  
  2535.       or monitor it etc. Changes to the server.db file won't take place until i*
  2536.  *t is
  2537.  
  2538. DiamondBase_____________________________________________________________33_
  2539.  
  2540.  
  2541.  
  2542.      restarted.  At the moment, sending a suggestive signal like SIGTERM or
  2543.  
  2544.      SIGHUP will cause it to exit when convenient.
  2545.  
  2546.  
  2547.    fflThere is a static limit on the size of relation which can be handled (4K *
  2548.  *at
  2549.  
  2550.      the moment). Getting around this efficiently is a little sticky.
  2551.  
  2552.  
  2553.    fflThe rendezvous point between client and server is clumsy and essentially
  2554.  
  2555.      means they need to be run in the same directory.  Configuration at in-
  2556.  
  2557.      stallation time is one possibility, or at runtime which is probably more
  2558.  
  2559.      acceptable.
  2560.  
  2561.  
  2562.    fflThe schema compiler (DSC) is still a uni application, so it can blow away
  2563.  
  2564.      the database from under the server's feet if you are stupid enough.  This
  2565.  
  2566.      shouldn't be permitted.
  2567.  
  2568.  
  2569.    fflNon-vital commands in diaRel like verStr aren't implemented yet.
  2570.  
  2571.  
  2572.    fflDeath of server will freeze the application using it.
  2573.  
  2574.  
  2575.    fflSecurity is reliant on protecting the gibraltar file, and the code opens *
  2576.  *the
  2577.  
  2578.      IPC services as 600 currently, so only processes under the same uid as the
  2579.  
  2580.      server can access it.  This needs to be greatly improved.  Ideally, client
  2581.  
  2582.      instances should not be able to interfere with one another. We may have to
  2583.  
  2584.      resort to encryption to achieve this and there will be performance penalti*
  2585.  *es.
  2586.  
  2587.      Denial of service attacks are also possible.
  2588.  
  2589.  
  2590.    Just remember that if I have missed something, Use The Source Luke. The
  2591.  
  2592. files gib.cc and dclient.cc contain the relevant source for the server and clie*
  2593.  *nt
  2594.  
  2595. library respectively. They aren't too complicated.
  2596.  
  2597.  
  2598.  
  2599. 6.9    Still to do
  2600.  
  2601.  
  2602.    fflReduce the size of the caveat list.
  2603.  
  2604.  
  2605.    fflProfile the code to remove bottlenecks
  2606.  
  2607.  
  2608.    fflReplacing the linked lists with hash tables for the client and object lis*
  2609.  *ts.
  2610.  
  2611.  
  2612.    fflUsing semaphores instead of message queues for efficiency
  2613.  
  2614.  
  2615.    fflAn OS/2 port.
  2616.  
  2617.  
  2618.    fflMore thorough test suite.
  2619.  
  2620.  
  2621.    fflAdd dbString support.
  2622.  
  2623.  
  2624.    fflPort/test on other unix platforms.
  2625.  
  2626.  
  2627.    fflGo to bed.
  2628.  
  2629. 34_________________________________________________________DSC_Users_Guide_
  2630.  
  2631.  
  2632.  
  2633. 7     DSC Users Guide
  2634.  
  2635.  
  2636. The DiamondBase Schema Compiler (DSC) is a utility provided with the Di-
  2637.  
  2638. amondBase database package which takes a lot of the hard work out of writing
  2639.  
  2640. database applications.  It does this by generating most of the code required to
  2641.  
  2642. maintain the database automatically.  In addition DSC generates new, empty
  2643.  
  2644. databases for each schema you specify.
  2645.  
  2646.     Throughout this section and the next, it is expected that the reader has a
  2647.  
  2648. good understanding of the concepts involved in relational database design[1].
  2649.  
  2650.  
  2651.  
  2652. 7.1    A Simple Record Library
  2653.  
  2654.  
  2655. Let us begin with a small example.  Consider the application of producing a
  2656.  
  2657. database for storing record library information.  One part of such a database
  2658.  
  2659. would be a relation which stores information about a single artist. The informa-
  2660.  
  2661. tion we would like to store is the artist's name and the artist's abbreviation.*
  2662.  * The
  2663.  
  2664. specification of this relation is given below.
  2665.  
  2666. relation Artist
  2667.  
  2668. f
  2669.  
  2670.      // Field specification.
  2671.  
  2672.  
  2673.  
  2674.      char     artName[100];    // Artist's Name.
  2675.  
  2676.      char     abbr[10];        // Artist's Abbreviations.
  2677.  
  2678.      long     titles = 0;         // Number of titles.
  2679.  
  2680.  
  2681.  
  2682.      unique  artId;           // A unique number to identify
  2683.  
  2684.                                 // this artist by.
  2685.  
  2686.  
  2687.  
  2688.      // Index specification
  2689.  
  2690.  
  2691.  
  2692.      index    name on artName;     // An index for artist names
  2693.  
  2694.      index    abbrev on abbr;      // An index for artist
  2695.  
  2696.                                     // abbreviations.
  2697.  
  2698.  
  2699.  
  2700.      // Constructors
  2701.  
  2702.  
  2703.  
  2704.      construct using titles,artName index name;
  2705.  
  2706.      construct titles;
  2707.  
  2708. g
  2709.  
  2710.     To make starting your DiamondBase application as easy as possible, the
  2711.  
  2712. specification of a schema is based on the specification of data structures in t*
  2713.  *he C
  2714.  
  2715. or C++ languages. As such some of the schema will be obvious, however before
  2716.  
  2717. continuing we will look at the important parts it.
  2718.  
  2719. DiamondBase_____________________________________________________________35_
  2720.  
  2721.  
  2722.  
  2723.    fflrelation Artist
  2724.  
  2725.  
  2726.  
  2727.    The first word here is a keyword, indicating that this is the start of a new
  2728.  
  2729. relation specification. The second is the name for the relation. This will beco*
  2730.  *me
  2731.  
  2732. the name of the class associated with this relation, thus becoming a type name.*
  2733.  * If
  2734.  
  2735. you wanted to use "Author" as a variable name in your program, consider calling
  2736.  
  2737. the relation something else in the schema.
  2738.  
  2739.    Note also the opening "brace" (`f'). The information belonging to this relat*
  2740.  *ion
  2741.  
  2742. is contained within these braces.  You must finish the relation with a closing
  2743.  
  2744. "brace" (`g').
  2745.  
  2746.    There is no limit to the number of relations which can appear in a single
  2747.  
  2748. schema file. Each must begin with the keyword relation and must be enclosed
  2749.  
  2750. within braces.
  2751.  
  2752.    There can be an optional "called name" after the relation and before the
  2753.  
  2754. brace. It allows the relation to have a different name to the underlying struct*
  2755.  *ure.
  2756.  
  2757.  
  2758.  
  2759. 7.1.1  Field Specification
  2760.  
  2761.  
  2762.    fflchar artName[100];
  2763.  
  2764.  
  2765.  
  2766.    Now we begin the business of specifying the fields for the relation. First t*
  2767.  *he
  2768.  
  2769. type of the field is given, in this case a character (or as we shall see, an ar*
  2770.  *ray
  2771.  
  2772. or characters).  Next a name must be given to the field.  In this case the name
  2773.  
  2774. is "artName".  You will be able to access a class member called "artName" to
  2775.  
  2776. manipulate this data in the programs you write.
  2777.  
  2778.    Lastly, you have the option of specifying that more than one "type" (in this
  2779.  
  2780. case character) should be allocated. This is the syntax for specifying an array*
  2781.  * of
  2782.  
  2783. data items, and in the case of characters is also the method for declaring stri*
  2784.  *ngs.
  2785.  
  2786.    Default arguments can be given using an = sign. These are assigned to the
  2787.  
  2788. relation during construction.
  2789.  
  2790.    The valid types for use in a relation are given in the DSC Reference Manual.
  2791.  
  2792.    Note that each field specification must be terminated by a semi-colon (`;').
  2793.  
  2794.  
  2795.  
  2796.    fflunique authId;
  2797.  
  2798.  
  2799.  
  2800.    The unique type is special, in that it is never assigned a value by Diamond-
  2801.  
  2802. Base applications. Instead DiamondBase assigns a value to these fields when
  2803.  
  2804. a new record is created, guaranteeing that the value it gives is unique for that
  2805.  
  2806. relation at that time.
  2807.  
  2808.    It is important to note that these unique numbers are only instantaneously
  2809.  
  2810. unique. If a record is deleted from the relation, the unique value it once had *
  2811.  *is
  2812.  
  2813. then free to be re-used.
  2814.  
  2815. 36_________________________________________________________DSC_Users_Guide_
  2816.  
  2817.  
  2818.  
  2819. 7.1.2   Index Specification
  2820.  
  2821.  
  2822. Indicies are used as mechanisms for locating records within the relation based
  2823.  
  2824. on some sorting field or key.  As such their creation does not involve allocati*
  2825.  *ng
  2826.  
  2827. any additional storage within a relation. Instead DSC generates the appropriate
  2828.  
  2829. code to generate any keys which are required dynamically. The examples of index
  2830.  
  2831. specification above are similar, so the first will be used as an example.
  2832.  
  2833.  
  2834.     fflindex name on artName;
  2835.  
  2836.  
  2837.     The first word is the index keyword. This is followed by an identifier. Thi*
  2838.  *s is
  2839.  
  2840. the name of the index and can be used in application code when specifying which
  2841.  
  2842. index should be used for record queries 1.
  2843.  
  2844.     The name of the index is followed by another keyword on, and then a list of
  2845.  
  2846. one or more identifiers, seperated by commas. These identifiers are the names of
  2847.  
  2848. the fields which should be used as sort keys for the index and should be specif*
  2849.  *ied
  2850.  
  2851. in the order of importance. For example,
  2852.  
  2853.       index myindex on myfield1, myfield2;
  2854.  
  2855. would cause a b-tree to be created with myfield1 as a primary sorting key, and
  2856.  
  2857. myfield2 as a secondary sort key.
  2858.  
  2859.  
  2860.  
  2861. 7.1.3   Constructor Specification
  2862.  
  2863.  
  2864. Constructors may be declared for your relation. You should make sure that you
  2865.  
  2866. do not create ambiguous constructors.  Your compiler will give an error if you
  2867.  
  2868. do. You should also not use a constructor that takes a char* and a long in that
  2869.  
  2870. order.  Such a constructor exists already so that you can construct using a key
  2871.  
  2872. and an index number.
  2873.  
  2874.  
  2875.     fflconstruct using titles,artName index name;
  2876.  
  2877.  
  2878.     This creates a constructor that accepts a long and char* and then does a get
  2879.  
  2880. using the name index. The "index name" portion is optional.
  2881.  
  2882.  
  2883.  
  2884. 7.2    Compiling a Schema
  2885.  
  2886.  
  2887. After creating a schema you will want to compile it using DSC. This process
  2888.  
  2889. may generate a number of files, which by default will be created in the current
  2890.  
  2891. directory. For large databases which is inconvenient from a programming point
  2892.  
  2893. of view, if not simply messy.  So as an example, you might set up a directory
  2894.  
  2895. structure in your project path which had subdirectories called schema (for stor*
  2896.  *ing
  2897.  
  2898. schema descriptions) and dbfiles (for storing the generated database files).
  2899. ______________________________
  2900.    1In fact the name which is made available to application programmers if pref*
  2901.  *ixed by
  2902.  
  2903. "dbIdx_", so that the index above would be refered to in code as "dbIdx_name".
  2904.  
  2905. DiamondBase_____________________________________________________________37_
  2906.  
  2907.  
  2908.  
  2909.    Your application source files might go in the root directory of your project
  2910.  
  2911. path, while schemas are located in the schema path, and the database files
  2912.  
  2913. themselves (containing the data) are stored in the dbfiles path.
  2914.  
  2915.    Let us assume that such a directory structure exists, and that the schema
  2916.  
  2917. file used in section 7.1 is in the schema path and is called artist.ds (the .ds
  2918.  
  2919. extension denotes a DiamondBase Schema file)2.  To compile this schema and
  2920.  
  2921. place the database files in the dbfiles path, we use the following command :
  2922.  
  2923.  
  2924.                              Specify the database file path
  2925.                                   z_____"______-
  2926.         dsc    I_schema_-z____"   O dbfiles            artist___-z__"
  2927.  
  2928.             Specify the schema path                The schema filename
  2929.  
  2930.  
  2931.    This could generate 3 source files in the current path called artist.h, arti*
  2932.  *st.cc
  2933.  
  2934. and artist_s.h.
  2935.  
  2936.    It then may create a new data file for each relation in your schema (in this
  2937.  
  2938. case only one), named after the relation which has a .db extension. This file is
  2939.  
  2940. placed in the dbfiles path.
  2941.  
  2942.    Finally DSC may create one .id file for each index specified in the schema.
  2943.  
  2944. This extension is suffixed by a number from 0 to 9, using a different number for
  2945.  
  2946. each index specified in the schema. These index files will also be located in t*
  2947.  *he
  2948.  
  2949. dbfiles path.
  2950.  
  2951.    The database files will only be generated if you use the -D flag and the code
  2952.  
  2953. described above will only be generated if you specify the -C flag.  This ensures
  2954.  
  2955. that you do not overwrite anything.
  2956.  
  2957.  
  2958.  
  2959. 7.3    Derived relations
  2960.  
  2961.  
  2962. It is often the case that you would want to inherit a DSC relation into another
  2963.  
  2964. class so that you may augment its functionality.  To help with this, there is
  2965.  
  2966. another command line argument for DSC.
  2967.  
  2968.  
  2969.    ffldsc -G base derived file
  2970.  
  2971.  
  2972.    This will create "file.h" and "file.cc" files containing a class named deriv*
  2973.  *ed
  2974.  
  2975. which has a base class base.  The class will appear as a skeleton class based on
  2976.  
  2977. your base class.
  2978.  
  2979.  
  2980.  
  2981. 7.4    Getting on with the Application
  2982.  
  2983.  
  2984. You now have everything that is required to start building your own application.
  2985.  
  2986. There are a few more command line options which may become useful down the
  2987.  
  2988. track as your application develops.  These are explained in detail in the next
  2989.  
  2990. section.
  2991. ______________________________
  2992.    2schema files should have the extension ".ds" for clarity
  2993.  
  2994. 38_____________________________________________________DSC_Reference_Guide_
  2995.  
  2996.  
  2997.  
  2998. 8     DSC Reference Guide
  2999.  
  3000.  
  3001.  
  3002. 8.1    Command Line Arguments
  3003.  
  3004.  
  3005. The command syntax for DSC is as follows :
  3006.  
  3007.      dsc [options] <schema name>
  3008.  
  3009.     The command line arguments to DSC are shown in figure 1.
  3010.  
  3011.     If no extension is given for the schema file, the extension .ds is used.
  3012.  
  3013.  
  3014.  
  3015.        _______________________________________________________________
  3016.        _ Option             _Action                                   _
  3017.        _________________________________________________________________
  3018.        _ -C                 _Create generated source code              _
  3019.        _                    _                                          _
  3020.        _ -D                 _Create database files                      _
  3021.        _                    _                                           _
  3022.        _ -G base derived fileG_enerate a derived class                   _
  3023.        _                      _                                          _
  3024.        _ -O < path >       _ Place generated database files in < path > _
  3025.        _                   _                                            _
  3026.        _ -S < path >        _Place generated source code in < path >   _
  3027.        _                    _                                          _
  3028.        _ -I < path >        _Use schema files located in < path >       _
  3029.        _______________________________________________________________  _
  3030.  
  3031.  
  3032.  
  3033.                    Figure 1: Command-line options to DSC
  3034.  
  3035.  
  3036.  
  3037. 8.2    DSC Data Types
  3038.  
  3039.  
  3040. The types available in DSC are similar to those which are available in C++ with
  3041.  
  3042. three exceptions, and several ommissions. Table 2 shows all the legal types in a
  3043.  
  3044. DSC schema file, their C++ equivalents, their type identifiers and gives a short
  3045.  
  3046. description of their properties.
  3047.  
  3048.  
  3049.  
  3050. 8.3    DSC Syntax Definition
  3051.  
  3052.  
  3053. The syntax for schema description is modelled on the C and C++ languages.
  3054.  
  3055. There may be one or more relations descripted in a schema file, with each being
  3056.  
  3057. preceeded by the relation phrase, and each enclosed in a pair or brackets (`f g*
  3058.  *').
  3059.  
  3060. Table 3 shows the complete syntax for DSC in BNF.
  3061.  
  3062.     NOTE This BNF is out of date. It is 3am and I have no plans to try
  3063.  
  3064. to persuade LaTEXwhat the current BNF looks like.  I suggest reading
  3065.  
  3066. dsc.y. It makes for many hours of fun for the whole family. Note that
  3067.  
  3068. the version below does not include default arguments and constructors
  3069.  
  3070. (at least).
  3071.  
  3072. DiamondBase_____________________________________________________________39_
  3073.  
  3074.  
  3075.  
  3076. ___________________________________________________________________________
  3077. _ DSC Type _ C++ Type        _  Id _ Decsription                           _
  3078. _____________________________________________________________________________
  3079. _ long       _long int          0_ _ A long integer. The size of this type    _
  3080. _            _                   _ _                                          _
  3081. _            _                 _    _will vary, but is usually 32 bits.        *
  3082.  * _
  3083. ___________________________________________________________________________    *
  3084.  * _
  3085. _ ulong      _unsigned long int 1_ _ A long integer which may only         _
  3086. _            _                   _ _                                       _
  3087. _            _                 _    _take positive values.                   _
  3088. ___________________________________________________________________________  _
  3089. _ short      _short int         2_ _ A short integer. The size of this        _
  3090. _            _                   _ _                                          _
  3091. _            _                 _    _type will vary between compilers.       _
  3092. ___________________________________________________________________________  _
  3093. _ ushort     _unsigned short int3_ _ A short integer which may only         _
  3094. _            _                   _ _                                        _
  3095. _            _                 _    _contain positive values.                _
  3096. ___________________________________________________________________________  _
  3097. _ double     _double            _4  _A double precision floating point       _
  3098. _            _                  _   _                                        _
  3099. _            _                 _    _number.                              _
  3100. ____________________________________________________________________________
  3101. _ float      f_loat             5_ _ A single precission floating point        _
  3102. _             _                  _ _                                           _
  3103. _            _                 _    _number.                              _
  3104. ____________________________________________________________________________
  3105. _ money     _moneyType       _  6  _ A type defined to store currency        _
  3106. _           _                _     _                                         _
  3107. _            _                 _    _information.                           _
  3108. ___________________________________________________________________________ _
  3109. _ date       _dateType         _7  _ A type defined to store date            _
  3110. _            _                 _   _                                         _
  3111. _            _                 _    _information.                           _
  3112. ___________________________________________________________________________ _
  3113. _ char       _char              _8  _A character, or 8-bit number           _
  3114. ___________________________________________________________________________ _
  3115. _ unique     _uniqueType       _9  _ A type whose value is guaranteed to be _
  3116. _            _                 _   _                                        _
  3117. _            _                 _    _instantaneously unique.                _
  3118. ___________________________________________________________________________ _
  3119. _ dbString   _dbString          _10 _A resizable string class                 _
  3120. ___________________________________________________________________________   _
  3121. _ dbData    _dbData           _ 11 _ A generic resizable binary data object   _
  3122. ___________________________________________________________________________   _
  3123. _ ichar      c_har              _12 _A case insensitive char                 _
  3124. ___________________________________________________________________________  _
  3125.  
  3126.  
  3127.  
  3128.                Table 2: Valid types and their integer identifiers
  3129.  
  3130. 40_____________________________________________________DSC_Reference_Guide_
  3131.  
  3132.  
  3133.  
  3134.            _______________________________________________________
  3135.            _ schemaFile    !   schemaFile relation                 _
  3136.            _                                                       _
  3137.            _               !   null                               _
  3138.            _                                                      _
  3139.            _                                                     _
  3140.            _                                                     _
  3141.            _ relation      !   relation ident structName fieldList _
  3142.            _                                                       _
  3143.            _                                                     _
  3144.            _                                                     _
  3145.            _ structName    !   [is] called ident                   _
  3146.            _                                                       _
  3147.            _               !   null                               _
  3148.            _                                                      _
  3149.            _                                                     _
  3150.            _                                                     _
  3151.            _ fieldList     !   f fieldList1 indexList g             _
  3152.            _                                                        _
  3153.            _                                                     _
  3154.            _                                                     _
  3155.            _ fieldList1    !   fieldList1 type ident size ;          _
  3156.            _                                                         _
  3157.            _               !   null                               _
  3158.            _                                                      _
  3159.            _                                                     _
  3160.            _                                                     _
  3161.            _ type          !   short                             _
  3162.            _                                                     _
  3163.            _               !   ushort                            _
  3164.            _                                                     _
  3165.            _               !   long                              _
  3166.            _                                                     _
  3167.            _               !   ulong                             _
  3168.            _                                                     _
  3169.            _               !   float                              _
  3170.            _                                                      _
  3171.            _               !   double                            _
  3172.            _                                                     _
  3173.            _               !   char                              _
  3174.            _                                                     _
  3175.            _               !   money                            _
  3176.            _                                                    _
  3177.            _               !   date                              _
  3178.            _                                                     _
  3179.            _               !   unique                            _
  3180.            _                                                     _
  3181.            _               !   dbString                         _
  3182.            _                                                    _
  3183.            _               !   dbData                           _
  3184.            _                                                    _
  3185.            _                                                     _
  3186.            _                                                     _
  3187.            _ size          !   [ number ]                         _
  3188.            _                                                      _
  3189.            _               !   null                               _
  3190.            _                                                      _
  3191.            _                                                     _
  3192.            _                                                     _
  3193.            _ indexList     !   indexList indexSpec ;               _
  3194.            _                                                       _
  3195.            _               !   null                               _
  3196.            _                                                      _
  3197.            _                                                     _
  3198.            _                                                     _
  3199.            _ indexSpec     !   indexSpec2 , ident                 _
  3200.            _                                                      _
  3201.            _               !   null                               _
  3202.            ________________________________________________________
  3203.  
  3204.  
  3205.  
  3206.                         Table 3: BNF Syntax for DSC
  3207.  
  3208. DiamondBase_____________________________________________________________41_
  3209.  
  3210.  
  3211.  
  3212. 8.4    File Formats
  3213.  
  3214.  
  3215. DSC is responsible for creating only the header for the actual .db file associa*
  3216.  *ted
  3217.  
  3218. with each relation - the creation of b-trees and storage of data in the .db fil*
  3219.  *e are
  3220.  
  3221. delegated out to other parts of DiamondBase . Consequently this section deals
  3222.  
  3223. only with the header information for the data file.
  3224.  
  3225.  
  3226.  
  3227. 8.4.1  List Headers
  3228.  
  3229.  
  3230. Each data file contains enough information to derive the structure of each rela*
  3231.  *tion,
  3232.  
  3233. including the names of fields and the list of indicies. The information is brok*
  3234.  *en
  3235.  
  3236. into two parts - the field information and the index information. This informat*
  3237.  *ion
  3238.  
  3239. is encapsulated in two classes, the fieldList and indexList classes. These clas*
  3240.  *ses
  3241.  
  3242. are given in figure 2 and figure 3.
  3243.  
  3244.  
  3245.  
  3246. struct fieldList
  3247.  
  3248. f
  3249.  
  3250.     int          numFields;  // The number of fields for this
  3251.  
  3252.                                // relation
  3253.  
  3254.     fieldInfo  fields;      // A linked list of individual field
  3255.  
  3256.                                // information
  3257.  
  3258.  
  3259.  
  3260.     fieldList() ffields=0;numFields=0;g // Initialise class members
  3261.  
  3262.  
  3263.  
  3264.     fieldList() fdelete fields;g        // Destroy the list
  3265.  
  3266.  
  3267.  
  3268.     friend ostream& operator o (ostream&, fieldList&)
  3269.  
  3270.     friend ofstream& operator o (ofstream&, fieldList&)
  3271.  
  3272.     friend ifstream& operator AE (ifstream&, fieldList&)
  3273.  
  3274. g
  3275.  
  3276.  
  3277.                 Figure 2: Class description for the Field Lists
  3278.  
  3279.  
  3280.  
  3281.    As you will see these are only place keepers for the heads of two linked lis*
  3282.  *ts.
  3283.  
  3284. Since they are both essentially the same only the first will be discussed.
  3285.  
  3286.    Firstly the number of entries in the linked list is stored to make reading t*
  3287.  *he
  3288.  
  3289. list from a file easier.  The only other data member is a pointer to the head of
  3290.  
  3291. the list.
  3292.  
  3293.    Function-wise there is a constructor which simply sets it's data members to
  3294.  
  3295. zero and a destructor which causes the memory allocated for the list to be dele*
  3296.  *ted.
  3297.  
  3298.    Finally there are three operators for input/output.  The first is an inserti*
  3299.  *on
  3300.  
  3301. operator for normal output streams. This just causes the information stored in
  3302.  
  3303. the linked list to be placed on the stream given. The second insertion operator
  3304.  
  3305. 42_____________________________________________________DSC_Reference_Guide_
  3306.  
  3307.  
  3308.  
  3309. struct indexList
  3310.  
  3311. f
  3312.  
  3313.      int          numIndicies;  // The number of indicies for this
  3314.  
  3315.                                   // relation
  3316.  
  3317.      indexInfo  indicies;      // A linked list of individual index
  3318.  
  3319.                                   // information
  3320.  
  3321.  
  3322.  
  3323.      // Initialise class members
  3324.  
  3325.      indexList() findicies=0;numIndicies=0;g
  3326.  
  3327.  
  3328.  
  3329.      // Destroy the list
  3330.  
  3331.      indexList() fdelete indicies;g
  3332.  
  3333.  
  3334.  
  3335.      friend ostream& operator o (ostream&, indexList&)
  3336.  
  3337.      friend ofstream& operator o (ofstream&, indexList&)
  3338.  
  3339.      friend ifstream& operator AE (ifstream&, indexList&)
  3340.  
  3341. g
  3342.  
  3343.  
  3344.                  Figure 3: Class description for the Index List
  3345.  
  3346.  
  3347.  
  3348. writes the binary data to an output file. Lastly there is an extraction operator
  3349.  
  3350. for retreiving the binary information from an input file.
  3351.  
  3352.  
  3353.  
  3354. 8.4.2   List Information
  3355.  
  3356.  
  3357. The actual information for each field or index if stored in the structures shown
  3358.  
  3359. in figure 4 and figure 5. There is little similarity between the two, so both m*
  3360.  *ust
  3361.  
  3362. be discussed.
  3363.  
  3364.  
  3365.  
  3366.     fflThe fieldInfo Structure
  3367.  
  3368.  
  3369.  
  3370.     Field information is located in the fieldInfo structure.  These are chained
  3371.  
  3372. together in a linked list, the head of which is stored in the fieldList structu*
  3373.  *re.
  3374.  
  3375.     The structure contains the name of the field (as a character array), the ty*
  3376.  *pe
  3377.  
  3378. of the data stored in that field (as an integer. The list of valid types and th*
  3379.  *eir
  3380.  
  3381. identifiers can be found in section 8.2), the size of the type in bytes and a p*
  3382.  *ointer
  3383.  
  3384. to the next fieldInfo structure in the list.
  3385.  
  3386.     The constructor for the class creates a new fieldInfo object with the values
  3387.  
  3388. passed to it as parameters.
  3389.  
  3390.     The destructor deletes the space allocated for the field name and then dele*
  3391.  *tes
  3392.  
  3393. the next fieldInfo structure in the list, if it exists.
  3394.  
  3395.  
  3396.  
  3397.     fflThe indexInfo Structure
  3398.  
  3399. DiamondBase_____________________________________________________________43_
  3400.  
  3401.  
  3402.  
  3403.    The indexInfo structure really only differes in the information it stores. T*
  3404.  *here
  3405.  
  3406. is the index type (not currently used), an array of fields which are used in the
  3407.  
  3408. index (listed in decreasing sort precedence), and a pointer to the next indexIn*
  3409.  *fo
  3410.  
  3411. structure.
  3412.  
  3413.  
  3414.  
  3415. 8.4.3  Database File Headers
  3416.  
  3417.  
  3418. The structure of the file is shown in figure 6.
  3419.  
  3420.  
  3421. struct fieldInfo
  3422.  
  3423. f
  3424.  
  3425.     int          fldType;
  3426.  
  3427.     int          fldSize;
  3428.  
  3429.     char        fldName;
  3430.  
  3431.     fieldInfo  nextFld;
  3432.  
  3433.  
  3434.  
  3435.     fieldInfo(char name, int ty, int sz)
  3436.  
  3437.     f
  3438.  
  3439.          fldName = new char[strlen(name)+1];
  3440.  
  3441.          strcpy(fldName,name);
  3442.  
  3443.          fldType = ty;
  3444.  
  3445.          fldSize = sz;
  3446.  
  3447.  
  3448.  
  3449.          nextFld = 0;
  3450.  
  3451.     g
  3452.  
  3453.     fieldInfo()
  3454.  
  3455.     f
  3456.  
  3457.          delete fldName;
  3458.  
  3459.          if (nextFld)
  3460.  
  3461.              delete nextFld;
  3462.  
  3463.     g
  3464.  
  3465.     friend ostream& operator o (ostream&, fieldInfo&);
  3466.  
  3467.     friend ofstream& operator o (ofstream&, fieldInfo&);
  3468.  
  3469. g;
  3470.  
  3471.  
  3472.                Figure 4: Structures for storing field information
  3473.  
  3474. 44_____________________________________________________DSC_Reference_Guide_
  3475.  
  3476.  
  3477.  
  3478. struct indexInfo
  3479.  
  3480. f
  3481.  
  3482.      int          idxType;
  3483.  
  3484.      int          idxFields[MAX_FIELDS_IN_INDEX];
  3485.  
  3486.      indexInfo  nextIdx;
  3487.  
  3488.  
  3489.  
  3490.      indexInfo(int type, TIndicies indicies )
  3491.  
  3492.      f
  3493.  
  3494.          idxType = type;
  3495.  
  3496.          for(int i=0;i<MAX_FIELDS_IN_INDEX;i++)
  3497.  
  3498.          f
  3499.  
  3500.               idxFields[i] = indicies[i];
  3501.  
  3502.          g
  3503.  
  3504.          nextIdx = 0;
  3505.  
  3506.      g
  3507.  
  3508.      indexInfo()
  3509.  
  3510.      f
  3511.  
  3512.          if (nextIdx)
  3513.  
  3514.               delete nextIdx;
  3515.  
  3516.      g
  3517.  
  3518.      friend ostream& operator o (ostream&, indexInfo&);
  3519.  
  3520.      friend ofstream& operator o (ofstream&, indexInfo&);
  3521.  
  3522. g;
  3523.  
  3524.  
  3525.                Figure 5: Structures for storing index information
  3526.  
  3527. DiamondBase_____________________________________________________________45_
  3528.  
  3529.  
  3530.  
  3531.                       _______________________________
  3532.                       _         Size of header         _
  3533.                       _                                _
  3534.                       _           (4 bytes)           _
  3535.                       _________________________________
  3536.                       _         fieldList struct         _
  3537.                       _                                  _
  3538.                       _           (8 bytes)           _
  3539.                       _______________________________ _
  3540.                       _  1 or more fieldInfo structures  _
  3541.                       _                                  _
  3542.                       _        (16 bytes each)        _
  3543.                       _________________________________
  3544.                       _       indexList structure       _
  3545.                       _                                 _
  3546.                       _           (8 bytes)           _
  3547.                       _______________________________ _
  3548.                       _ 0 or more indexInfo structures _
  3549.                       _                                _
  3550.                       _        (12 bytes each)        _
  3551.                       _________________________________
  3552.                       _          Data records          _
  3553.                       _                                _
  3554.                       _               :               _
  3555.                       _                               _
  3556.                       _               :               _
  3557.                       _                               _
  3558.                       _               :               _
  3559.                       _                               _
  3560.                       _               :               _
  3561.                       _______________________________ _
  3562.  
  3563.  
  3564.  
  3565.                   Figure 6: File structure for database files.
  3566.  
  3567. 46______________________________________________________________File_formats_
  3568.  
  3569.  
  3570.  
  3571. 9     File formats
  3572.  
  3573.  
  3574.  
  3575. 9.1    Database Config file
  3576.  
  3577.  
  3578. This file just specifies the directory where the files related to a particular *
  3579.  *relation
  3580.  
  3581. reside. It contains lines in the form:
  3582.  
  3583.  
  3584.  
  3585. relationName=directory-path
  3586.  
  3587.  
  3588.  
  3589. 9.2    recServer
  3590.  
  3591.  
  3592. The record server is a generic block storage system. Upon creation, a record si*
  3593.  *ze
  3594.  
  3595. is nominated, and space for 4096 records is allocated.  The object inheriting a
  3596.  
  3597. recServer can then request a new record id, store the record at that location or
  3598.  
  3599. delete the record at that location.
  3600.  
  3601.     The actual layout of the file is documented in the next section.  The file
  3602.  
  3603. basically consists of a header followed by alternate bit pools and record stora*
  3604.  *ge
  3605.  
  3606. areas.  The file will expand in size to accomodate demand for records.  It is
  3607.  
  3608. currently unable to shrink as demand for records decrease.  There are ways of
  3609.  
  3610. implementing this but they are currently not used.
  3611.  
  3612.     When the database becomes 80% full, the number of free slots is increased by
  3613.  
  3614. 25% or 1 - whichever is bigger.  To keep the file size to a minimum, the record
  3615.  
  3616. space after the last bitPool isn't grabbed from the file system until records a*
  3617.  *re
  3618.  
  3619. actually stored there.
  3620.  
  3621.     Since the recServer is designed to be used as a storage facility for other *
  3622.  *pro-
  3623.  
  3624. gram modules, it has an offset which can be supplied at construction to reserve
  3625.  
  3626. a certain number of bytes at the beginning of the file for other purposes.
  3627.  
  3628.  
  3629.  
  3630. 9.2.1   Header
  3631.  
  3632.  
  3633. The header keeps track of the current status of the database. Namely the size of
  3634.  
  3635. each record, the number of active records and the total storage capacity of the
  3636.  
  3637. database in records.
  3638.  
  3639.  
  3640.  
  3641. 9.2.2   Bit Pools
  3642.  
  3643.  
  3644. Bitpools are essentially bitmaps which record which records are used in the fol-
  3645.  
  3646. lowing record storage area.  It also has a header to record how many bits are
  3647.  
  3648. used. This allows a quick scan of bits to determine which record slots are empty
  3649.  
  3650. in the following record storage area. Bitpools are currently a fixed size of 40*
  3651.  *96
  3652.  
  3653. slots - which are bit packed to occupy 512 bytes.
  3654.  
  3655. DiamondBase_____________________________________________________________47_
  3656.  
  3657.  
  3658.  
  3659. 9.2.3  Record Pools
  3660.  
  3661.  
  3662. The record pools are a section of the file which is 4096 * lengthOfRecord long.
  3663.  
  3664. There is no flag on the actual record to indicate whether it is used or not - t*
  3665.  *his is
  3666.  
  3667. simply a storage area. The preceding bitPool must be interrogated to determine
  3668.  
  3669. the status of a particular bitPool.
  3670.  
  3671.  
  3672.  
  3673. 9.2.4  bTree bucket layout
  3674.  
  3675.  
  3676. The bTree is where the real magic in the database happens. For a detailed view -
  3677.  
  3678. we suggest reading the comments in bucket.cc. The bTree consists of a header
  3679.  
  3680. and a data area. The header has pointers to the previous, next and parent bucke*
  3681.  *ts
  3682.  
  3683. as well as a flag to indicate interior or leaf node.  Note that the parent poin*
  3684.  *ter
  3685.  
  3686. may be incorrect if you were in the right hand side of the parent bucket when it
  3687.  
  3688. split. These pointers are repaired during tree traversal for efficiency reasons*
  3689.  *. It
  3690.  
  3691. also stores the number of active keys in the data area.
  3692.  
  3693.    The data area consists of alternating pointer key pairs with one more pointer
  3694.  
  3695. than key. The pointers are long integers which either point to child buckets (in
  3696.  
  3697. an interior node) or the record in the recServer at a leaf node. The key data is
  3698.  
  3699. long word aligned to avoid nasty problems during key comparison. This makes
  3700.  
  3701. the index storage larger than necessary but is faster. Intel architectures coul*
  3702.  *d be
  3703.  
  3704. optimized as the processor is alignment friendly.
  3705.  
  3706.    The bTree inherits a recServer to store its actual buckets. There is a global
  3707.  
  3708. header before the recServer header which records the unaligned length of the key
  3709.  
  3710. and where the root bucket is.
  3711.  
  3712.    I refuse to describe the full bTree manipulation details.  I can recommend
  3713.  
  3714. Smith, "Data Structures and Algorithms" for a good discussion. If you want to
  3715.  
  3716. know how ours works - read Kevin's code. If there are sufficient enquiries we w*
  3717.  *ill
  3718.  
  3719. describe - when we have looked at the code again.
  3720.  
  3721.  
  3722.  
  3723. 9.3    Variable Length Fields
  3724.  
  3725.  
  3726. The format of the .str file used by the memServer for variable length fields (t*
  3727.  *ypes
  3728.  
  3729. dbData and dbString) are described in section 5.
  3730.  
  3731. 48____________________________________________________________Miscellaneous_
  3732.  
  3733.  
  3734.  
  3735. 10      Miscellaneous
  3736.  
  3737.  
  3738.  
  3739. 10.1     ToDo
  3740.  
  3741.  
  3742.     fflImplementing multi-user version.
  3743.  
  3744.       This is very high priority - and will probably involve some use of shared
  3745.  
  3746.       memory and/or a central locking process.
  3747.  
  3748.       This has been implemented for a single machine, multi client model.
  3749.  
  3750.  
  3751.     fflImplementing duplicate records
  3752.  
  3753.       Not likely!  We've come to the conclusion that the inclusion of a unique
  3754.  
  3755.       field in an index gives exactly what ducplicate indexes gives you except *
  3756.  *the
  3757.  
  3758.       semantics are far better.
  3759.  
  3760.  
  3761.     fflA query language
  3762.  
  3763.  
  3764.     fflBtree reconstruction facility
  3765.  
  3766.  
  3767.     fflRecord dump facility This now exists in the db2txt program.  The recon-
  3768.  
  3769.       struction facility will be the reverse of this once written. It is next o*
  3770.  *n the
  3771.  
  3772.       agenda.
  3773.  
  3774.  
  3775.     fflMonitoring facility to count database operations
  3776.  
  3777.  
  3778.     fflDatabase browser
  3779.  
  3780.       This has been made easier by the recent addition of diaGRel.
  3781.  
  3782.  
  3783.     fflInteractive relation creation
  3784.  
  3785.  
  3786.     fflEliminate bTree indexing of completely unique fields
  3787.  
  3788.  
  3789.     fflBetter fan-out specification in database
  3790.  
  3791.       The bTree buckets are fixed size currently - and will take as many keys as
  3792.  
  3793.       will fit. The number of keys should be set and the size of the bTree buck*
  3794.  *et
  3795.  
  3796.       varied.
  3797.  
  3798.  
  3799.     fflefficient bTree deletion
  3800.  
  3801.       bTree nodes aren't merged when they drop below half full. They should be
  3802.  
  3803.       for efficiency reasons.
  3804.  
  3805.  
  3806.     fflDatabase update tool
  3807.  
  3808.       When adding fields to a database, it would be nice to be able to upgrade
  3809.  
  3810.       the existing database automatically. This has to be done by hand currentl*
  3811.  *y.
  3812.  
  3813. DiamondBase_____________________________________________________________49_
  3814.  
  3815.  
  3816.  
  3817. 10.2    Profiling data
  3818.  
  3819.  
  3820. We include some sample profiling data for those speed freaks out there who want
  3821.  
  3822. to improve performance. We found some very interesting things after our initial
  3823.  
  3824. profiling experiments - like the fact that our memory checking library had 90%
  3825.  
  3826. of the CPU time.
  3827.  
  3828.    The bcopy function was also overused quite a bit and this led to far too many
  3829.  
  3830. function calls where much better alternatives were available.  Use of bcopy has
  3831.  
  3832. been reduced to a minimum.
  3833.  
  3834.    We have attempted to speed up all the very frequently used functions and
  3835.  
  3836. eliminate unnecessary calls to them.
  3837.  
  3838.    Kevin is to provide this bit. [Well, I will one day when I can collect all t*
  3839.  *he
  3840.  
  3841. data and get it into some format that might be vaguely useful for something
  3842.  
  3843. or someone and possibly formatted in a way that could fit here, in addition to
  3844.  
  3845. making this sentence shorter in some way or another].
  3846.  
  3847.  
  3848.  
  3849. References
  3850.  
  3851.  
  3852.  [1]C.J. Date, An Introduction to Database Systems, Volume 1, Fifth Edition,
  3853.  
  3854.     Addison-Wesley, 1992, pp 245-398.
  3855.