264 lines
6.4 KiB
C
264 lines
6.4 KiB
C
// SPDX-License-Identifier: ISC
|
|
// database impl
|
|
#include "y16t_db.h"
|
|
#include "y16t_internal.h"
|
|
#include "y16t_idx.h"
|
|
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
|
|
typedef struct {
|
|
int fd;
|
|
} y16t_db_actx_t;
|
|
|
|
static const uint8_t zeros[44] = {0};
|
|
|
|
__attribute__((pure)) static off_t
|
|
y16t_db_offstr(const uint32_t offset) { return ((off_t)offset) << 12; }
|
|
|
|
__attribute__((pure)) static uint32_t
|
|
y16t_db_unoffstr(const off_t x) { return x >> 12; }
|
|
|
|
__attribute__((nonnull))
|
|
static uint32_t y16t_db_palloc(void * context_)
|
|
{
|
|
y16t_db_actx_t *context = context_;
|
|
const int fd = context->fd;
|
|
const off_t eoffs_orig = lseek(fd, 0, SEEK_END);
|
|
if(eoffs_orig == -1) return 0;
|
|
const off_t eoffs = (eoffs_orig >= (1 << 18)) ? eoffs_orig : (1 << 18);
|
|
return (-1 == ftruncate(fd, eoffs + (1 << 18)))
|
|
? 0
|
|
: y16t_db_unoffstr(eoffs);
|
|
}
|
|
|
|
__attribute__((nonnull))
|
|
static uint32_t y16t_db_palloc2(void * context_)
|
|
{
|
|
y16t_db_actx_t *context = context_;
|
|
const int fd = context->fd;
|
|
const off_t eoffs = lseek(fd, 0, SEEK_END);
|
|
if(eoffs == -1) return 0;
|
|
return (-1 == ftruncate(fd, eoffs + y16t_db_offstr(1)))
|
|
? 0
|
|
: y16t_db_unoffstr(eoffs);
|
|
}
|
|
|
|
// @param bufexp must point to 44 valid bytes
|
|
__attribute__((nonnull))
|
|
static int y16t_db_intern_pgsearch(
|
|
const int fd,
|
|
const off_t start_offset,
|
|
const uint8_t bufexp[],
|
|
uint32_t *i_
|
|
) {
|
|
uint8_t buf[4096] = {0};
|
|
ssize_t tmp = y16t_pread_all(fd, buf, sizeof(buf), start_offset);
|
|
if(tmp < 0) return (int)tmp;
|
|
|
|
*i_ = 0;
|
|
uint32_t i;
|
|
for(i = 0; i < sizeof(buf); i += 44) {
|
|
if(memcmp(&buf[i], zeros, 44) == 0)
|
|
break;
|
|
if(memcmp(&buf[i], bufexp, 44) == 0) {
|
|
*i_ = i;
|
|
return 1;
|
|
}
|
|
}
|
|
*i_ = i;
|
|
return 0;
|
|
}
|
|
|
|
// inserts a database entry
|
|
// x, y, z should point to arrays of 16 bytes each
|
|
int y16t_db_insert(
|
|
y16t_db_t db,
|
|
const uint8_t *x,
|
|
const uint8_t *y,
|
|
const uint8_t *z
|
|
) {
|
|
// first table
|
|
uint32_t offset = 0;
|
|
int tmp = 0;
|
|
y16t_db_actx_t actx = { db };
|
|
{
|
|
const y16t_idx_t idx = { db, 0 };
|
|
tmp = y16t_idx_get_or_insert(
|
|
idx, x[0], y[0], &offset,
|
|
y16t_db_palloc, (void*)&actx
|
|
);
|
|
if(tmp < 0) return tmp;
|
|
}
|
|
|
|
// second table
|
|
{
|
|
const y16t_idx_t idx = { db, offset };
|
|
tmp = y16t_idx_get_or_insert(
|
|
idx, x[1], y[1], &offset,
|
|
y16t_db_palloc2, (void*)&actx
|
|
);
|
|
if(tmp < 0) return tmp;
|
|
}
|
|
|
|
// prepare entry
|
|
uint8_t bufexp[44];
|
|
memcpy(bufexp, &x[2], 14);
|
|
memcpy(bufexp + 14, &y[2], 14);
|
|
memcpy(bufexp + 28, &z, 16);
|
|
|
|
// sequential data, read complete page
|
|
const off_t start_offset = y16t_db_offstr(offset);
|
|
uint32_t i;
|
|
tmp = y16t_db_intern_pgsearch(db, start_offset, bufexp, &i);
|
|
switch(tmp) {
|
|
case 1:
|
|
return 0;
|
|
case 0:
|
|
if(i >= 4052) return -ENOMEM;
|
|
return y16t_pwrite_all(db, bufexp, sizeof(bufexp), start_offset + i);
|
|
default:
|
|
return tmp;
|
|
}
|
|
}
|
|
|
|
// lookup a database entry
|
|
// @return 1 means found, 0 means not found, negative is a negated errno value
|
|
// x, y, z should point to arrays of 16 bytes each
|
|
int y16t_db_lookup(
|
|
y16t_db_t db,
|
|
const uint8_t *x,
|
|
const uint8_t *y,
|
|
const uint8_t *z
|
|
) {
|
|
uint32_t offset = 0;
|
|
int tmp = 0;
|
|
|
|
// first table
|
|
y16t_idx_t idx = { db, 0 };
|
|
tmp = y16t_idx_lookup(idx, x[0], y[0], &offset);
|
|
if(tmp < 0) return tmp;
|
|
if(!offset) return 0;
|
|
|
|
// second table
|
|
idx.offset = offset;
|
|
tmp = y16t_idx_lookup(idx, x[1], y[1], &offset);
|
|
if(tmp < 0) return tmp;
|
|
if(!offset) return 0;
|
|
|
|
// prepare entry
|
|
uint8_t bufexp[44];
|
|
memcpy(bufexp, &x[2], 14);
|
|
memcpy(bufexp + 14, &y[2], 14);
|
|
memcpy(bufexp + 28, &z, 16);
|
|
|
|
// sequential data, read complete page
|
|
uint32_t i;
|
|
return y16t_db_intern_pgsearch(db, y16t_db_offstr(offset), bufexp, &i);
|
|
}
|
|
|
|
// iterate over the database
|
|
typedef struct {
|
|
y16t_db_t db;
|
|
const uint8_t *xy;
|
|
uint8_t oth;
|
|
int (*callback)(const uint8_t*, const uint8_t*, void*);
|
|
void *context;
|
|
} y16t_db_fectx_t;
|
|
|
|
static int y16t_db_foreach_x3(uint8_t x1, uint32_t offset, void *context_)
|
|
{
|
|
if(!offset) return 0;
|
|
const y16t_db_fectx_t *context = context_;
|
|
|
|
// sequential data, read complete page
|
|
uint8_t buf[4096] = {0};
|
|
const off_t start_offset = y16t_db_offstr(offset);
|
|
ssize_t tmp = y16t_pread_all(context->db, buf, sizeof(buf), start_offset);
|
|
if(tmp < 0) return (int)tmp;
|
|
|
|
uint32_t i;
|
|
const uint8_t *xyrest = &context->xy[2];
|
|
for(i = 0; i < sizeof(buf); i += 44) {
|
|
if(memcmp(&buf[i], zeros, 44) == 0)
|
|
break;
|
|
if(memcmp(&buf[i + 14], xyrest, 14) == 0) {
|
|
uint8_t x[16] = {0};
|
|
x[0] = context->oth;
|
|
x[1] = x1;
|
|
memcpy(&x[2], &buf[i], 14);
|
|
const int tmp2 = context->callback(x, &buf[i + 28], context->context);
|
|
if(tmp2) return tmp2;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int y16t_db_foreach_y3(uint8_t y1, uint32_t offset, void *context_)
|
|
{
|
|
if(!offset) return 0;
|
|
const y16t_db_fectx_t *context = context_;
|
|
|
|
// sequential data, read complete page
|
|
uint8_t buf[4096] = {0};
|
|
const off_t start_offset = y16t_db_offstr(offset);
|
|
ssize_t tmp = y16t_pread_all(context->db, buf, sizeof(buf), start_offset);
|
|
if(tmp < 0) return (int)tmp;
|
|
|
|
uint32_t i;
|
|
const uint8_t *xyrest = &context->xy[2];
|
|
for(i = 0; i < sizeof(buf); i += 44) {
|
|
if(memcmp(&buf[i], zeros, 44) == 0)
|
|
break;
|
|
if(memcmp(&buf[i], xyrest, 14) == 0) {
|
|
uint8_t y[16] = {0};
|
|
y[0] = context->oth;
|
|
y[1] = y1;
|
|
memcpy(&y[2], &buf[i + 14], 14);
|
|
const int tmp2 = context->callback(y, &buf[i + 28], context->context);
|
|
if(tmp2) return tmp2;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int y16t_db_foreach_x2(uint8_t x0, uint32_t offset, void *context_) {
|
|
y16t_db_fectx_t *context = context_;
|
|
if(!offset) return 0;
|
|
context->oth = x0;
|
|
const y16t_idx_t idx = { context->db, offset };
|
|
return y16t_idx_foreach_x(idx, context->xy[1],
|
|
y16t_db_foreach_x3, context_);
|
|
}
|
|
|
|
static int y16t_db_foreach_y2(uint8_t y0, uint32_t offset, void *context_) {
|
|
y16t_db_fectx_t *context = context_;
|
|
if(!offset) return 0;
|
|
context->oth = y0;
|
|
const y16t_idx_t idx = { context->db, offset };
|
|
return y16t_idx_foreach_y(idx, context->xy[1],
|
|
y16t_db_foreach_y3, context_);
|
|
}
|
|
|
|
int y16t_db_foreach_x(
|
|
y16t_db_t db, const uint8_t *y,
|
|
int (*callback)(const uint8_t*, const uint8_t*, void*),
|
|
void *context
|
|
) {
|
|
y16t_db_fectx_t fectx = { db, y, 0, callback, context };
|
|
const y16t_idx_t idx = { db, 0 };
|
|
return y16t_idx_foreach_x(idx, y[0], y16t_db_foreach_x2, (void*) &fectx);
|
|
}
|
|
|
|
int y16t_db_foreach_y(
|
|
y16t_db_t db, const uint8_t *x,
|
|
int (*callback)(const uint8_t*, const uint8_t*, void*),
|
|
void *context
|
|
) {
|
|
y16t_db_fectx_t fectx = { db, x, 0, callback, context };
|
|
const y16t_idx_t idx = { db, 0 };
|
|
return y16t_idx_foreach_y(idx, x[0], y16t_db_foreach_y2, (void*) &fectx);
|
|
}
|