Migrate to v1 data format

Some bugs were fixed too, such as checking for table existence in ydb_create_table() wasn't working and broken instance status after page appending or deletion.
master
Yury Kurlykov 2019-12-05 00:12:09 +10:00
parent 3704f944e7
commit 0cf4623c7a
Signed by: t1meshift
GPG Key ID: B133F3167ABF94D8
6 changed files with 171 additions and 141 deletions

View File

@ -7,7 +7,9 @@ include_directories(inc)
add_library(YeltsinDB STATIC add_library(YeltsinDB STATIC
src/ydb.c inc/YeltsinDB/ydb.h src/ydb.c inc/YeltsinDB/ydb.h
inc/YeltsinDB/error_code.h src/table_page.c inc/YeltsinDB/error_code.h
inc/YeltsinDB/table_page.h src/table_page.c inc/YeltsinDB/table_page.h
inc/YeltsinDB/constants.h inc/YeltsinDB/constants.h
inc/YeltsinDB/types.h inc/YeltsinDB/macro.h) inc/YeltsinDB/types.h
inc/YeltsinDB/macro.h
)

56
cmake/FindCheck.cmake Normal file
View File

@ -0,0 +1,56 @@
# - Try to find the CHECK libraries
# Once done this will define
#
# CHECK_FOUND - system has check
# CHECK_INCLUDE_DIR - the check include directory
# CHECK_LIBRARIES - check library
#
# This configuration file for finding libcheck is originally from
# the opensync project. The originally was downloaded from here:
# opensync.org/browser/branches/3rd-party-cmake-modules/modules/FindCheck.cmake
#
# Copyright (c) 2007 Daniel Gollub <dgollub@suse.de>
# Copyright (c) 2007 Bjoern Ricks <b.ricks@fh-osnabrueck.de>
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
INCLUDE( FindPkgConfig )
# Take care about check.pc settings
PKG_SEARCH_MODULE( CHECK check )
# Look for CHECK include dir and libraries
IF( NOT CHECK_FOUND )
IF ( CHECK_INSTALL_DIR )
MESSAGE ( STATUS "Using override CHECK_INSTALL_DIR to find check" )
SET ( CHECK_INCLUDE_DIR "${CHECK_INSTALL_DIR}/include" )
SET ( CHECK_INCLUDE_DIRS "${CHECK_INCLUDE_DIR}" )
FIND_LIBRARY( CHECK_LIBRARY NAMES check PATHS "${CHECK_INSTALL_DIR}/lib" )
FIND_LIBRARY( COMPAT_LIBRARY NAMES compat PATHS "${CHECK_INSTALL_DIR}/lib" )
SET ( CHECK_LIBRARIES "${CHECK_LIBRARY}" "${COMPAT_LIBRARY}" )
ELSE ( CHECK_INSTALL_DIR )
FIND_PATH( CHECK_INCLUDE_DIR check.h )
FIND_LIBRARY( CHECK_LIBRARIES NAMES check )
ENDIF ( CHECK_INSTALL_DIR )
IF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
SET( CHECK_FOUND 1 )
IF ( NOT Check_FIND_QUIETLY )
MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" )
ENDIF ( NOT Check_FIND_QUIETLY )
ELSE ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
IF ( Check_FIND_REQUIRED )
MESSAGE( FATAL_ERROR "Could NOT find CHECK" )
ELSE ( Check_FIND_REQUIRED )
IF ( NOT Check_FIND_QUIETLY )
MESSAGE( STATUS "Could NOT find CHECK" )
ENDIF ( NOT Check_FIND_QUIETLY )
ENDIF ( Check_FIND_REQUIRED )
ENDIF ( CHECK_INCLUDE_DIR AND CHECK_LIBRARIES )
ENDIF( NOT CHECK_FOUND )
# Hide advanced variables from CMake GUIs
MARK_AS_ADVANCED( CHECK_INCLUDE_DIR CHECK_LIBRARIES )

View File

@ -21,31 +21,6 @@
// TODO static_assert for sizes // TODO static_assert for sizes
// v0
enum YDB_v0_sizes {
YDB_v0_first_page_size = 8,
YDB_v0_last_page_size = 8,
YDB_v0_last_free_page_size = 8,
YDB_v0_page_flags_size = 1,
YDB_v0_page_next_size = 8,
YDB_v0_page_row_count_size = 2,
};
enum YDB_v0_offsets {
YDB_v0_first_page_offset = YDB_TABLE_FILE_DATA_START_OFFSET,
YDB_v0_last_page_offset = YDB_v0_first_page_offset + YDB_v0_first_page_size,
YDB_v0_last_free_page_offset = YDB_v0_last_page_offset + YDB_v0_last_page_size,
YDB_v0_data_offset = YDB_v0_last_free_page_offset + YDB_v0_last_free_page_size,
};
enum YDB_v0_page_offsets {
YDB_v0_page_flags_offset = 0,
YDB_v0_page_next_offset = YDB_v0_page_flags_offset + YDB_v0_page_flags_size,
YDB_v0_page_row_count_offset = YDB_v0_page_next_offset + YDB_v0_page_next_size,
YDB_v0_page_data_offset = YDB_v0_page_row_count_offset + YDB_v0_page_row_count_size,
};
// v1
enum YDB_v1_sizes { enum YDB_v1_sizes {
YDB_v1_first_page_size = 8, YDB_v1_first_page_size = 8,
YDB_v1_last_page_size = 8, YDB_v1_last_page_size = 8,
@ -56,6 +31,13 @@ enum YDB_v1_sizes {
YDB_v1_page_row_count_size = 2, YDB_v1_page_row_count_size = 2,
}; };
enum YDB_v1_offsets {
YDB_v1_first_page_offset = YDB_TABLE_FILE_DATA_START_OFFSET,
YDB_v1_last_page_offset = YDB_v1_first_page_offset + YDB_v1_first_page_size,
YDB_v1_last_free_page_offset = YDB_v1_last_page_offset + YDB_v1_last_page_size,
YDB_v1_data_offset = YDB_v1_last_free_page_offset + YDB_v1_last_free_page_size,
};
enum YDB_v1_page_offsets { enum YDB_v1_page_offsets {
YDB_v1_page_flags_offset = 0, YDB_v1_page_flags_offset = 0,
YDB_v1_page_next_offset = YDB_v1_page_flags_offset + YDB_v1_page_flags_size, YDB_v1_page_next_offset = YDB_v1_page_flags_offset + YDB_v1_page_flags_size,

View File

@ -68,26 +68,13 @@ YDB_Error ydb_create_table(YDB_Engine* instance, const char *path);
YDB_Error ydb_unload_table(YDB_Engine* instance); YDB_Error ydb_unload_table(YDB_Engine* instance);
/** /**
* @brief Seek to `index`th page. * @brief Switch to previous page.
* @param instance A YeltsinDB instance. * @param instance A YeltsinDB instance.
* @param index Page index.
* @return Operation status. * @return Operation status.
* *
* If an error was returned, the state of instance remains the same as it was before execution.
* @todo Possible error codes. * @todo Possible error codes.
*/ */
YDB_Error ydb_seek_page(YDB_Engine* instance, int64_t index); YDB_Error ydb_prev_page(YDB_Engine* instance);
/**
* @brief Get current page index.
* @param instance A YeltsinDB instance.
* @return Current page index.
* @sa error_code.h
*
* Could return error codes (negative values).
* @todo Possible error codes.
*/
int64_t ydb_tell_page(YDB_Engine* instance);
/** /**
* @brief Switch to next page. * @brief Switch to next page.
@ -134,6 +121,15 @@ YDB_TablePage* ydb_get_current_page(YDB_Engine* instance);
*/ */
YDB_Error ydb_delete_current_page(YDB_Engine* instance); YDB_Error ydb_delete_current_page(YDB_Engine* instance);
/**
* @brief Seek to the last page.
* @param instance A YeltsinDB instance
* @return Operation status.
*
* @warning Could break an instance if ydb_
*/
YDB_Error ydb_seek_to_end(YDB_Engine* instance);
// TODO: rebuild page offsets, etc. // TODO: rebuild page offsets, etc.
/** /**
@ -151,7 +147,7 @@ YDB_Error ydb_delete_current_page(YDB_Engine* instance);
* *
* - types.h * - types.h
* *
* And in some cases even [table file structure](table_file_v0.md) * And in some cases even [table file structure](table_file_v1.md)
*/ */
#ifdef __cplusplus #ifdef __cplusplus

186
src/ydb.c
View File

@ -24,8 +24,6 @@ struct __YDB_Engine {
YDB_Offset curr_page_offset; /**< A location of current page in file. */ YDB_Offset curr_page_offset; /**< A location of current page in file. */
YDB_Offset next_page_offset; /**< A location of next page in file. */ YDB_Offset next_page_offset; /**< A location of next page in file. */
int64_t current_page_index; /**< Current page index in range [0, page_count). */
YDB_TablePage *curr_page; /**< A pointer to the current page. */ YDB_TablePage *curr_page; /**< A pointer to the current page. */
uint8_t in_use; /**< "In use" flag. */ uint8_t in_use; /**< "In use" flag. */
@ -46,8 +44,7 @@ void ydb_terminate_instance(YDB_Engine *instance) {
} }
// Internal usage only! // Internal usage only!
// Its only purpose to read current page data and set next_page offset. // Its only purpose to read current page data and set next_page and prev_page offsets.
// You should write prev_page offset on your own.
static YDB_Error __ydb_read_page(YDB_Engine *inst) { static YDB_Error __ydb_read_page(YDB_Engine *inst) {
THROW_IF_NULL(inst, YDB_ERR_INSTANCE_NOT_INITIALIZED); THROW_IF_NULL(inst, YDB_ERR_INSTANCE_NOT_INITIALIZED);
@ -62,16 +59,19 @@ static YDB_Error __ydb_read_page(YDB_Engine *inst) {
return YDB_ERR_TABLE_DATA_CORRUPTED; return YDB_ERR_TABLE_DATA_CORRUPTED;
} }
// Read page flags, next page offset and row count // Read page flags, next and prev page offset and row count
YDB_Flags page_flags = p_data[0]; YDB_Flags page_flags = p_data[0];
YDB_Offset next; YDB_Offset next;
YDB_Offset prev;
YDB_PageSize row_count; YDB_PageSize row_count;
memcpy(&next, p_data + YDB_v0_page_next_offset, sizeof(next)); memcpy(&next, p_data + YDB_v1_page_next_offset, sizeof(next));
REASSIGN_FROM_LE(next); REASSIGN_FROM_LE(next);
memcpy(&row_count, p_data + YDB_v0_page_row_count_offset, sizeof(row_count)); memcpy(&prev, p_data + YDB_v1_page_prev_offset, sizeof(prev));
REASSIGN_FROM_LE(prev);
memcpy(&row_count, p_data + YDB_v1_page_row_count_offset, sizeof(row_count));
REASSIGN_FROM_LE(row_count); REASSIGN_FROM_LE(row_count);
const YDB_PageSize meta_size = YDB_v0_page_data_offset; const YDB_PageSize meta_size = YDB_v1_page_data_offset;
const YDB_PageSize data_size = YDB_TABLE_PAGE_SIZE - meta_size; const YDB_PageSize data_size = YDB_TABLE_PAGE_SIZE - meta_size;
YDB_TablePage *p = ydb_page_alloc(data_size); YDB_TablePage *p = ydb_page_alloc(data_size);
@ -83,6 +83,7 @@ static YDB_Error __ydb_read_page(YDB_Engine *inst) {
if (write_status) return write_status; if (write_status) return write_status;
inst->curr_page = p; inst->curr_page = p;
inst->prev_page_offset = prev;
inst->next_page_offset = next; inst->next_page_offset = next;
return YDB_ERR_SUCCESS; return YDB_ERR_SUCCESS;
@ -101,17 +102,21 @@ static YDB_Offset __ydb_allocate_page_and_seek(YDB_Engine *inst) {
// Allocate an empty chunk // Allocate an empty chunk
char* new_page_data = calloc(1, YDB_TABLE_PAGE_SIZE); char* new_page_data = calloc(1, YDB_TABLE_PAGE_SIZE);
// Write last page offset as prev page offset in this page
YDB_Offset last_page_offset_le = TO_LE(inst->last_page_offset);
memcpy(new_page_data + YDB_v1_page_prev_offset, &last_page_offset_le, sizeof(YDB_Offset));
// Write it to file
fwrite(new_page_data, YDB_TABLE_PAGE_SIZE, 1, inst->fd); fwrite(new_page_data, YDB_TABLE_PAGE_SIZE, 1, inst->fd);
free(new_page_data); free(new_page_data);
// TODO throw error on fail // TODO throw error on fail
// Write next page offset in the previous page // Write next page offset in the previous (last) page
fseek(inst->fd, inst->last_page_offset + YDB_v0_page_next_offset, SEEK_SET); // Skip page flag fseek(inst->fd, inst->last_page_offset + YDB_v1_page_next_offset, SEEK_SET);
fwrite(&allocated_page_offset_le, sizeof(YDB_Offset), 1, inst->fd); fwrite(&allocated_page_offset_le, sizeof(YDB_Offset), 1, inst->fd);
// Write last page offset // Write last page offset
inst->last_page_offset = result; inst->last_page_offset = result;
fseek(inst->fd, YDB_v0_last_page_offset, SEEK_SET); fseek(inst->fd, YDB_v1_last_page_offset, SEEK_SET);
fwrite(&allocated_page_offset_le, sizeof(YDB_Offset), 1, inst->fd); fwrite(&allocated_page_offset_le, sizeof(YDB_Offset), 1, inst->fd);
fflush(inst->fd); fflush(inst->fd);
} else { } else {
@ -119,19 +124,22 @@ static YDB_Offset __ydb_allocate_page_and_seek(YDB_Engine *inst) {
result = inst->last_free_page_offset; result = inst->last_free_page_offset;
// Read last free page offset after allocation // Read last free page offset after allocation
fseek(inst->fd, result + YDB_v0_page_next_offset, SEEK_SET); // Skip flag fseek(inst->fd, result + YDB_v1_page_next_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); REASSIGN_FROM_LE(inst->last_free_page_offset);
fseek(inst->fd, -(long)(sizeof(YDB_Offset) + 1), SEEK_CUR); //FIXME magic
// Rewrite page header // Go back to our almost allocated page
char page_header[] = "\x00" // No flags fseek(inst->fd, result, SEEK_SET);
"\x00\x00\x00\x00\x00\x00\x00\x00" // No next page
"\x00\x00"; // No rows // Rewrite page header with last page offset as previous page
fwrite(page_header, sizeof(page_header)-1, 1, inst->fd); char* page_header = calloc(1, YDB_v1_data_offset);
YDB_Offset last_page_offset_le = TO_LE(inst->last_page_offset);
memcpy(page_header + YDB_v1_page_prev_offset, &last_page_offset_le, sizeof(YDB_Offset));
fwrite(page_header, YDB_v1_data_offset, 1, inst->fd);
free(page_header);
// Write last free page offset after allocation in file // Write last free page offset after allocation in file
fseek(inst->fd, YDB_v0_last_free_page_offset, SEEK_SET); fseek(inst->fd, YDB_v1_last_free_page_offset, SEEK_SET);
YDB_Offset lfp_offset_le = TO_LE(inst->last_free_page_offset); YDB_Offset lfp_offset_le = TO_LE(inst->last_free_page_offset);
fwrite(&lfp_offset_le, sizeof(YDB_Offset), 1, inst->fd); fwrite(&lfp_offset_le, sizeof(YDB_Offset), 1, inst->fd);
} }
@ -152,9 +160,9 @@ YDB_Error ydb_load_table(YDB_Engine *instance, const char *path) {
instance->fd = fopen(path, "rb+"); instance->fd = fopen(path, "rb+");
THROW_IF_NULL(instance->fd, YDB_ERR_UNKNOWN); // TODO file open error THROW_IF_NULL(instance->fd, YDB_ERR_UNKNOWN); // TODO file open error
// FIXME magic // Check file signature
char signature[4]; char signature[YDB_TABLE_FILE_SIGN_SIZE];
fread(signature, 1, 4, instance->fd); fread(signature, 1, YDB_TABLE_FILE_SIGN_SIZE, instance->fd);
int signature_match = memcmp(signature, YDB_TABLE_FILE_SIGN, 3) == 0; int signature_match = memcmp(signature, YDB_TABLE_FILE_SIGN, 3) == 0;
if (!signature_match) { if (!signature_match) {
return YDB_ERR_TABLE_DATA_CORRUPTED; return YDB_ERR_TABLE_DATA_CORRUPTED;
@ -163,18 +171,18 @@ YDB_Error ydb_load_table(YDB_Engine *instance, const char *path) {
fread(&(instance->ver_major), sizeof(instance->ver_major), 1, instance->fd); fread(&(instance->ver_major), sizeof(instance->ver_major), 1, instance->fd);
fread(&(instance->ver_minor), sizeof(instance->ver_minor), 1, instance->fd); fread(&(instance->ver_minor), sizeof(instance->ver_minor), 1, instance->fd);
if (instance->ver_major != 0) { // TODO proper version check if (instance->ver_major != 1) { // TODO proper version check!
return YDB_ERR_TABLE_DATA_VERSION_MISMATCH; return YDB_ERR_TABLE_DATA_VERSION_MISMATCH;
} }
// Check consistency of a page
switch (signature[3]) { switch (signature[3]) {
case '!': case '!':
break; break;
case '?': case '?':
if (instance->ver_minor < 2) {
return YDB_ERR_TABLE_DATA_CORRUPTED;
}
// TODO mark table as possibly corrupted and start rollback from journal // TODO mark table as possibly corrupted and start rollback from journal
// FIXME
return YDB_ERR_TABLE_DATA_CORRUPTED;
break; break;
default: default:
return YDB_ERR_TABLE_DATA_CORRUPTED; return YDB_ERR_TABLE_DATA_CORRUPTED;
@ -210,7 +218,6 @@ YDB_Error ydb_unload_table(YDB_Engine *instance) {
i->prev_page_offset = 0; i->prev_page_offset = 0;
i->curr_page_offset = 0; i->curr_page_offset = 0;
i->next_page_offset = 0; i->next_page_offset = 0;
i->current_page_index = 0;
ydb_page_free(i->curr_page); ydb_page_free(i->curr_page);
i->curr_page = NULL; i->curr_page = NULL;
free(i->filename); free(i->filename);
@ -226,7 +233,7 @@ YDB_Error ydb_create_table(YDB_Engine *instance, const char *path) {
THROW_IF_NULL(instance, YDB_ERR_INSTANCE_NOT_INITIALIZED); THROW_IF_NULL(instance, YDB_ERR_INSTANCE_NOT_INITIALIZED);
THROW_IF_NULL(!instance->in_use, YDB_ERR_INSTANCE_IN_USE); THROW_IF_NULL(!instance->in_use, YDB_ERR_INSTANCE_IN_USE);
if (access(instance->filename, F_OK) != -1) { if (access(path, F_OK) != -1) {
// TODO: Windows does not check W_OK correctly, use other methods. // TODO: Windows does not check W_OK correctly, use other methods.
// TODO: if can't read/write, throw other error // TODO: if can't read/write, throw other error
return YDB_ERR_TABLE_EXIST; return YDB_ERR_TABLE_EXIST;
@ -234,11 +241,11 @@ YDB_Error ydb_create_table(YDB_Engine *instance, const char *path) {
FILE *f = fopen(path, "wb"); FILE *f = fopen(path, "wb");
char tpl[] = YDB_TABLE_FILE_SIGN char tpl[] = YDB_TABLE_FILE_SIGN // File signature
"\x00\x02" "\x01\x00" // File version FIXME magic
"\x1E\x00\x00\x00\x00\x00\x00\x00" "\x1E\x00\x00\x00\x00\x00\x00\x00" // First page offset
"\x1E\x00\x00\x00\x00\x00\x00\x00" "\x1E\x00\x00\x00\x00\x00\x00\x00" // Last page offset
"\x00\x00\x00\x00\x00\x00\x00\x00"; "\x00\x00\x00\x00\x00\x00\x00\x00"; // Last free page offset
fwrite(tpl, sizeof(tpl)-1, 1, f); fwrite(tpl, sizeof(tpl)-1, 1, f);
char *first_page = calloc(1, YDB_TABLE_PAGE_SIZE); char *first_page = calloc(1, YDB_TABLE_PAGE_SIZE);
@ -250,10 +257,13 @@ YDB_Error ydb_create_table(YDB_Engine *instance, const char *path) {
return ydb_load_table(instance, path); return ydb_load_table(instance, path);
} }
int64_t ydb_tell_page(YDB_Engine *instance) { YDB_Error ydb_prev_page(YDB_Engine *instance) {
THROW_IF_NULL(instance, YDB_ERR_INSTANCE_NOT_INITIALIZED); THROW_IF_NULL(instance, YDB_ERR_INSTANCE_NOT_INITIALIZED);
THROW_IF_NULL(instance->in_use, YDB_ERR_INSTANCE_NOT_IN_USE); THROW_IF_NULL(instance->in_use, YDB_ERR_INSTANCE_NOT_IN_USE);
return instance->current_page_index; THROW_IF_NULL(instance->prev_page_offset, YDB_ERR_NO_MORE_PAGES);
instance->curr_page_offset = instance->prev_page_offset;
return __ydb_read_page(instance);
} }
YDB_Error ydb_next_page(YDB_Engine *instance) { YDB_Error ydb_next_page(YDB_Engine *instance) {
@ -261,48 +271,10 @@ YDB_Error ydb_next_page(YDB_Engine *instance) {
THROW_IF_NULL(instance->in_use, YDB_ERR_INSTANCE_NOT_IN_USE); THROW_IF_NULL(instance->in_use, YDB_ERR_INSTANCE_NOT_IN_USE);
THROW_IF_NULL(instance->next_page_offset, YDB_ERR_NO_MORE_PAGES); THROW_IF_NULL(instance->next_page_offset, YDB_ERR_NO_MORE_PAGES);
instance->prev_page_offset = instance->curr_page_offset;
instance->curr_page_offset = instance->next_page_offset; instance->curr_page_offset = instance->next_page_offset;
++instance->current_page_index;
return __ydb_read_page(instance); return __ydb_read_page(instance);
} }
YDB_Error ydb_seek_page(YDB_Engine *instance, int64_t index) {
THROW_IF_NULL(instance, YDB_ERR_INSTANCE_NOT_INITIALIZED);
THROW_IF_NULL(instance->in_use, YDB_ERR_INSTANCE_NOT_IN_USE);
if (index < 0) {
return YDB_ERR_PAGE_INDEX_OUT_OF_RANGE;
}
// Save current state
YDB_Offset prev_page_offset = instance->prev_page_offset;
YDB_Offset curr_page_offset = instance->curr_page_offset;
YDB_Offset next_page_offset = instance->next_page_offset;
int64_t curr_page_index = instance->current_page_index;
if (index < instance->current_page_index) {
instance->prev_page_offset = 0;
instance->curr_page_offset = instance->first_page_offset;
instance->current_page_index = 0;
__ydb_read_page(instance);
}
while (instance->current_page_index != index) {
YDB_Error status = ydb_next_page(instance);
if (status != YDB_ERR_SUCCESS) {
instance->prev_page_offset = prev_page_offset;
instance->curr_page_offset = curr_page_offset;
instance->next_page_offset = next_page_offset;
instance->current_page_index = curr_page_index;
__ydb_read_page(instance);
return status;
}
}
return YDB_ERR_SUCCESS;
}
YDB_TablePage* ydb_get_current_page(YDB_Engine *instance) { YDB_TablePage* ydb_get_current_page(YDB_Engine *instance) {
THROW_IF_NULL(instance, NULL); THROW_IF_NULL(instance, NULL);
THROW_IF_NULL(instance->in_use, NULL); THROW_IF_NULL(instance->in_use, NULL);
@ -314,21 +286,20 @@ YDB_Error ydb_append_page(YDB_Engine* instance, YDB_TablePage* page) {
THROW_IF_NULL(instance, YDB_ERR_INSTANCE_NOT_INITIALIZED); THROW_IF_NULL(instance, YDB_ERR_INSTANCE_NOT_INITIALIZED);
THROW_IF_NULL(instance->in_use, YDB_ERR_INSTANCE_NOT_IN_USE); THROW_IF_NULL(instance->in_use, YDB_ERR_INSTANCE_NOT_IN_USE);
__ydb_allocate_page_and_seek(instance); YDB_Offset new_page_offset = __ydb_allocate_page_and_seek(instance);
YDB_PageSize rc = ydb_page_row_count_get(page); YDB_PageSize rc = ydb_page_row_count_get(page);
YDB_PageSize rc_le = TO_LE(rc);
YDB_Flags f = ydb_page_flags_get(page); YDB_Flags f = ydb_page_flags_get(page);
YDB_Offset next = 0;
char d[YDB_TABLE_PAGE_SIZE - YDB_v0_page_data_offset]; char d[YDB_TABLE_PAGE_SIZE - YDB_v1_page_data_offset];
ydb_page_data_seek(page, 0); ydb_page_data_seek(page, 0);
if (ydb_page_data_read(page, d, sizeof(d))) { if (ydb_page_data_read(page, d, sizeof(d))) {
return YDB_ERR_UNKNOWN; // FIXME return YDB_ERR_UNKNOWN; // FIXME
} }
YDB_PageSize rc_le = TO_LE(rc);
fwrite(&f, sizeof(f), 1, instance->fd); fwrite(&f, sizeof(f), 1, instance->fd);
fwrite(&next, sizeof(next), 1, instance->fd); fseek(instance->fd, new_page_offset + YDB_v1_page_row_count_offset, SEEK_SET);
fwrite(&rc_le, sizeof(rc), 1, instance->fd); fwrite(&rc_le, sizeof(rc), 1, instance->fd);
fwrite(d, sizeof(d), 1, instance->fd); fwrite(d, sizeof(d), 1, instance->fd);
@ -355,8 +326,8 @@ YDB_Error ydb_replace_current_page(YDB_Engine *instance, YDB_TablePage *page) {
YDB_Flags page_flags = ydb_page_flags_get(page); YDB_Flags page_flags = ydb_page_flags_get(page);
fwrite(&page_flags, sizeof(YDB_Flags), 1, instance->fd); fwrite(&page_flags, sizeof(YDB_Flags), 1, instance->fd);
// Skip next page offset // Skip next and prev page offsets
fseek(instance->fd, sizeof(YDB_Offset), SEEK_CUR); fseek(instance->fd, YDB_v1_page_next_size + YDB_v1_page_prev_size, SEEK_CUR);
// Write row count // Write row count
YDB_PageSize row_cnt = ydb_page_row_count_get(page); YDB_PageSize row_cnt = ydb_page_row_count_get(page);
@ -364,7 +335,7 @@ YDB_Error ydb_replace_current_page(YDB_Engine *instance, YDB_TablePage *page) {
fwrite(&row_cnt_le, sizeof(row_cnt), 1, instance->fd); fwrite(&row_cnt_le, sizeof(row_cnt), 1, instance->fd);
// Write data // Write data
char page_data[YDB_TABLE_PAGE_SIZE - YDB_v0_page_data_offset]; char page_data[YDB_TABLE_PAGE_SIZE - YDB_v1_page_data_offset];
ydb_page_data_seek(page, 0); ydb_page_data_seek(page, 0);
if (ydb_page_data_read(page, page_data, sizeof(page_data))) { if (ydb_page_data_read(page, page_data, sizeof(page_data))) {
return YDB_ERR_UNKNOWN; // FIXME return YDB_ERR_UNKNOWN; // FIXME
@ -385,9 +356,11 @@ YDB_Error ydb_delete_current_page(YDB_Engine *instance) {
THROW_IF_NULL(instance->in_use, YDB_ERR_INSTANCE_NOT_IN_USE); THROW_IF_NULL(instance->in_use, YDB_ERR_INSTANCE_NOT_IN_USE);
if (instance->prev_page_offset == 0 && instance->next_page_offset == 0) { if (instance->prev_page_offset == 0 && instance->next_page_offset == 0) {
fseek(instance->fd, instance->curr_page_offset + 9, SEEK_SET); // Skip page flags + next ptr // Just clear page header. That's all.
YDB_PageSize tmp = 0; fseek(instance->fd, instance->curr_page_offset, SEEK_SET);
fwrite(&tmp, sizeof(YDB_PageSize), 1, instance->fd); char* empty_header = calloc(1, YDB_v1_page_data_offset);
fwrite(empty_header, YDB_v1_page_data_offset, 1, instance->fd);
free(empty_header);
return YDB_ERR_SUCCESS; return YDB_ERR_SUCCESS;
} }
@ -400,32 +373,51 @@ YDB_Error ydb_delete_current_page(YDB_Engine *instance) {
fwrite(&lfp_le, sizeof(YDB_Offset), 1, instance->fd); fwrite(&lfp_le, sizeof(YDB_Offset), 1, instance->fd);
// Link the previous page with next one (could be null ptr) // Link the previous page with next one (could be null ptr)
fseek(instance->fd, instance->prev_page_offset + 1, SEEK_SET); // Skip flags if (instance->prev_page_offset != 0) {
fseek(instance->fd, instance->prev_page_offset + YDB_v1_page_next_offset, SEEK_SET);
} else {
// If it was the first page, rewrite first_page_offset with next_page_offset
fseek(instance->fd, YDB_v1_first_page_offset, SEEK_SET);
}
YDB_Offset np_le = TO_LE(instance->next_page_offset); YDB_Offset np_le = TO_LE(instance->next_page_offset);
fwrite(&np_le, sizeof(YDB_Offset), 1, instance->fd); fwrite(&np_le, sizeof(YDB_Offset), 1, instance->fd);
// If it was the last page, rewrite last_page_offset with prev_page_offset // Link the next page with previous one (could be null ptr)
if (instance->next_page_offset == 0) { if (instance->next_page_offset != 0) {
fseek(instance->fd, 14, SEEK_SET); fseek(instance->fd, instance->next_page_offset + YDB_v1_page_prev_offset, SEEK_SET);
YDB_Offset pp_le = TO_LE(instance->prev_page_offset); } else {
fwrite(&pp_le, sizeof(YDB_Offset), 1, instance->fd); // If it was the last page, rewrite last_page_offset with prev_page_offset
fseek(instance->fd, YDB_v1_last_page_offset, SEEK_SET);
} }
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 // Rewrite last_free_page_offset with current offset
fseek(instance->fd, 22, SEEK_SET); fseek(instance->fd, YDB_v1_last_free_page_offset, SEEK_SET);
YDB_Offset cp_le = TO_LE(instance->curr_page_offset); YDB_Offset cp_le = TO_LE(instance->curr_page_offset);
fwrite(&cp_le, sizeof(YDB_Offset), 1, instance->fd); fwrite(&cp_le, sizeof(YDB_Offset), 1, instance->fd);
// Flush buffer // Flush buffer
fflush(instance->fd); fflush(instance->fd);
// Set previous page // Seek to the next page if it's not the last, else seek to the previous one
int64_t ind = --instance->current_page_index; if (instance->next_page_offset != 0) {
if (ydb_seek_page(instance, ind + 1)) { instance->curr_page_offset = instance->next_page_offset;
return YDB_ERR_UNKNOWN; } else {
instance->curr_page_offset = instance->prev_page_offset;
} }
return __ydb_read_page(instance);
}
return YDB_ERR_SUCCESS; YDB_Error ydb_seek_to_end(YDB_Engine *instance) {
THROW_IF_NULL(instance, YDB_ERR_INSTANCE_NOT_INITIALIZED);
THROW_IF_NULL(instance->in_use, YDB_ERR_INSTANCE_NOT_IN_USE);
if (instance->next_page_offset == 0)
return YDB_ERR_SUCCESS;
instance->curr_page_offset = instance->next_page_offset;
return __ydb_read_page(instance);
} }
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -1,5 +1,7 @@
# Table file structure (v0) # Table file structure (v0)
Notice that this version is not supported now. Use v1 documentation instead.
## Table file version changelog ## Table file version changelog
### v0.2 ### v0.2