252 lines
6 KiB
C
252 lines
6 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;
|
|
|
|
__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);
|
|
int tmp = posix_fallocate(fd, eoffs, 1 << 18);
|
|
if(tmp < 0) {
|
|
errno = tmp;
|
|
return 0;
|
|
} else return eoffs >> 10;
|
|
}
|
|
|
|
__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;
|
|
int tmp = posix_fallocate(fd, eoffs, 1 << 12);
|
|
if(tmp < 0) {
|
|
errno = tmp;
|
|
return 0;
|
|
} else return eoffs >> 10;
|
|
}
|
|
|
|
// @param bufexp must point to 44 valid bytes
|
|
__attribute__((nonnull))
|
|
static int y16t_db_intern_pgsearch(
|
|
const int fd,
|
|
off_t start_offset,
|
|
uint8_t bufexp[],
|
|
uint32_t *i_
|
|
) {
|
|
uint8_t buf[4096] = {0};
|
|
const uint8_t zeros[44] = {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 = ((off_t)offset) << 10;
|
|
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, ((off_t)offset) << 10, bufexp, &i);
|
|
}
|
|
|
|
// iterate over the database
|
|
typedef struct {
|
|
y16t_db_t db;
|
|
const uint8_t *xy;
|
|
int (*callback)(const uint8_t*, const uint8_t*, void*);
|
|
void *context;
|
|
} y16t_db_fectx_t;
|
|
|
|
static int y16t_db_foreach_x3(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 uint8_t zeros[44] = {0};
|
|
const off_t start_offset = ((off_t)offset) << 10;
|
|
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) {
|
|
const int tmp2 = context->callback(&buf[i], &buf[i + 28], context->context);
|
|
if(tmp2) return tmp2;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int y16t_db_foreach_y3(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 uint8_t zeros[44] = {0};
|
|
const off_t start_offset = ((off_t)offset) << 10;
|
|
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) {
|
|
const int tmp2 = context->callback(&buf[i + 14], &buf[i + 28], context->context);
|
|
if(tmp2) return tmp2;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int y16t_db_foreach_x2(uint32_t offset, void *context_) {
|
|
const y16t_db_fectx_t *context = context_;
|
|
if(!offset) return 0;
|
|
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(uint32_t offset, void *context_) {
|
|
const y16t_db_fectx_t *context = context_;
|
|
if(!offset) return 0;
|
|
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, 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, callback, context };
|
|
const y16t_idx_t idx = { db, 0 };
|
|
return y16t_idx_foreach_y(idx, x[0], y16t_db_foreach_y2, (void*) &fectx);
|
|
}
|