| Name | Modified | Size | Downloads / Week |
|---|---|---|---|
| php | 2026-07-26 | ||
| README.md | 2026-07-26 | 6.1 kB | |
| Totals: 2 Items | 6.1 kB | 0 |
CHB (Colony Hash Bucket)
CHB is a lightweight on-disk hash table designed for fast key-value storage with a simple and deterministic binary format in 275 lines of pure PHP.
Installation
require_once('Chb.php');
Opening a Database
Open an existing CHB file or create a new one. MUL and SZE can be only specified at creation time.
$clu = 0;
$mul = 1;
$sze = 16;
$db = new Chb('storage.chb', $clu, $mul, $sze);
Parameters
| Parameter | Description |
|---|---|
path |
Path to the CHB file |
clu |
cluster optimization, set it to 0 |
mul |
Bucket multiplier (65536 × MUL buckets) from 1 to 255 |
sze |
An index of preset record sizes that range from few bytes to almost 65536 |
Storing Data
Insert or update a key/value pair.
$db->set(
'customer:1001',
json_encode([
'name' => 'John',
'email' => 'john@example.com'
])
);
Example
$db->set('username', 'admin');
$db->set('email', 'admin@example.com');
Retrieving Data
Retrieve a value associated with a key.
$value = $db->get('username');
if ($value !== null) {
echo $value;
}
Example
$email = $db->get('email');
echo $email;
Deleting Data
Records are logically deleted and may be recycled later.
$db->delete('username');
Example
if ($db->delete('email')) {
echo "Deleted";
}
Scanning Records
Iterate through all records stored in the database.
foreach ($db->scan() as $key => $value) {
echo $key . PHP_EOL;
echo $value . PHP_EOL;
}
Example
foreach ($db->scan() as $key => $value) {
printf(
"%s => %s\n",
$key,
$value
);
}
Closing the Database
Always close the database when finished.
$db->close();
Complete Example
<?php
require_once('Chb.php');
$db = new Chb('example.chb');
$db->set('user:1', 'John Doe');
$db->set('user:2', 'Jane Doe');
echo $db->get('user:1') . PHP_EOL;
foreach ($db->scan() as $key => $value) {
echo "$key => $value\n";
};
$db->delete('user:2');
echo "after deletion..." . PHP_EOL;
foreach ($db->scan() as $key => $value) {
echo "$key => $value\n";
};
$db->close();
Notes
- Keys may contain from 1 to 128 bytes.
- Records have a fixed size defined at database creation time.
- Deleted records are logically removed and can be reused.
- Bucket count is calculated as
65536 × MUL. - Lookups are performed using hash-based bucket indexing.
- CHB uses file locking to support concurrent access.
- The file format is portable and easy to inspect or recover.
Typical Use Cases
- Persistent caches
- Metadata stores
- Embedded applications
- Index files
- Key/value storage
- Lightweight storage engines
- Custom database projects
Details
- default MUL is 1, that means CHB will prepare the db for 65536 buckets, useful for storing about 45000 records, you should adapt for a load factor of 0.7. With MUL set to 255 you can store 11000000 records.
- default SZE is 16, that means 576 bytes for the key and the value (see below). Know your data, because the fixed record size can make your file very big with a lot of wasted space.
- I have developed this class, because my hosting provider had the DBA extension disabled, and I wanted a simple way to store small JSON records.
- The on-disk format is saved in little-endian.
Creating a Database
In case you need help to set the correct parameters, you can use the mulsze.php script. It accepts the expected records count and the expected content (key + value) size in bytes. In the following example I expect about 200000 record of 3200 bytes.
php mulsze.php 200000 3200
This is the output.
Expected records count: `200000`, expected record size: `3200`.
With 0.7 load factor you need the following MUL: 5 for a total of 327680 buckets.
The following is the value for SZE: 19 for a max key+value of 4086 bytes.
Note that for every record you will waste 886 bytes.
You can initialize your database in this way:
$db = new Chb('storage.chb', 0, 5, 19);
$db->close();
What about CLU
My use case requires records with content sized 576 bytes. When the content is less than 4096 bytes and the chains become very long, the algorithm can perform an optimization by preallocating records on the disk, marking them deleted (and losing space of course). In this way the locality improves and the performance is better. In this cases the right thing is to perform a rehash with new parameters.
In my case I was testing 5.000.000 records with 65536 buckets with chain longer than 70 hops. This is not something you want; using the CLU optimiziation the performance improved. Notice that this can be enabled after creation by passing $clu = 1, but the real solution is to rehash.
SZE values
SZE sets the record size, at left the index to be passed, at right the max content (key + value) size.
| Index | Max Content Size |
|---|---|
1 |
4 |
2 |
6 |
3 |
12 |
4 |
26 |
5 |
30 |
6 |
36 |
7 |
54 |
8 |
56 |
9 |
82 |
10 |
96 |
11 |
108 |
12 |
186 |
13 |
264 |
14 |
306 |
15 |
446 |
16 |
576 |
17 |
810 |
18 |
1356 |
19 |
4086 |
20 |
8183 |
21 |
12279 |
22 |
16375 |
23 |
20471 |
24 |
24567 |
25 |
28663 |
26 |
32759 |
27 |
36855 |
28 |
40951 |
29 |
45047 |
30 |
49143 |
31 |
53239 |
32 |
57335 |
33 |
61431 |
34 |
65527 |
Changelog
2026-07-26(0.1.10) Serious bugfix that could render the old file unreadable, read the Chb source code, in the beginning there are more details.