Using KitaroDB: the basic procedure
The following are the basic steps you’ll perform to create, access, update, manage and deploy a KitaroDB database:
- Download and install KitaroDB. See Downloads.
- Add a reference in Visual Studio to KitaroDB resources. See Using KitaroDB classes below.
- Decide what kind of database you want: a key-value pair database or an intrusive-keyed database with records. If you want an intrusive-keyed database, define the intrusive keys. See Creating a KitaroDB database, and see Keys and records in intrusive-keyed databases for information on how keys work.
- Create the database. See Creating a KitaroDB database.
- Insert, delete, read, and update records or key-value pairs, and manage the database as necessary. See the following:
- Deploy your application. Note that for .NET Framework applications, deployment systems must have Visual Studio 2012 C Runtime libraries and .NET Framework 4.0 or higher. Additionally, if you plan to ship KitaroDB files with your application, be sure to include both the index file and the data file. See Understanding KitaroDB files below.
As you work with KitaroDB, refer to the API documentation for your platform for information on classes, methods, enumerations, and so forth:
Using KitaroDB classes
Classes in the KitaroDB API are in the KitaroDB namespace. To use KitaroDB API classes, you must add a reference in your Visual Studio project to one of the following:
- For Windows Store and Windows Phone development: KitaroDB SDK for Windows 8
- For native .NET application development: KitaroDB.DLL
- For C++ Win32 development: db.h
NOTE: Most methods in the KitaroDB API have two versions: one that ends in Async and one that doesn’t—for example, DBSelectAsync and DBSelect. For Win32 development, you must use methods that don’t end in Async. For Windows Store (WinRT) and Windows Phone application development, you must use methods that do end in Async, with a few exceptions. (See WinRT API documentation.)
For method parameters, note that WinRT types, such as Platform::String, are used for Windows Store and Windows Phone development. Native .NET types are used for .NET Framework development for Win32 platforms. And C++ types, such as std::string, are used for native C++ development for Win32 platforms.
Understanding KitaroDB files
KitaroDB databases are built on indexed sequential access method (ISAM) files. A KitaroDB database consists of two files with the same name but different extensions. One file contains data and by default has the .kd1 extension—for example, orders.kd1. The other file contains indexes for the data and by default has the .kdb extension—for example, orders.kdb. These two files are always referenced as a single file with the extension of the index file. For example, a database with the orders.kd1 and orders.kdb files is referenced as orders.kdb.
When you create or rename a KitaroDB database, you supply the index filename, and KitaroDB creates a data filename based on the index filename. That data filename will be identical to the index filename except that the last character of the file extension is replaced by a 1. So, for example, if you specify an index filename of mykdb.abc, the data file will be named mykdb.ab1. Note, however, that if the extension for the index file ends in a number, the last character of the data file name (not extension) will be replaced by an underscore. For example, if the index file is order.ab1, the data file will be orde_.ab1.
Note the following:
- If you want to ship KitaroDB files with your application, be sure to include both files.
- KitaroDB 2.0 can access files created with earlier versions of KitaroDB, but this access is read only.
Using GRFAs and RFAs
Records in KitaroDB databases include global record file addresses (GRFAs), which are 10-byte binary identifiers that uniquely identify the location and contents of a record in a file. You can use GRFAs to access previously-read records and to detect when a record has changed. A GRFA consists of a six-byte record file address (RFA) and four additional bytes that change when the contents of the record change. Note that the RFA remains the same for the life of the record, so you can use it to access a record whether or not its content has changed.
You can get the GRFA for a record when you insert it (the grfa parameter to DB.Insert[Async]
returns this value). And you can use DBCursor.GetGRFA
to get the GRFA of the record at the current cursor position. You can use a GRFA or RFA to position an unfiltered cursor, and you can use a GRFA or RFA to manually unlock records. See Inserting a record or key-value pair
and Using cursors
for more information.
Keys and records in intrusive-keyed databases
KitaroDB supports high-speed keyed access, and it supports ordered sequential access for intrusive-keyed databases. As your database grows, high-speed keyed access is maintained. Your file’s size can grow to fit the needs of your application, given the physical limitations of your disk.
For example, you can have a file that contains a record for each customer. (A record consists of a set of fields, each of which stores a specific item of data, such as a customer number, a first and last name, a company name, and so forth.) If you want to find a particular customer, such as customer 125 or customer B. Jones, your program might have to search the entire file. KitaroDB, however, provides efficient access using an index.
An index enables the database to quickly find specific records in a database file without having to search the entire file and without requiring your program to look at extra records. This is called keyed access. It also enables you to define an order for the sequential processing of a database file. This is called sequential access. Each index in a file is defined by a key, which is one or more fields or portions of fields from a record that are used to locate that record. For example, you can define a key for a customer number field that places customer numbers in ascending or descending order within the corresponding index.
A file can have more than one index. For example, you could define an index for a customer number field and another index for a customer name field. These indexes would enable KitaroDB to quickly access the record for customer number 125, for example, or the record for customer B. Jones. The keys of a file also define the sequential order in which the file may be processed. For example, you could access a file sequentially by the customer number key, alphabetically by the customer name key, geographically by the customer city key, or by any other key that’s been defined.
How it works…
A KitaroDB database’s index contains leaf entries, which are sequentially ordered key values that point to corresponding data records. For example, an index defined by a customer number key, as illustrated in figure 1 below, could contain the customer numbers (key values) in descending order for all customers in a file. These customer number entries would then point to data records, which would be in no particular order. The index, however, is always in a specific order as defined by the key.
Indexes are also structured hierarchically so that access to any particular record occurs with a minimum of index reading. Access to any data record by a particular key requires the same number of index reads, provided the index doesn’t change. This number is determined by the index depth. Keyed access requires one index read for each level of the index. The number of levels required for an index is universally proportional to key length. Large files (one million or more records) with long keys (45 or more characters) have five or more levels of index depth.
Figure 1. Diagram of KitaroDB file’s index.
As shown in figure 1 above, a file’s index is composed of blocks. A block is the smallest unit of an index that can be read or written at one time, and block size is set when you create a file. (If the key size is less than or equal to 256K, the block size is set to 4K. If it is greater than 256K, the block size is set to 32K.) The index in the diagram is three levels deep. In this case, separator blocks make up the first two levels of the index. (Any file with more than one index block has separator blocks.) The third or last level is made up of leaf blocks, which contain sorted key values (in this case, customer numbers) with a one-to-one correspondence between each leaf entry and the data record to which it points. The separator blocks exist as pathways to the leaf entries and are composed of pointers to lower-level index blocks and separator values that narrow the range of key values. The root block is a special separator block that is read first on any keyed access.
For example, let’s assume we want to access the data record for customer number 40002 by a customer number key using the following method:
DB.Select(null, "40002", DBLockFlags.Auto)
First, the root block is read. KitaroDB will determine that our customer number, 4, is greater than the value 3. KitaroDB therefore reads the separator block indicated by the first bold pointer in the diagram. KitaroDB then determines that the first two numbers of the customer number (40) are less than the value 52 in the separator block. It therefore reads the next block indicated by the second bold pointer in the diagram. KitaroDB then finds entry 40002 within this block, which accesses the data record for customer number 40002. By structuring the index hierarchically, KitaroDB accesses data records without having to read through the entire index. Also note that reading a record by key value requires the same number of index reads.