use pread/pwrite instead of stdio API

This commit is contained in:
Alain Zscheile 2023-01-03 07:55:00 +01:00
parent ace7232d93
commit 8fc79dd372
6 changed files with 152 additions and 108 deletions

135
idx.c
View file

@ -3,68 +3,63 @@
#include "y16t_internal.h"
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
static __attribute__((pure))
uint32_t y16t_table_at(const uint8_t x, const uint8_t y)
uint32_t y16t_table_at(const y16t_idx_t idx, const uint8_t x, const uint8_t y)
{
return y16t_hilbert_xy2d(1 << 16, x, y) << 2;
return (idx.offset << 10)
| (y16t_hilbert_xy2d(1 << 16, x, y) << 2);
}
static __attribute__((pure))
int y16t_idx_hret(const int tmp)
{
if(tmp == 4) {
return 0;
} else if(tmp < 0) {
return tmp;
} else {
return -EIO;
}
}
int y16t_idx_lookup(
FILE *fh,
uint8_t x,
uint8_t y,
uint32_t *result
y16t_idx_t idx,
uint8_t x,
uint8_t y,
uint32_t *result
) {
const long key = y16t_table_at(x, y);
if(key && fseek(fh, key, SEEK_CUR) == -1)
return -EIO;
if(fread(result, 4, 1, fh) != 1)
return -EIO;
*result = ntohl(*result);
if(fseek(fh, -key - 4, SEEK_CUR) == -1)
return -EIO;
return 0;
const off_t key = y16t_table_at(idx, x, y);
const int tmp = y16t_idx_hret(y16t_pread_all(idx.fd, result, 4, key));
if(tmp >= 0) *result = ntohl(*result);
return tmp;
}
int y16t_idx_update(
FILE *fh,
y16t_idx_t idx,
const uint8_t x,
const uint8_t y,
const uint32_t newval
) {
const long key = y16t_table_at(x, y);
const off_t key = y16t_table_at(idx, x, y);
const uint32_t odval = htonl(newval);
if(key && fseek(fh, key, SEEK_CUR) == -1)
return -EIO;
if(fwrite(&odval, 4, 1, fh) != 1)
return -EIO;
if(fseek(fh, -key - 4, SEEK_CUR) == -1)
return -EIO;
return 0;
return y16t_idx_hret(y16t_pwrite_all(idx.fd, &odval, 4, key));
}
int y16t_idx_get_or_insert(
FILE *fh,
y16t_idx_t idx,
const uint8_t x,
const uint8_t y,
uint32_t *value,
uint32_t (*palloc)(void*),
void *context
uint32_t *value,
uint32_t (*palloc)(void*),
void *context
) {
const long key = y16t_table_at(x, y);
if(key && fseek(fh, key, SEEK_CUR) == -1)
return -EIO;
const long key = y16t_table_at(idx, x, y);
uint32_t value_tmp = 0;
if(fread(&value_tmp, 4, 1, fh) != 1)
return -EIO;
int tmp = y16t_idx_hret(y16t_pread_all(idx.fd, &value_tmp, 4, key));
if(tmp < 0)
return tmp;
if(!value_tmp) {
// allocate new entry
@ -72,78 +67,50 @@ int y16t_idx_get_or_insert(
if(!value_tmp)
return -ENOMEM;
value_tmp = htonl(value_tmp);
if(fseek(fh, -4, SEEK_CUR) == -1)
return -EIO;
if(fwrite(&value_tmp, 4, 1, fh) != 1)
return -EIO;
tmp = y16t_idx_hret(y16t_pwrite_all(idx.fd, &value_tmp, 4, key));
}
*value = ntohl(value_tmp);
if(fseek(fh, -key - 4, SEEK_CUR) == -1)
return -EIO;
return 0;
return tmp;
}
static int y16t_idx_foreach_inner(
FILE *fh,
long *offset,
y16t_idx_t idx,
uint8_t x,
uint8_t y,
int (*callback)(uint32_t, void*),
void *context
) {
const uint32_t key = y16t_table_at(x, y);
const long delta = ((long)key) - *offset;
if(delta && fseek(fh, delta, SEEK_CUR) == -1)
return -EIO;
*offset = key + 4;
uint32_t value = 0;
if(fread(&value, 4, 1, fh) != 1)
return -EIO;
const int tmp = callback(ntohl(value), context);
if(tmp) {
fseek(fh, -*offset, SEEK_CUR);
*offset = 0;
}
return tmp;
int tmp = y16t_idx_lookup(idx, x, y, &value);
if(tmp < 0) return tmp;
return callback(ntohl(value), context);
}
int y16t_idx_foreach_x(
FILE *fh,
uint8_t y,
int (*callback)(uint32_t, void*),
void *context
y16t_idx_t idx,
uint8_t y,
int (*callback)(uint32_t, void*),
void *context
) {
long offset = 0;
for (uint16_t x = 0; x < 0xff; ++x) {
const int tmp = y16t_idx_foreach_inner(fh, &offset, x, y, callback, context);
const int tmp = y16t_idx_foreach_inner(idx, x, y, callback, context);
if(tmp) return tmp;
}
if(offset && fseek(fh, -offset, SEEK_CUR) == -1)
return -EIO;
return 0;
}
int y16t_idx_foreach_y(
FILE *fh,
uint8_t x,
int (*callback)(uint32_t, void*),
void *context
y16t_idx_t idx,
uint8_t x,
int (*callback)(uint32_t, void*),
void *context
) {
long offset = 0;
for (uint16_t y = 0; y < 0xff; ++y) {
const int tmp = y16t_idx_foreach_inner(fh, &offset, x, y, callback, context);
const int tmp = y16t_idx_foreach_inner(idx, x, y, callback, context);
if(tmp) return tmp;
}
if(offset && fseek(fh, -offset, SEEK_CUR) == -1)
return -EIO;
return 0;
}

View file

@ -6,17 +6,26 @@ project('y16t 16bit-field quad tree library', 'c',
install_headers('y16t.h')
c_base_args = [
'-fno-plt',
'-fno-unwind-tables',
'-fno-exceptions',
'-Werror=return-type',
'-Werror=implicit-function-declaration',
'-Werror=incompatible-pointer-types-discards-qualifiers',
'-D_XOPEN_SOURCE=500']
liby16t = shared_library('y16t',
files('hilbert.c', 'idx.c'),
files('hilbert.c', 'idx.c', 'pall.c'),
version : '0.0.0',
c_args : ['-fno-plt', '-fno-unwind-tables', '-fno-exceptions', '-Werror=return-type'],
c_args : [c_base_args],
include_directories : include_directories('.'),
install : true)
executable('y16t-printall',
files('y16t_printall.c'),
link_with : [liby16t],
c_args : ['-fno-plt', '-fno-unwind-tables', '-fno-exceptions', '-Werror=return-type'],
c_args : [c_base_args],
include_directories : include_directories('.'),
install : true
)

56
pall.c Normal file
View file

@ -0,0 +1,56 @@
#include "y16t_internal.h"
#include <errno.h>
#include <unistd.h>
__attribute__((nonnull))
static ssize_t y16t_pall_hret(const ssize_t tmp, size_t *dnb)
{
if(tmp > 0) {
*dnb += tmp;
return tmp;
} else if(!tmp) {
return -EIO;
} else {
return -errno;
}
}
ssize_t y16t_pread_all(const int fd, void *buf, size_t nbyte, off_t offset)
{
size_t dnb = 0;
while(nbyte) {
const ssize_t tmp = y16t_pall_hret(pread(
fd,
buf + dnb,
nbyte - dnb,
offset + dnb), &dnb);
switch(tmp) {
case -EINTR:
continue;
default:
if(tmp > 0) continue;
return tmp;
}
}
return (ssize_t)dnb;
}
ssize_t y16t_pwrite_all(const int fd, const void *buf, size_t nbyte, off_t offset)
{
size_t dnb = 0;
while(nbyte) {
const ssize_t tmp = y16t_pall_hret(pwrite(
fd,
buf + dnb,
nbyte - dnb,
offset + dnb), &dnb);
switch(tmp) {
case -EINTR:
continue;
default:
if(tmp > 0) continue;
return tmp;
}
}
return (ssize_t)dnb;
}

36
y16t.h
View file

@ -2,7 +2,12 @@
#pragma once
#include <inttypes.h>
#include <stddef.h>
#include <stdio.h>
typedef struct {
int fd;
// offset is in 1KiB units
size_t offset;
} y16t_idx_t;
// try to lookup the given coordinates,
// and return the corresponding location via `result`.
@ -10,24 +15,23 @@
// returns a negative errno number in case of failure
__attribute__((nonnull))
int y16t_idx_lookup(
FILE *fh,
y16t_idx_t idx,
uint8_t x,
uint8_t y,
uint32_t *result
);
// update a table entry.
__attribute__((nonnull))
int y16t_idx_update(
FILE *fh,
uint8_t x,
uint8_t y,
uint32_t newval
y16t_idx_t idx,
uint8_t x,
uint8_t y,
uint32_t newval
);
// insert a table entry if it doesn't already exist
int y16t_idx_get_or_insert(
FILE *fh,
y16t_idx_t idx,
uint8_t x,
uint8_t y,
uint32_t *value,
@ -37,15 +41,15 @@ int y16t_idx_get_or_insert(
// iterate over columns or rows
int y16t_idx_foreach_x(
FILE *fh,
uint8_t y,
int (*callback)(uint32_t, void*),
void *context
y16t_idx_t idx,
uint8_t y,
int (*callback)(uint32_t, void*),
void *context
);
int y16t_idx_foreach_y(
FILE *fh,
uint8_t χ,
int (*callback)(uint32_t, void*),
void *context
y16t_idx_t idx,
uint8_t χ,
int (*callback)(uint32_t, void*),
void *context
);

View file

@ -1,5 +1,6 @@
// SPDX-License-Identifier: ISC
#pragma once
#include <sys/types.h>
#include <inttypes.h>
// conversion between hilbert curve distance and x,y values
@ -8,3 +9,8 @@ __attribute__((pure))
uint32_t y16t_hilbert_xy2d(uint32_t n, uint32_t x, uint32_t y);
void y16t_hilbert_d2xy(uint32_t n, uint32_t d, uint32_t *x, uint32_t *y);
// handling of resumption of pread/pwrite calls
ssize_t y16t_pread_all(int fd, void *buf, size_t nbyte, off_t offset);
ssize_t y16t_pwrite_all(int fd, const void *buf, size_t nbyte, off_t offset);

View file

@ -1,6 +1,7 @@
#include "y16t.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
int printall_fecb(uint32_t x, void* ctx)
{
@ -15,18 +16,19 @@ int main(int argc, char *argv[])
return -1;
}
FILE *fh = fopen(argv[1], "r");
if(!fh) {
int fd = open(argv[1], O_RDONLY);
if(fd < 0) {
perror("open");
fprintf(stderr, "ERROR: unable to open file\n");
return -1;
}
uint8_t value = atoi(argv[3]);
const y16t_idx_t idx = { fd, 0 };
switch(argv[2][0]) {
case 'x': return y16t_idx_foreach_x(fh, value, printall_fecb, 0);
case 'y': return y16t_idx_foreach_y(fh, value, printall_fecb, 0);
case 'x': return y16t_idx_foreach_x(idx, value, printall_fecb, 0);
case 'y': return y16t_idx_foreach_y(idx, value, printall_fecb, 0);
default: return -1;
}
}