1IOWOW - The C11 persistent key/value database engine based on [skip list](https://en.wikipedia.org/wiki/Skip_list) 2================================================================================================================== 3 4 5[](https://t.me/ejdb2) 6[](https://github.com/Softmotions/iowow/blob/master/LICENSE) 7 8 9Website http://iowow.io 10 11# Key components 12 13* [iwkv.h](https://github.com/Softmotions/iowow/blob/master/src/kv/iwkv.h) Persistent key/value database engine 14* [iwfsmfile.h](https://github.com/Softmotions/iowow/blob/master/src/fs/iwfsmfile.h) File blocks allocation manager like `malloc()` on files 15 16# IWKV 17 18## Features 19 20* Support of multiple key-value databases within a single file 21* Online database backups 22* Native support of integer keys 23* [Write Ahead Logging (WAL) support](http://iowow.io/wal) 24* Ultra-fast traversal of database records 25* Compound keys support 26* Good performance comparing its main competitors: `lmdb`, `leveldb`, `kyoto cabinet` 27* Tiny C11 library (200Kb) can be easily embedded into any software 28 29[](https://iowow.io/articles/intro/) 30 31 32## Used by 33 34* EJDB - Embeddable JSON database engine. http://ejdb.org 35 36## Limitations 37 38* Maximum iwkv storage file size: `512 GB (0x7fffffff80)` 39* Total size of a single key+value record must be not greater than `255Mb (0xfffffff)` 40* In-memory cache for every opened database takes `~130Kb`, cache can be disposed by `iwkv_db_cache_release()` 41 42# Supported platforms 43 44## Linux 45### Ubuntu/Debian 46#### PPA repository 47 48```sh 49sudo add-apt-repository ppa:adamansky/iwowow 50sudo apt-get update 51sudo apt-get install iowow 52``` 53 54#### Building debian packages 55 56```sh 57mkdir build && cd build 58cmake .. -DCMAKE_BUILD_TYPE=Release -DPACKAGE_DEB=ON 59make package 60``` 61 62### RPM based Linux distributions 63```sh 64mkdir build && cd build 65cmake .. -DCMAKE_BUILD_TYPE=Release -DPACKAGE_RPM=ON 66make package 67``` 68 69## FreeBSD 70 71Successfully tested on FreeBSD 10/11 72 73## OSX 74 75Successfully tested on OSX 10.12/10.13 76 77## Windows 78 79[Cross-compilation for windows](http://iowow.io/iw/win) 80 81 82## MIPS based systems (+big-endian) 83 84Successfully tested on Debian 9.4, MIPS 32, gcc 6.x compiler. 85 86# Examples 87 88[src/kv/examples](https://github.com/Softmotions/iowow/tree/master/src/kv/examples) 89 90## Store and retrieve records 91 92```c 93#include <iowow/iwkv.h> 94#include <string.h> 95#include <stdlib.h> 96 97int main() { 98 IWKV_OPTS opts = { 99 .path = "example1.db", 100 .oflags = IWKV_TRUNC // Cleanup database before open 101 }; 102 IWKV iwkv; 103 IWDB mydb; 104 iwrc rc = iwkv_open(&opts, &iwkv); 105 if (rc) { 106 iwlog_ecode_error3(rc); 107 return 1; 108 } 109 // Now open mydb 110 // - Database id: 1 111 rc = iwkv_db(iwkv, 1, 0, &mydb); 112 if (rc) { 113 iwlog_ecode_error2(rc, "Failed to open mydb"); 114 return 1; 115 } 116 // Work with db: put/get value 117 IWKV_val key, val; 118 key.data = "foo"; 119 key.size = strlen(key.data); 120 val.data = "bar"; 121 val.size = strlen(val.data); 122 123 fprintf(stdout, "put: %.*s => %.*s\n", 124 (int) key.size, (char *) key.data, 125 (int) val.size, (char *) val.data); 126 127 rc = iwkv_put(mydb, &key, &val, 0); 128 if (rc) { 129 iwlog_ecode_error3(rc); 130 return rc; 131 } 132 // Retrieve value associated with `foo` key 133 val.data = 0; 134 val.size = 0; 135 rc = iwkv_get(mydb, &key, &val); 136 if (rc) { 137 iwlog_ecode_error3(rc); 138 return rc; 139 } 140 141 fprintf(stdout, "get: %.*s => %.*s\n", 142 (int) key.size, (char *) key.data, 143 (int) val.size, (char *) val.data); 144 145 iwkv_val_dispose(&val); 146 iwkv_close(&iwkv); 147 return 0; 148} 149``` 150**Compile and run:** 151 152```sh 153gcc -std=gnu11 -Wall -pedantic -c -o example1.o example1.c 154gcc -o example1 example1.o -liowow 155 156./example1 157 put: foo => bar 158 get: foo => bar 159``` 160 161## Cursor iteration example 162 163```c 164/// 165/// Fills database with a set of football table records 166/// then traverse records according to club name in ascending and descending orders. 167/// 168 169#include "iwkv.h" 170#include <string.h> 171#include <stdlib.h> 172#include <stdint.h> 173 174static struct data_s { 175 const char *club; 176 uint8_t points; 177} _points[] = { 178 179 { "Aston Villa", 25 }, 180 { "Manchester City", 57 }, 181 { "Arsenal", 40 }, 182 { "Everton", 37 }, 183 { "West Ham United", 27 }, 184 { "Tottenham Hotspur", 41 }, 185 { "Wolverhampton Wanderers", 43 }, 186 { "Norwich City", 21 }, 187 { "Leicester City", 53 }, 188 { "Manchester United", 45 }, 189 { "Newcastle United", 35 }, 190 { "Brighton & Hove Albion", 29 }, 191 { "AFC Bournemouth", 27 }, 192 { "Crystal Palace", 39 }, 193 { "Sheffield United", 43 }, 194 { "Burnley", 39 }, 195 { "Southampton", 34 }, 196 { "Watford", 27 }, 197 { "Chelsea", 48 }, 198 { "Liverpool", 82 }, 199}; 200 201static iwrc run(void) { 202 IWKV_OPTS opts = { 203 .path = "cursor1.db", 204 .oflags = IWKV_TRUNC // Cleanup database before open 205 }; 206 IWKV iwkv; 207 IWDB db; 208 IWKV_cursor cur = 0; 209 iwrc rc = iwkv_open(&opts, &iwkv); 210 RCRET(rc); 211 212 rc = iwkv_db(iwkv, 1, 0, &db); 213 RCGO(rc, finish); 214 215 for (int i = 0; i < sizeof(_points) / sizeof(_points[0]); ++i) { 216 struct data_s *n = &_points[i]; 217 IWKV_val key = { .data = (void *) n->club, .size = strlen(n->club) }; 218 IWKV_val val = { .data = &n->points, .size = sizeof(n->points) }; 219 RCC(rc, finish, iwkv_put(db, &key, &val, 0)); 220 } 221 222 fprintf(stdout, ">>>> Traverse in descending order\n"); 223 RCC(rc, finish, iwkv_cursor_open(db, &cur, IWKV_CURSOR_BEFORE_FIRST, 0)); 224 while ((rc = iwkv_cursor_to(cur, IWKV_CURSOR_NEXT)) == 0) { 225 IWKV_val key, val; 226 RCC(rc, finish, iwkv_cursor_get(cur, &key, &val)); 227 fprintf(stdout, "%.*s: %u\n", 228 (int) key.size, (char *) key.data, 229 *(uint8_t *) val.data); 230 iwkv_kv_dispose(&key, &val); 231 } 232 rc = 0; 233 iwkv_cursor_close(&cur); 234 235 fprintf(stdout, "\n>>>> Traverse in ascending order\n"); 236 RCC(rc, finish, iwkv_cursor_open(db, &cur, IWKV_CURSOR_AFTER_LAST, 0)); 237 while ((rc = iwkv_cursor_to(cur, IWKV_CURSOR_PREV)) == 0) { 238 IWKV_val key, val; 239 RCC(rc, finish, iwkv_cursor_get(cur, &key, &val)); 240 fprintf(stdout, "%.*s: %u\n", 241 (int) key.size, (char *) key.data, 242 *(uint8_t *) val.data); 243 iwkv_kv_dispose(&key, &val); 244 } 245 rc = 0; 246 iwkv_cursor_close(&cur); 247 248 // Select all keys greater or equal than: Manchester United 249 { 250 fprintf(stdout, "\n>>>> Records GE: %s\n", _points[9].club); 251 IWKV_val key = { .data = (void *) _points[9].club, .size = strlen(_points[9].club) }, val; 252 RCC(rc, finish, iwkv_cursor_open(db, &cur, IWKV_CURSOR_GE, &key)); 253 do { 254 RCC(rc, finish, iwkv_cursor_get(cur, &key, &val)); 255 fprintf(stdout, "%.*s: %u\n", 256 (int) key.size, (char *) key.data, 257 *(uint8_t *) val.data); 258 iwkv_kv_dispose(&key, &val); 259 } while ((rc = iwkv_cursor_to(cur, IWKV_CURSOR_NEXT)) == 0); 260 rc = 0; 261 } 262 iwkv_cursor_close(&cur); 263 264finish: 265 if (cur) { 266 iwkv_cursor_close(&cur); 267 } 268 iwkv_close(&iwkv); 269 return rc; 270} 271 272int main() { 273 iwrc rc = run(); 274 if (rc) { 275 iwlog_ecode_error3(rc); 276 return 1; 277 } 278 return 0; 279} 280``` 281 282Output: 283``` 284>>>> Traverse in descending order 285Wolverhampton Wanderers: 43 286West Ham United: 27 287Watford: 27 288Tottenham Hotspur: 41 289Southampton: 34 290Sheffield United: 43 291Norwich City: 21 292Newcastle United: 35 293Manchester United: 45 294Manchester City: 57 295Liverpool: 82 296Leicester City: 53 297Everton: 37 298Crystal Palace: 39 299Chelsea: 48 300Burnley: 39 301Brighton & Hove Albion: 29 302Aston Villa: 25 303Arsenal: 40 304AFC Bournemouth: 27 305 306>>>> Traverse in ascending order 307AFC Bournemouth: 27 308Arsenal: 40 309Aston Villa: 25 310Brighton & Hove Albion: 29 311Burnley: 39 312Chelsea: 48 313Crystal Palace: 39 314Everton: 37 315Leicester City: 53 316Liverpool: 82 317Manchester City: 57 318Manchester United: 45 319Newcastle United: 35 320Norwich City: 21 321Sheffield United: 43 322Southampton: 34 323Tottenham Hotspur: 41 324Watford: 27 325West Ham United: 27 326Wolverhampton Wanderers: 43 327 328>>>> Records GE: Manchester United 329Manchester United: 45 330Manchester City: 57 331Liverpool: 82 332Leicester City: 53 333Everton: 37 334Crystal Palace: 39 335Chelsea: 48 336Burnley: 39 337Brighton & Hove Albion: 29 338Aston Villa: 25 339Arsenal: 40 340AFC Bournemouth: 27 341``` 342 343 344