cacheowanie

This commit is contained in:
Kacper Donat 2018-12-14 19:57:49 +01:00
parent d018819188
commit 4c83ba3036
10 changed files with 402 additions and 58 deletions

View File

@ -2,10 +2,11 @@ CC=gcc
CFLAGS=-Wall -O0 -g
LDFLAGS=-lm -lreadline
all: makeidx openidx
all: makeidx openidx readidx
makeidx: makeidx.o io.o common.o index.o bitmap.c
openidx: openidx.o io.o common.o index.o bitmap.c
makeidx: makeidx.o io.o common.o index.o bitmap.o tape.o
readidx: readidx.o io.o common.o index.o bitmap.o tape.o
openidx: openidx.o io.o common.o index.o bitmap.o tape.o
-include $(wildcard *.d)

View File

83
index.c
View File

@ -4,11 +4,16 @@
#include "io.h"
#include "common.h"
#include "bitmap.h"
#include <libgen.h>
#include <linux/limits.h>
#define BTREE_ERR_CANNOT_OPEN_FILE -1
#define BTREE_ERR_PAGE_SIZE_DIFFERENT -2
#define SWAP(type, x, y) do { type tmp; tmp = y; y = x; x = tmp; } while (0)
#define SWAP(type, x, y) do { type __tmp__; __tmp__ = y; y = x; x = __tmp__; } while (0)
unsigned reads = 0;
unsigned writes = 0;
/* private functions */
void _btree_insert_into_node(btree_t *tree, btree_node_t *node, btree_entry_t *entry);
@ -21,16 +26,24 @@ int _btree_save_header(btree_t *tree)
page_t _btree_alloc(btree_t *tree)
{
page_t page = 2;
page_t page = 1, bitmap_page = 1;
long long bit;
uint8_t bitmap[PAGE_SIZE];
file_read(tree->file, 1, bitmap, PAGE_SIZE);
bit = bitmap_find_first(bitmap, PAGE_SIZE);
bitmap_set(bitmap, bit);
file_write(tree->file, 1, bitmap, PAGE_SIZE);
do {
file_read(tree->file, bitmap_page, bitmap, PAGE_SIZE);
bit = bitmap_find_first(bitmap, PAGE_SIZE);
page += bit;
if (bit == -1) {
bitmap_page += PAGE_SIZE * 8 + 1;
page += PAGE_SIZE * 8 + 1;
}
} while (bit == -1);
bitmap_set(bitmap, bit);
file_write(tree->file, bitmap_page, bitmap, PAGE_SIZE);
page += bit + 1;
printfv(VERBOSITY_DEBUG, "[alloc] allocated page %zu.\n", page);
@ -42,7 +55,7 @@ void _btree_page_free(btree_t *tree, page_t page)
printfv(VERBOSITY_DEBUG, "[alloc] freeing page %zu.\n", page);
uint8_t bitmap[PAGE_SIZE];
file_read(tree->file, 1, bitmap, PAGE_SIZE);
file_read(tree->file, 1 + (page / (PAGE_SIZE * 8)) * PAGE_SIZE, bitmap, PAGE_SIZE);
bitmap_unset(bitmap, page - 2);
file_write(tree->file, 1, bitmap, PAGE_SIZE);
}
@ -145,15 +158,31 @@ void _btree_node_insert_entry(btree_node_t* node, btree_entry_t entry)
node->header.entries++;
}
void _btree_init(btree_t *tree)
void _btree_init(btree_t *tree, char* mode)
{
char path[PATH_MAX];
strcpy(path, tree->header.main);
char *dir = dirname(path);
sprintf(path, "%s/%s", dir, tree->header.main);
_btree_stack_clear(tree);
tree->main = tape_open(path, mode);
}
int btree_init(btree_t *tree, char* filename, size_t d)
{
printfv(VERBOSITY_DEBUG, "[btree] Initializing btree in file %s d=%zu.\n", filename, d);
tree->file = file_open(filename, "w+", PAGE_SIZE);
char path[PATH_MAX];
strcpy(path, filename);
char* ext = strrchr(path, '.');
if (ext) *ext = 0;
sprintf(tree->header.main, "%s.dat", path);
printfv(VERBOSITY_DEBUG, "[btree] Initializing btree in file %s d=%zu, main=%s.\n", filename, d, tree->header.main);
tree->file = file_open(filename, "w+");
if (!tree->file) {
fprintf(stderr, "Cannot open file %s.\n", filename);
@ -171,7 +200,7 @@ int btree_init(btree_t *tree, char* filename, size_t d)
root.header.entries = 0;
_btree_write_node(&root, tree, tree->header.root);
_btree_init(tree);
_btree_init(tree, "w");
return 0;
}
@ -180,7 +209,7 @@ int btree_open(btree_t *tree, char* filename)
{
printfv(VERBOSITY_DEBUG, "[btree] Trying to open btree index in file %s\n", filename);
tree->file = file_open(filename, "r+", PAGE_SIZE);
tree->file = file_open(filename, "r+");
if (!tree->file) {
fprintf(stderr, "Cannot open file %s.\n", filename);
@ -189,7 +218,7 @@ int btree_open(btree_t *tree, char* filename)
file_read(tree->file, 0, &tree->header, sizeof(btree_header_t));
printfv(VERBOSITY_DEBUG, "[btree] Found BTREE d=%zu, ps=%zu, root=%" PRIu64 "\n", tree->header.d, tree->header.page_size, tree->header.root);
printfv(VERBOSITY_DEBUG, "[btree] Found BTREE d=%zu, ps=%zu, root=%" PRIu64 ", mainfile=%s\n", tree->header.d, tree->header.page_size, tree->header.root, tree->header.main);
if (tree->header.page_size != PAGE_SIZE) {
fprintf(stderr, "BTree page size mismatch, expecting %d got %zu, closing.\n", PAGE_SIZE, tree->header.page_size);
@ -197,7 +226,7 @@ int btree_open(btree_t *tree, char* filename)
return BTREE_ERR_PAGE_SIZE_DIFFERENT;
}
_btree_init(tree);
_btree_init(tree, "rb+");
return 0;
}
@ -427,14 +456,16 @@ page_t btree_find(btree_t *tree, record_key_t key, btree_entry_t* dest, btree_no
page_t btree_insert(btree_t *tree, record_t record)
{
record_key_t key = record.key;
record_key_t key = record.key;
btree_node_t node;
if (btree_find(tree, key, NULL, &node, NULL) != PAGE_NONE) {
printfv(VERBOSITY_DEBUG, "[btree] record with key %zu already exists.\n", key);
return PAGE_NONE;
}
btree_entry_t entry = { PAGE_NONE, key, 2137, PAGE_NONE };
offset_t offset = tape_append(tree->main, &record, sizeof(record));
btree_entry_t entry = { PAGE_NONE, key, offset, PAGE_NONE };
_btree_insert_into_node(tree, &node, &entry);
return node.page;
@ -591,6 +622,23 @@ page_t btree_remove(btree_t *tree, record_key_t key)
return node.page;
}
bool btree_update(btree_t *tree, record_key_t key, record_t record)
{
if (record.key != key) {
printfv(VERBOSITY_DEBUG, "[btree] update key mismatch, removing %zu and adding %zu.\n", key, record.key);
btree_remove(tree, key);
return btree_insert(tree, record) != PAGE_NONE;
}
btree_entry_t entry;
if (btree_find(tree, key, &entry, NULL, NULL) == PAGE_NONE) {
printfv(VERBOSITY_DEBUG, "[btree] Record with key %zu not found.\n", key, record.key);
return false;
}
return true;
}
btree_entry_t *btree_get_entry(btree_node_t* node, unsigned n)
{
if (n > node->header.entries) {
@ -604,4 +652,5 @@ void btree_close(btree_t* tree)
{
printfv(VERBOSITY_DEBUG, "[btree] Closing index %s.\n", tree->file->filename);
file_close(tree->file);
tape_close(tree->main);
}

View File

@ -3,6 +3,7 @@
#include "io.h"
#include "record.h"
#include "tape.h"
#include <inttypes.h>
#define SIZEOF_ENTRIES(n) (sizeof(btree_node_header_t) + (sizeof(btree_entry_t) - sizeof(page_t))*(n) + ((n) > 0 ? 1 : 0) * sizeof(page_t))
@ -16,11 +17,15 @@
#define NODE_IS_ROOT 1
#define NODE_IS_LEAF 2
extern unsigned reads;
extern unsigned writes;
typedef struct {
size_t d; /* 8 bytes long */
size_t page_size; /* 8 bytes long */
page_t root; /* 8 bytes long */
} btree_header_t; /* 24 bytes long */
char main[256]; /* 256 bytes long */
} btree_header_t; /* 280 bytes long */
typedef struct {
uint16_t flags;
@ -48,6 +53,7 @@ typedef struct {
typedef struct {
file_t *file;
tape_t *main;
btree_header_t header;
struct {
btree_stack_elem_t *current;

95
io.c
View File

@ -5,22 +5,23 @@
#include <stdlib.h>
#include <string.h>
file_t* file_open(const char* filename, const char* mode, size_t page_size)
page_cache_entry_t *_file_load_page(file_t* file, page_t page);
void _file_flush_page(file_t *file, page_cache_entry_t *entry);
file_t* file_open(const char* filename, const char* mode)
{
FILE* handle = fopen(filename, mode);
if (!handle) {
printfv(VERBOSITY_NORMAL, "Can't open file %s.\n", filename);
printfv(VERBOSITY_NORMAL, "[io] Can't open file %s.\n", filename);
return NULL;
}
printfv(VERBOSITY_DEBUG, "File %s opened in %s with page size %zu.\n", filename, mode, page_size);
printfv(VERBOSITY_DEBUG, "[io] File %s opened in %s with page size %zu.\n", filename, mode, PAGE_SIZE);
file_t* result = malloc(sizeof(file_t));
result->page_size = page_size;
result->file = handle;
result->filename = malloc(strlen(filename) + 1);
result->buffer = malloc(page_size);
result->file = handle;
result->filename = malloc(strlen(filename) + 1);
strcpy(result->filename, filename);
@ -29,32 +30,80 @@ file_t* file_open(const char* filename, const char* mode, size_t page_size)
void file_close(file_t* file)
{
printfv(VERBOSITY_DEBUG, "Closing file %s.\n", file->filename);
file_flush(file);
printfv(VERBOSITY_DEBUG, "[io] Closing file %s.\n", file->filename);
fclose(file->file);
free(file->filename);
free(file->buffer);
free(file);
}
size_t file_read(file_t* file, unsigned block, void* buffer, size_t length)
size_t file_read(file_t* file, page_t page, void* buffer, size_t length)
{
memset(file->buffer, 0, file->page_size);
page_cache_entry_t *entry = _file_load_page(file, page);
memcpy(buffer, entry->data, length);
printfv(VERBOSITY_DEBUG, "Reading page %u of %s.\n", block, file->filename);
fseek(file->file, block * file->page_size, SEEK_SET);
int read = fread(file->buffer, 1, file->page_size, file->file);
memcpy(buffer, file->buffer, length);
return read;
return entry->size;
}
size_t file_write(file_t* file, unsigned block, const void* buffer, size_t length)
size_t file_write(file_t* file, page_t page, const void* buffer, size_t length)
{
memset(file->buffer, 0, file->page_size);
memcpy(file->buffer, buffer, length);
page_cache_entry_t *entry = _file_load_page(file, page);
printfv(VERBOSITY_DEBUG, "Writing page %u to %s. (%zu bytes)\n", block, file->filename, length);
fseek(file->file, block * file->page_size, SEEK_SET);
return fwrite(file->buffer, 1, file->page_size, file->file);
memset(entry->data, 0, PAGE_SIZE);
memcpy(entry->data, buffer, length);
entry->flags |= PAGE_DIRTY;
entry->size = length;
return entry->size;
}
void file_flush(file_t* file)
{
for (unsigned i = 0; i < CACHE_ENTRIES; i++) {
_file_flush_page(file, file->cache + i);
}
}
page_cache_entry_t *_file_load_page(file_t* file, page_t page)
{
page_cache_entry_t *entry = file->cache + (page % CACHE_ENTRIES);
if (entry->page == page && entry->flags & PAGE_PRESENT) {
// already in cache
return entry;
}
_file_flush_page(file, entry);
int result = fseek(file->file, page * PAGE_SIZE, SEEK_SET);
memset(entry->data, 0, PAGE_SIZE);
entry->size = fread(entry->data, 1, PAGE_SIZE, file->file);
if (entry->size) {
printfv(VERBOSITY_DEBUG, "[io] Loading page %u of %s (%zu bytes).\n", page, file->filename, entry->size);
reads++;
}
entry->page = page;
entry->flags |= PAGE_PRESENT;
return entry;
}
void _file_flush_page(file_t *file, page_cache_entry_t *entry)
{
if (entry->flags & PAGE_PRESENT && entry->flags & PAGE_DIRTY) {
printfv(VERBOSITY_DEBUG, "[io] Flushing page %u to %s (%zu bytes).\n", entry->page, file->filename, entry->size);
fseek(file->file, entry->page * PAGE_SIZE, SEEK_SET);
fwrite(entry->data, 1, entry->size, file->file);
// disable dirty flag
entry->flags &= ~PAGE_DIRTY;
writes++;
}
}

41
io.h
View File

@ -1,28 +1,43 @@
#ifndef IO_H
#define IO_H
#define PAGE_SIZE 512
#define PAGE_NONE 0
#define PAGE_SIZE 512
#define PAGE_NONE 0
#define PAGE_PRESENT 1
#define PAGE_DIRTY 2
#define CACHE_ENTRIES 16
#include <stdio.h>
#include <inttypes.h>
typedef struct {
FILE* file;
char* filename;
size_t page_size;
void* buffer;
} file_t;
extern unsigned reads;
extern unsigned writes;
typedef uint64_t page_t;
typedef uint64_t offset_t;
file_t* file_open(const char* filename, const char* mode, size_t page_size);
typedef struct {
page_t page;
size_t size;
char data[PAGE_SIZE];
uint8_t flags;
} page_cache_entry_t;
typedef struct {
FILE* file;
char* filename;
page_cache_entry_t cache[CACHE_ENTRIES];
} file_t;
file_t* file_open(const char* filename, const char* mode);
void file_close(file_t* file);
size_t file_read(file_t* file, unsigned block, void* buffer, size_t size);
size_t file_write(file_t* file, unsigned block, const void* buffer, size_t size);
size_t file_read(file_t* file, page_t page, void* buffer, size_t size);
size_t file_write(file_t* file, page_t page, const void* buffer, size_t size);
void file_flush(file_t* file);
#endif

View File

@ -62,6 +62,7 @@ result_t dump_command(const char* command, char* args);
result_t print_command(const char* command, char* args);
result_t records_command(const char* command, char* args);
result_t find_command(const char* command, char* args);
result_t read_command(const char* command, char* args);
result_t delete_command(const char* command, char* args);
result_t verbosity_command(const char* command, char* args);
@ -73,6 +74,7 @@ static command_t commands[] = {
{ "print", "Prints tree", print_command },
{ "records", "Prints records of given page", records_command },
{ "find", "Finds record", find_command },
{ "read", "Reads record", read_command },
{ "delete", "Deletes record", delete_command },
{ "verbosity", "Changes the verbosity", verbosity_command },
};
@ -144,6 +146,29 @@ result_t find_command(const char* command, char* args)
return RESULT_OK;
}
result_t read_command(const char* command, char* args)
{
record_key_t key;
if (sscanf(args, "%u", &key) == 1) {
btree_entry_t entry;
page_t page;
record_t record;
if ((page = btree_find(&tree, key, &entry, NULL, NULL))) {
printf("Record %u found on page %zu, offset: %lu\n", key, page, entry.location);
tape_read(tree.main, entry.location, &record, sizeof(record_t));
printf("PK: %u, x: %lf, y: %lf\n", record.key, record.x, record.y);
} else {
printf("404 Not found\n");
}
} else {
printf("Usage: read key\n");
}
return RESULT_OK;
}
result_t delete_command(const char* command, char* args)
{
record_key_t key;
@ -217,7 +242,7 @@ void print_page(page_t page, unsigned depth, unsigned current)
for (int i = 0; i < node.header.entries; i++) {
entry = btree_get_entry(&node, i);
print_page(entry->left, depth - 1, current + 1);
printf("%s%zu < %u [0x%zx] > %zu\n", prefix, entry->left, entry->key, entry->location, entry->right);
printf("%s%zu < %u [0x%08zx] > %zu\n", prefix, entry->left, entry->key, entry->location, entry->right);
}
print_page(entry->right, depth - 1, current + 1);
}

83
readidx.c Normal file
View File

@ -0,0 +1,83 @@
#include <stdlib.h>
#include <memory.h>
#define OPTPARSE_IMPLEMENTATION
#define OPTPARSE_API static
#include "common.h"
#include "index.h"
typedef struct {
char* index;
} opts_t;
opts_t options;
btree_t tree;
void init_args(int args, char* argv[])
{
optparse_t opts;
optparse_init(&opts, argv);
for (char opt; opt != -1; opt = optparse(&opts, "qv")) {
switch (opt) {
case 'q':
verbosity--;
break;
case 'v':
verbosity++;
break;
}
}
options.index = optparse_arg(&opts);
}
void help(const char* name) {
printf(
"%s - some help"
,
name
);
}
void print_page(page_t page)
{
if (!page) return;
char buffer[PAGE_SIZE];
char prefix[1024] = {};
file_read(tree.file, page, buffer, PAGE_SIZE);
btree_node_t node;
memcpy(&node.header, buffer, sizeof(node.header));
memcpy(&node.entries, buffer + sizeof(node.header), NODE_SIZE_MAX);
btree_entry_t *entry;
for (int i = 0; i < node.header.entries; i++) {
entry = btree_get_entry(&node, i);
print_page(entry->left);
printf("%u\n", entry->key);
}
print_page(entry->right);
}
int main(int argc, char* argv[])
{
if (argc < 2) {
help(argv[0]);
return 0;
}
init_args(argc, argv);
if (btree_open(&tree, options.index) != 0) {
fprintf(stderr, "Cannot open indes %s for reading.", options.index);
return 1;
}
print_page(tree.header.root);
return EXIT_SUCCESS;
}

96
tape.c Normal file
View File

@ -0,0 +1,96 @@
#include "tape.h"
#include "common.h"
#include <stdlib.h>
#include <memory.h>
#include <string.h>
tape_t* tape_open(const char* filename, const char* mode)
{
file_t *file = file_open(filename, mode);
printfv(VERBOSITY_VERBOSE, "Opening file %s in mode %s.\n", filename, mode);
if (!file) {
fprintf(stderr, "Cannot open %s in %s mode.", filename, mode);
return NULL;
}
tape_t* tape = malloc(sizeof(tape_t));
fseek(file->file, 0, SEEK_END);
tape->file = file;
tape->end = ftell(file->file);
return tape;
}
void tape_close(tape_t* tape)
{
file_close(tape->file);
}
void* tape_read(tape_t* tape, offset_t offset, void* record, size_t size)
{
char buffer[PAGE_SIZE];
page_t page = offset / PAGE_SIZE;
offset = offset % PAGE_SIZE;
offset_t written = 0;
file_read(tape->file, page, buffer, PAGE_SIZE);
while (size > PAGE_SIZE - offset) {
memcpy(record + written, buffer + offset, PAGE_SIZE - offset);
size -= PAGE_SIZE - offset;
written += PAGE_SIZE - offset;
page++;
offset = 0;
file_read(tape->file, page, buffer, PAGE_SIZE);
}
memcpy(record + written, buffer + offset, size);
return record;
}
offset_t tape_write(tape_t* tape, offset_t location, void* record, size_t size)
{
char buffer[PAGE_SIZE];
page_t page = location / PAGE_SIZE;
offset_t offset = location % PAGE_SIZE;
offset_t written = 0;
size_t original = file_read(tape->file, page, buffer, PAGE_SIZE);
while (size > PAGE_SIZE - offset) {
memcpy(buffer + offset, record + written, PAGE_SIZE - offset);
size -= PAGE_SIZE - offset;
written += PAGE_SIZE - offset;
file_write(tape->file, page, buffer, PAGE_SIZE);
page++;
offset = 0;
file_read(tape->file, page, buffer, PAGE_SIZE);
}
memcpy(buffer + offset, record + written, size);
file_write(tape->file, page, buffer, offset + size > original ? offset + size : original);
written += size;
if (location + written > tape->end) {
tape->end = location + written;
}
return location;
}
offset_t tape_append(tape_t* tape, void* record, size_t size)
{
return tape_write(tape, tape->end, record, size);
}

20
tape.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef TAPE_H_
#define TAPE_H_
#include <stdio.h>
#include "record.h"
#include "io.h"
typedef struct {
file_t *file;
offset_t end;
} tape_t;
tape_t* tape_open(const char* filename, const char* mode);
void tape_close(tape_t* tape);
void* tape_read(tape_t* tape, offset_t offset, void* record, size_t size);
offset_t tape_write(tape_t* tape, offset_t offet, void* record, size_t size);
offset_t tape_append(tape_t* tape, void* record, size_t size);
#endif