Skip to content

Commit 956adb2

Browse files
committed
Relax FILE_ERROR handling. Benchmark example
1 parent e4a3f7a commit 956adb2

File tree

6 files changed

+250
-24
lines changed

6 files changed

+250
-24
lines changed

examples/benchmark/bench_data.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#!/usr/bin/env python2
2+
3+
'''
4+
Based on - https://www.unixuser.org/~euske/doc/cdbinternals/pycdb.py.html
5+
'''
6+
7+
# calc hash value with a given key
8+
def calc_hash(s):
9+
return reduce(lambda h, c: (((h << 5) + h) ^ ord(c)) & 0xffffffffL, s, 5381)
10+
11+
# cdbmake(filename, hash)
12+
def cdbmake(f, a):
13+
from struct import pack
14+
15+
# write cdb
16+
def write_cdb(fp):
17+
pos_header = fp.tell()
18+
19+
# skip header
20+
p = pos_header + 8 * 256
21+
fp.seek(p)
22+
23+
bucket = [[] for i in range(256)]
24+
25+
# write data & make hash
26+
for (k, v) in a.iteritems():
27+
fp.write(pack('<LL', len(k), len(v)))
28+
fp.write(k)
29+
fp.write(v)
30+
h = calc_hash(k)
31+
bucket[h % 256].append((h, p))
32+
p += len(k) + len(v) + 8
33+
34+
pos_hash = p
35+
36+
# write hash tables
37+
for bt in bucket:
38+
if bt:
39+
nslots = 2 * len(bt)
40+
hash_tab = [(0, 0) for i in range(nslots)]
41+
for (h, p) in bt:
42+
i = (h >> 8) % nslots
43+
while hash_tab[i][1]: # is slot already occupied?
44+
i = (i + 1) % nslots
45+
hash_tab[i] = (h, p)
46+
for (h, p) in hash_tab:
47+
fp.write(pack('<LL', h, p))
48+
49+
# write header
50+
fp.seek(pos_header)
51+
for bt in bucket:
52+
fp.write(pack('<LL', pos_hash, 2 * len(bt)))
53+
pos_hash += 16 * len(bt)
54+
return
55+
56+
fp = file(f, "wb")
57+
write_cdb(fp)
58+
fp.close()
59+
return
60+
61+
if __name__ == "__main__":
62+
63+
bench = {}
64+
for i in xrange(0, 5*1000000, 5):
65+
bench[str(i)] = str(i)
66+
print bench['255']
67+
cdbmake("bench.cdb", bench)

examples/benchmark/benchmark.ino

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
uCDB benchmark sketch
3+
4+
Write file bench.cdb ([0..5000000] divisible by 5) on SD card. Connect to Ardino board.
5+
Compile and upload sketch. Open Serial Monitor.
6+
7+
Board: Arduino Uno
8+
SD card: SDHC 7.31Gb FAT32, sectorsPerCluster - 64
9+
SD chip select pin: 10
10+
Arduino IDE Serial Monitors settings: 9600 baud, no line ending.
11+
12+
Created by Ioulianos Kakoulidis, 2021.
13+
Released into the public domain.
14+
*/
15+
16+
#include "uCDB.h"
17+
18+
void setup() {
19+
Serial.begin(9600);
20+
while (!Serial) {
21+
;
22+
}
23+
24+
if (!SD.begin(10)) {
25+
Serial.println("SD card initialization failed!");
26+
while (true) {
27+
;
28+
}
29+
}
30+
}
31+
32+
void loop() {
33+
uCDB ucdb;
34+
char str[16];
35+
long key;
36+
unsigned long startMillis;
37+
cdbResult rt;
38+
39+
Serial.println("Press any key to start test");
40+
while (!Serial.available()) {
41+
;
42+
}
43+
44+
if (ucdb.open("bench.cdb") != CDB_OK) {
45+
Serial.print("Invalid CDB: ");
46+
Serial.println("bench.cdb");
47+
return;
48+
}
49+
50+
Serial.println("Querying 1000 random keys from interval [0..5000000)...");
51+
startMillis = millis();
52+
for (int i = 0; i < 1000; ++i) {
53+
key = random(5000000);
54+
sprintf(str, "%ld", key);
55+
rt = ucdb.findKey(str, strlen(str));
56+
if (key%5) {
57+
if (rt != KEY_NOT_FOUND) {
58+
Serial.print("Error: ");
59+
Serial.println(key);
60+
break;
61+
}
62+
}
63+
else {
64+
if (rt != KEY_FOUND) {
65+
Serial.print("Error: ");
66+
Serial.println(key);
67+
break;
68+
}
69+
}
70+
}
71+
Serial.print("Query millis: ");
72+
Serial.println(millis() - startMillis);
73+
74+
Serial.println("Querying 1000 random keys from interval [-5000000,0)...");
75+
startMillis = millis();
76+
for (int i = 0; i < 1000; ++i) {
77+
key = random(-5000000, 0);
78+
sprintf(str, "%ld", key);
79+
rt = ucdb.findKey(str, strlen(str));
80+
if (rt != KEY_NOT_FOUND) {
81+
Serial.print("Error: ");
82+
Serial.println(str);
83+
break;
84+
}
85+
}
86+
Serial.print("Query millis: ");
87+
Serial.println(millis() - startMillis);
88+
89+
Serial.println("Querying 1000 random keys with findNextValue() from interval [0..5000000)...");
90+
startMillis = millis();
91+
for (int i = 0; i < 1000; ++i) {
92+
key = random(5000000);
93+
sprintf(str, "%ld", key);
94+
rt = ucdb.findKey(str, strlen(str));
95+
if (key%5) {
96+
if (rt != KEY_NOT_FOUND) {
97+
Serial.print("Error: ");
98+
Serial.println(key);
99+
break;
100+
}
101+
}
102+
else {
103+
if (rt != KEY_FOUND) {
104+
Serial.print("Error: ");
105+
Serial.println(key);
106+
break;
107+
}
108+
}
109+
rt = ucdb.findNextValue();
110+
if (rt != KEY_NOT_FOUND) {
111+
Serial.print("Error: ");
112+
Serial.println(key);
113+
break;
114+
}
115+
}
116+
Serial.print("Query millis: ");
117+
Serial.println(millis() - startMillis);
118+
119+
Serial.println("Querying 1000 random keys with findNextValue() from interval [-5000000,0)...");
120+
startMillis = millis();
121+
for (int i = 0; i < 1000; ++i) {
122+
key = random(-5000000, 0);
123+
sprintf(str, "%ld", key);
124+
rt = ucdb.findKey(str, strlen(str));
125+
if (rt != KEY_NOT_FOUND) {
126+
Serial.print("Error: ");
127+
Serial.println(str);
128+
break;
129+
}
130+
rt = ucdb.findNextValue();
131+
if (rt != KEY_NOT_FOUND) {
132+
Serial.print("Error: ");
133+
Serial.println(key);
134+
break;
135+
}
136+
}
137+
Serial.print("Query millis: ");
138+
Serial.println(millis() - startMillis);
139+
140+
141+
ucdb.close();
142+
while (Serial.available()) {
143+
Serial.read();
144+
}
145+
}

examples/benchmark/benchmark.png

18.4 KB
Loading

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=uCDB
2-
version=0.4.1
2+
version=0.4.2
33
author=Ioulianos Kakoulidis
44
maintainer=Ioulianos Kakoulidis <ioulianos.kakoulidis@hotmail.com>
55
sentence=API for querying Constant DataBase file store.

src/uCDB.cpp

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616
static unsigned long unpack(const byte *buff);
1717

1818
uCDB::uCDB() {
19+
zero();
1920
state = CDB_CLOSED;
2021
}
2122

2223
cdbResult uCDB::open(const char *fileName, unsigned long (*userHashFunc)(const void *key, unsigned long keyLen)) {
2324
unsigned long htPos;
2425
unsigned long htSlotsNum;
2526
byte buff[CDB_DESCRIPTOR_SIZE];
26-
27+
28+
zero();
2729
cdb.close(); // Close previously opened CDB file
2830

2931
if (!SD.exists(fileName)) {
@@ -56,10 +58,10 @@ cdbResult uCDB::open(const char *fileName, unsigned long (*userHashFunc)(const v
5658
continue; // Empty hash table
5759
}
5860
if ((htPos < CDB_HEADER_SIZE) || (htPos > cdb.size())) {
59-
return (state = CDB_ERROR);
61+
return (state = CDB_ERROR); // Critical CDB format or data integrity error
6062
}
6163
if (((cdb.size() - htPos) >> 3) < htSlotsNum) {
62-
return (state = CDB_ERROR);
64+
return (state = CDB_ERROR); // Critical CDB format or data integrity error
6365
}
6466

6567
// Adjust data end position and total slots number
@@ -69,12 +71,12 @@ cdbResult uCDB::open(const char *fileName, unsigned long (*userHashFunc)(const v
6971
slotsNum += htSlotsNum;
7072

7173
if (((cdb.size() - dataEndPos) >> 3) < slotsNum) {
72-
return (state = CDB_ERROR);
74+
return (state = CDB_ERROR); // Critical CDB format or data integrity error
7375
}
7476
}
7577
// Check total
7678
if ((cdb.size() - dataEndPos) != 8 * slotsNum){
77-
return (state = CDB_ERROR);
79+
return (state = CDB_ERROR); // Critical CDB format or data integrity error
7880
}
7981

8082
hashFunc = userHashFunc;
@@ -84,11 +86,11 @@ cdbResult uCDB::open(const char *fileName, unsigned long (*userHashFunc)(const v
8486
cdbResult uCDB::findKey(const void *key, unsigned long keyLen) {
8587
byte buff[CDB_DESCRIPTOR_SIZE];
8688

89+
zero();
8790
// Check CDB state
8891
switch (state) {
8992
case CDB_CLOSED:
9093
case CDB_NOT_FOUND:
91-
case FILE_ERROR:
9294
case CDB_ERROR:
9395
return state;
9496
default:
@@ -114,42 +116,42 @@ cdbResult uCDB::findKey(const void *key, unsigned long keyLen) {
114116

115117
cdbResult uCDB::findNextValue() {
116118
byte buff[CDB_BUFF_SIZE];
119+
bool rd;
117120

118121
// Check CDB state
119122
switch (state) {
120123
case CDB_CLOSED:
121124
case CDB_NOT_FOUND:
122-
case FILE_ERROR:
123125
case CDB_ERROR:
124126
return state;
125127
default:
126128
;
127129
}
128130

129131
while (slotsToScan) {
130-
if (!readDescriptor(buff, nextSlotPos)) {
131-
return (state = FILE_ERROR);
132-
}
133-
132+
rd = readDescriptor(buff, nextSlotPos);
134133
// Adjust slotsToScan and next slot position
135134
--slotsToScan;
136135
nextSlotPos += CDB_DESCRIPTOR_SIZE;
137136
if (nextSlotPos == hashTabEndPos) {
138137
nextSlotPos = hashTabStartPos;
139138
}
139+
140+
if (!rd) {
141+
return (state = FILE_ERROR);
142+
}
140143

141144
slotHash = unpack(buff);
142145
dataPos = unpack(buff + 4);
143146

144147
if (!dataPos) {
145-
slotsToScan = 0;
146-
nextSlotPos = 0;
148+
zero();
147149
return (state = KEY_NOT_FOUND);
148150
}
149151

150152
// Check data position
151153
if ((dataPos < CDB_HEADER_SIZE) || (dataPos > (dataEndPos - CDB_DESCRIPTOR_SIZE))) {
152-
return (state = CDB_ERROR);
154+
return (state = CDB_ERROR); // Critical CDB format or data integrity error
153155
}
154156

155157
if (slotHash == keyHash) {
@@ -163,24 +165,29 @@ cdbResult uCDB::findNextValue() {
163165
//> key, value length check
164166
unsigned long t = dataPos + CDB_DESCRIPTOR_SIZE;
165167
if ((dataEndPos - t) < dataKeyLen) {
166-
return (state = CDB_ERROR);
168+
return (state = CDB_ERROR); // Critical CDB format or data integrity error
167169
}
168170
t += dataKeyLen;
169171
if ((dataEndPos - t) < dataValueLen) {
170-
return (state = CDB_ERROR);
172+
return (state = CDB_ERROR); // Critical CDB format or data integrity error
171173
}
172174
//< key, value length check
173-
174-
valueBytesAvail = dataValueLen;
175175

176-
if ((keyLen_ == dataKeyLen) && (compareKey() == KEY_FOUND)) {
177-
return (state = KEY_FOUND);
176+
if (keyLen_ == dataKeyLen) {
177+
switch (compareKey()) {
178+
case KEY_FOUND:
179+
valueBytesAvail = dataValueLen;
180+
return (state = KEY_FOUND);
181+
case FILE_ERROR:
182+
return (state = FILE_ERROR);
183+
default:
184+
;
185+
}
178186
}
179187
}
180188
}
181189

182-
slotsToScan = 0;
183-
nextSlotPos = 0;
190+
zero(); // ?
184191

185192
return (state = KEY_NOT_FOUND);
186193
}
@@ -213,6 +220,7 @@ int uCDB::readValue(void *buff, unsigned int byteNum) {
213220
}
214221

215222
cdbResult uCDB::close() {
223+
zero();
216224
cdb.close();
217225
return (state = CDB_CLOSED);
218226
}
@@ -264,6 +272,11 @@ bool uCDB::readDescriptor(byte *buff, unsigned long pos) {
264272
}
265273
}
266274

275+
void uCDB::zero() {
276+
slotsToScan = 0;
277+
nextSlotPos = 0;
278+
}
279+
267280
unsigned long DJBHash(const void *key, unsigned long keyLen) {
268281
unsigned long h = 5381;
269282
const byte *curr = static_cast<const byte *>(key);

0 commit comments

Comments
 (0)