y16t/lib/db.c
2023-01-04 09:59:14 +01:00

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);
}