Implement big-endian machines support
parent
8d56569dd5
commit
a6a8d43f91
|
@ -1,9 +1,57 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <endian.h>
|
||||
|
||||
/**
|
||||
* @file macro.h
|
||||
* @brief The macros used in the engine.
|
||||
*/
|
||||
|
||||
/** @brief Return `err` if `x` is null. */
|
||||
#define THROW_IF_NULL(x, err) if (!(x)) return (err)
|
||||
#define THROW_IF_NULL(x, err) if (!(x)) return (err)
|
||||
|
||||
/**
|
||||
* @def TO_LE(x)
|
||||
* @param x Integer value.
|
||||
* @brief Convert a value stored in memory to little-endian.
|
||||
* Passes the value if current architecture is little-endian.
|
||||
*/
|
||||
/**
|
||||
* @def FROM_LE(x)
|
||||
* @param x Integer value.
|
||||
* @brief Convert a little-endian value to architecture endian.
|
||||
* Passes the value if current architecture is little-endian.
|
||||
*/
|
||||
/**
|
||||
* @def REASSIGN_FROM_LE(x)
|
||||
* @param x Non-const integer variable.
|
||||
* @brief Reassign a variable with converted stored value.
|
||||
* Does nothing if current architecture is little-endian.
|
||||
*/
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define TO_LE(x) _Generic((x), \
|
||||
uint16_t: htole16, \
|
||||
int16_t: htole16, \
|
||||
uint32_t: htole32, \
|
||||
int32_t: htole32, \
|
||||
uint64_t: htole64, \
|
||||
int64_t: htole64, \
|
||||
)(x)
|
||||
|
||||
#define FROM_LE(x) _Generic((x), \
|
||||
uint16_t: le16toh, \
|
||||
int16_t: le16toh, \
|
||||
uint32_t: le32toh, \
|
||||
int32_t: le32toh, \
|
||||
uint64_t: le64toh, \
|
||||
int64_t: le64toh, \
|
||||
)(x)
|
||||
|
||||
#define REASSIGN_FROM_LE(x) (x) = FROM_LE((x))
|
||||
#else
|
||||
#define TO_LE(x) (x)
|
||||
#define FROM_LE(x) (x)
|
||||
#define REASSIGN_FROM_LE(x)
|
||||
#endif
|
59
src/ydb.c
59
src/ydb.c
|
@ -83,19 +83,25 @@ void ydb_terminate_instance(YDB_Engine *instance) {
|
|||
static YDB_Error __ydb_read_page(YDB_Engine *inst) {
|
||||
THROW_IF_NULL(inst, YDB_ERR_INSTANCE_NOT_INITIALIZED);
|
||||
|
||||
// Seek to current page
|
||||
fseek(inst->fd, inst->curr_page_offset, SEEK_SET);
|
||||
|
||||
// Read page data
|
||||
char p_data[YDB_TABLE_PAGE_SIZE];
|
||||
size_t bytes_read = fread(p_data, 1, YDB_TABLE_PAGE_SIZE, inst->fd);
|
||||
// Throw error if failed to read exactly a page size.
|
||||
if (bytes_read != YDB_TABLE_PAGE_SIZE) {
|
||||
return YDB_ERR_TABLE_DATA_CORRUPTED;
|
||||
}
|
||||
|
||||
// Read page flags, next page offset and row count
|
||||
YDB_Flags page_flags = p_data[0];
|
||||
YDB_Offset next;
|
||||
YDB_PageSize row_count;
|
||||
memcpy(&next, p_data + v0_page_offsets.next_page_offset, sizeof(next));
|
||||
REASSIGN_FROM_LE(next);
|
||||
memcpy(&row_count, p_data + v0_page_offsets.row_count, sizeof(row_count));
|
||||
REASSIGN_FROM_LE(row_count);
|
||||
|
||||
const YDB_PageSize meta_size = v0_page_offsets.meta_end;
|
||||
const YDB_PageSize data_size = YDB_TABLE_PAGE_SIZE - meta_size;
|
||||
|
@ -116,27 +122,29 @@ static YDB_Error __ydb_read_page(YDB_Engine *inst) {
|
|||
// Moves file position to allocated block.
|
||||
// Also changes last_free_page_offset.
|
||||
static YDB_Offset __ydb_allocate_page_and_seek(YDB_Engine *inst) {
|
||||
// TODO change signature of the function. It should return an error code, I think.
|
||||
YDB_Offset result = 0;
|
||||
// If no free pages in the table, then...
|
||||
if (inst->last_free_page_offset == 0) {
|
||||
// Return the end of the file where a new page will be allocated
|
||||
fseek(inst->fd, 0, SEEK_END);
|
||||
result = ftell(inst->fd);
|
||||
|
||||
// Write next page offset in the previous page
|
||||
fseek(inst->fd, inst->last_page_offset + v0_page_offsets.next_page_offset, SEEK_SET); // Skip page flag
|
||||
fwrite(&result, sizeof(result), 1, inst->fd);
|
||||
YDB_Offset allocated_page_offset_le = TO_LE(result);
|
||||
|
||||
// Allocate an empty chunk
|
||||
fseek(inst->fd, 0, SEEK_END);
|
||||
char* new_page_data = calloc(1, YDB_TABLE_PAGE_SIZE);
|
||||
fwrite(new_page_data, YDB_TABLE_PAGE_SIZE, 1, inst->fd);
|
||||
free(new_page_data);
|
||||
// TODO throw error on fail
|
||||
|
||||
// Write next page offset in the previous page
|
||||
fseek(inst->fd, inst->last_page_offset + v0_page_offsets.next_page_offset, SEEK_SET); // Skip page flag
|
||||
fwrite(&allocated_page_offset_le, sizeof(YDB_Offset), 1, inst->fd);
|
||||
|
||||
// Write last page offset
|
||||
inst->last_page_offset = result;
|
||||
fseek(inst->fd, v0_offsets.last_page_offset, SEEK_SET);
|
||||
fwrite(&inst->last_page_offset, sizeof(YDB_Offset), 1, inst->fd);
|
||||
fwrite(&allocated_page_offset_le, sizeof(YDB_Offset), 1, inst->fd);
|
||||
fflush(inst->fd);
|
||||
} else {
|
||||
// Return last free page offset
|
||||
|
@ -144,7 +152,8 @@ static YDB_Offset __ydb_allocate_page_and_seek(YDB_Engine *inst) {
|
|||
|
||||
// Read last free page offset after allocation
|
||||
fseek(inst->fd, result + v0_page_offsets.next_page_offset, SEEK_SET); // Skip flag
|
||||
fread(&(inst->last_free_page_offset), sizeof(YDB_Offset), 1, inst->fd);
|
||||
fread(&inst->last_free_page_offset, sizeof(YDB_Offset), 1, inst->fd);
|
||||
REASSIGN_FROM_LE(inst->last_free_page_offset);
|
||||
fseek(inst->fd, -(long)(sizeof(YDB_Offset) + 1), SEEK_CUR);
|
||||
|
||||
// Rewrite page header
|
||||
|
@ -155,7 +164,8 @@ static YDB_Offset __ydb_allocate_page_and_seek(YDB_Engine *inst) {
|
|||
|
||||
// Write last free page offset after allocation in file
|
||||
fseek(inst->fd, v0_offsets.last_free_page_offset, SEEK_SET);
|
||||
fwrite(&(inst->last_free_page_offset), sizeof(YDB_Offset), 1, inst->fd);
|
||||
YDB_Offset lfp_offset_le = TO_LE(inst->last_free_page_offset);
|
||||
fwrite(&lfp_offset_le, sizeof(YDB_Offset), 1, inst->fd);
|
||||
}
|
||||
fflush(inst->fd);
|
||||
fseek(inst->fd, result, SEEK_SET);
|
||||
|
@ -201,9 +211,12 @@ YDB_Error ydb_load_table(YDB_Engine *instance, const char *path) {
|
|||
return YDB_ERR_TABLE_DATA_CORRUPTED;
|
||||
}
|
||||
|
||||
fread(&(instance->first_page_offset), sizeof(YDB_Offset), 1, instance->fd);
|
||||
fread(&(instance->last_page_offset), sizeof(YDB_Offset), 1, instance->fd);
|
||||
fread(&(instance->last_free_page_offset), sizeof(YDB_Offset), 1, instance->fd);
|
||||
fread(&instance->first_page_offset, sizeof(YDB_Offset), 1, instance->fd);
|
||||
REASSIGN_FROM_LE(instance->first_page_offset);
|
||||
fread(&instance->last_page_offset, sizeof(YDB_Offset), 1, instance->fd);
|
||||
REASSIGN_FROM_LE(instance->last_page_offset);
|
||||
fread(&instance->last_free_page_offset, sizeof(YDB_Offset), 1, instance->fd);
|
||||
REASSIGN_FROM_LE(instance->last_free_page_offset);
|
||||
// TODO check offsets
|
||||
|
||||
instance->in_use = -1; // unsigned value overflow to fill all the bits
|
||||
|
@ -252,7 +265,6 @@ YDB_Error ydb_create_table(YDB_Engine *instance, const char *path) {
|
|||
|
||||
FILE *f = fopen(path, "wb");
|
||||
|
||||
// TODO test on other byte ordered archs
|
||||
char tpl[] = YDB_TABLE_FILE_SIGN
|
||||
"\x00\x02"
|
||||
"\x1E\x00\x00\x00\x00\x00\x00\x00"
|
||||
|
@ -282,7 +294,7 @@ YDB_Error ydb_next_page(YDB_Engine *instance) {
|
|||
|
||||
instance->prev_page_offset = instance->curr_page_offset;
|
||||
instance->curr_page_offset = instance->next_page_offset;
|
||||
++(instance->current_page_index);
|
||||
++instance->current_page_index;
|
||||
return __ydb_read_page(instance);
|
||||
}
|
||||
|
||||
|
@ -344,9 +356,11 @@ YDB_Error ydb_append_page(YDB_Engine* instance, YDB_TablePage* page) {
|
|||
return YDB_ERR_UNKNOWN; // FIXME
|
||||
}
|
||||
|
||||
YDB_PageSize rc_le = TO_LE(rc);
|
||||
|
||||
fwrite(&f, sizeof(f), 1, instance->fd);
|
||||
fwrite(&next, sizeof(next), 1, instance->fd);
|
||||
fwrite(&rc, sizeof(rc), 1, instance->fd);
|
||||
fwrite(&rc_le, sizeof(rc), 1, instance->fd);
|
||||
fwrite(d, sizeof(d), 1, instance->fd);
|
||||
|
||||
fflush(instance->fd);
|
||||
|
@ -377,7 +391,8 @@ YDB_Error ydb_replace_current_page(YDB_Engine *instance, YDB_TablePage *page) {
|
|||
|
||||
// Write row count
|
||||
YDB_PageSize row_cnt = ydb_page_row_count_get(page);
|
||||
fwrite(&row_cnt, sizeof(row_cnt), 1, instance->fd);
|
||||
YDB_PageSize row_cnt_le = TO_LE(row_cnt);
|
||||
fwrite(&row_cnt_le, sizeof(row_cnt), 1, instance->fd);
|
||||
|
||||
// Write data
|
||||
char page_data[YDB_TABLE_PAGE_SIZE - v0_page_offsets.meta_end];
|
||||
|
@ -412,27 +427,31 @@ YDB_Error ydb_delete_current_page(YDB_Engine *instance) {
|
|||
fputc(YDB_TABLE_PAGE_FLAG_DELETED, instance->fd);
|
||||
|
||||
// Write last_free_page_offset as the next page for current one
|
||||
fwrite(&(instance->last_free_page_offset), sizeof(YDB_Offset), 1, instance->fd);
|
||||
YDB_Offset lfp_le = TO_LE(instance->last_free_page_offset);
|
||||
fwrite(&lfp_le, sizeof(YDB_Offset), 1, instance->fd);
|
||||
|
||||
// Link the previous page with next one (could be null ptr)
|
||||
fseek(instance->fd, instance->prev_page_offset + 1, SEEK_SET); // Skip flags
|
||||
fwrite(&(instance->next_page_offset), sizeof(YDB_Offset), 1, instance->fd);
|
||||
YDB_Offset np_le = TO_LE(instance->next_page_offset);
|
||||
fwrite(&np_le, sizeof(YDB_Offset), 1, instance->fd);
|
||||
|
||||
// If it was the last page, rewrite last_page_offset with prev_page_offset
|
||||
if (instance->next_page_offset == 0) {
|
||||
fseek(instance->fd, 14, SEEK_SET);
|
||||
fwrite(&(instance->prev_page_offset), sizeof(YDB_Offset), 1, instance->fd);
|
||||
YDB_Offset pp_le = TO_LE(instance->prev_page_offset);
|
||||
fwrite(&pp_le, sizeof(YDB_Offset), 1, instance->fd);
|
||||
}
|
||||
|
||||
// Rewrite last_free_page_offset with current offset
|
||||
fseek(instance->fd, 22, SEEK_SET);
|
||||
fwrite(&(instance->curr_page_offset), sizeof(YDB_Offset), 1, instance->fd);
|
||||
YDB_Offset cp_le = TO_LE(instance->curr_page_offset);
|
||||
fwrite(&cp_le, sizeof(YDB_Offset), 1, instance->fd);
|
||||
|
||||
// Flush buffer
|
||||
fflush(instance->fd);
|
||||
|
||||
// Set previous page
|
||||
int64_t ind = --(instance->current_page_index);
|
||||
int64_t ind = --instance->current_page_index;
|
||||
if (ydb_seek_page(instance, ind + 1)) {
|
||||
return YDB_ERR_UNKNOWN;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue