WiscDB
WiscDB Documentation

Table of contents

  1. File layout
  2. Building and modifying the system
    1. Executing a build
    2. Modifying and running main
  3. WiscDB API
    1. File storage
      1. Creating, opening, and deleting files
      2. Reading and writing data in a file
      3. Reading and writing data in a page

File layout

The files in this package are organized under the following hierarchy:

 include/            header files for provided classes
 lib/                object files for provided classes (File, Page)
 exceptions/         library of exceptions defined for WiscDB
 .                   main code for WiscDB, Lab 1

 

You will likely be most interested in files in the main directory

Executing a build

All command examples are meant to be run at the command prompt from the wiscdb directory. When executing a command, omit the $ prompt (so “$ make” means you just type “make” and press enter).

To build the executable:

   $ make

Modifying and running main

To run the executable, first build the code, then run:

   $ ./wiscdb_main

If you want to edit what wiscdb_main does, edit main.cpp.

WiscDB API

File storage

Interaction with the underlying filesystem is handled by two classes: File and Page. Files store zero or more fixed-length pages; each page holds zero or more variable-length records.

Record data is represented using std::strings of arbitrary characters.

Creating, opening, and deleting files

Files must first be created before they can be used:

  // Create and open a new file with the name "filename.db".
  wiscdb::File new_file = wiscdb::File::create("filename.db");

If you want to open an existing file, use File::open like so:

  // Open an existing file with the name "filename.db".
  wiscdb::File existing_file = wiscdb::File::open("filename.db");

Multiple File objects share the same stream to the underlying file. The stream will be automatically closed when the last File object is out of scope; no explicit close command is necessary.

You can delete a file with File::remove:

  // Delete a file with the name "filename.db".
  wiscdb::File::remove("filename.db");

Reading and writing data in a file

Data is added to a File by first allocating a Page, populating it with data, and then writing the Page back to the File.

For example:

   #include "file.h"

   ...

   // Write a record with the value "hello, world!" to the file.
   wiscdb::File db_file = wiscdb::File::open("filename.db");
   wiscdb::Page new_page = db_file.allocatePage();
   new_page.insertRecord("hello, world!");
   db_file.writePage(new_page);

Pages are read back from a File using their page numbers:

   #include "file.h"
   #include "page.h"

   ...

   // Allocate a page and then read it back.
   wiscdb::Page new_page = db_file.allocatePage();
   db_file.writePage(new_page);
   const wiscdb::PageId& page_number = new_page.page_number();
   wiscdb::Page same_page = db_file.readPage(page_number);

You can also iterate through all pages in the File:

   #include "file_iterator.h"

   ...

   for (wiscdb::FileIterator iter = db_file.begin();
        iter != db_file.end();
        ++iter) {
     std::cout << "Read page: " << iter->page_number() << std::endl;
   }

Reading and writing data in a page

Pages hold variable-length records containing arbitrary data.

To insert data on a page:

   #include "page.h"

   ...

   wiscdb::Page new_page;
   new_page.insertRecord("hello, world!");

Data is read by using RecordIds, which are provided when data is inserted:

   #include "page.h"

   ...

   wiscdb::Page new_page;
   const wiscdb::RecordId& rid = new_page.insertRecord("hello, world!");
   new_page.getRecord(rid); // returns "hello, world!"

As Pages use std::string to represent data, it's very natural to insert strings; however, any data can be stored:

   #include "page.h"

   ...

   struct Point {
     int x;
     int y;
   };
   Point new_point = {10, -5};
   wiscdb::Page new_page;
   std::string new_data(reinterpret_cast<char*>(&new_point),
                        sizeof(new_point));
   const wiscdb::RecordId& rid = new_page.insertRecord(new_data);
   Point read_point =
       *reinterpret_cast<const Point*>(new_page.getRecord(rid).data());

Note that serializing structures like this is not industrial strength; it's better to use something like Google's protocol buffers or Boost serialization.

You can also iterate through all records in the Page:

   #include "page_iterator.h"

   ...

   for (wiscdb::PageIterator iter = new_page.begin();
        iter != new_page.end();
        ++iter) {
     std::cout << "Record data: " << *iter << std::endl;