1
0
mirror of https://github.com/fumiama/fumidb.git synced 2026-06-05 08:40:30 +08:00

finish page & file

This commit is contained in:
源文雨
2022-05-01 17:42:11 +08:00
parent 1463c1f606
commit eda10fba91
8 changed files with 546 additions and 35 deletions

View File

@@ -3,23 +3,21 @@
由于文件内普遍以uint64作为指针因此理论最大支持文件大小为`16384PB`,在现有条件下完全足够使用。
## 文件头
文件最开头填充了固定的8字节ascii编码`FUMIDB\1\0`。前6字节必须为`FUMIDB`,表明本文件为`fumidb`数据库文件格式。7, 8字节`\1\0`作为数据库的版本是一个小端的uint16在这里表示第1版之后将依次递增。今后可能会在文件头增加更多字段,由于其后的`ptr of first table`不一定要求其指向的第一个表头紧跟文件头,字段的增加将不影响之前版本的解析。在目前实现时,为`possible other header data`空出16字节
文件最开头填充了固定的8字节ascii编码`FUMIDB\1\0`。前6字节必须为`FUMIDB`,表明本文件为`fumidb`数据库文件格式。7, 8字节`\1\0`作为数据库的版本是一个小端的uint16在这里表示第1版之后将依次递增。今后可能会在文件头增加更多字段。
```
0 8 16
┌───────────────────┬───────────────────┐
│ FUMIDB\1\0 │ ptr of unused blk │
├───────────────────┼───────────────────┤
│ ptr of first table│ ptr of next table
│ ptr of next table ...... ......
├───────────────────┴───────────────────┤
│ possible other header data │
├───────────────────────────────────────┤
│ first table head │
├───────────────────────────────────────┤
│ ...... ...... ...... │
├───────────────────────────────────────┤
│ some possible padding to fit 4096Byte │
├───────────────────┬───────────────────┤
│ ptr of next table │ second table head │
│ ptr of next table │ first table head
├───────────────────┴───────────────────┤
│ ...... ...... ...... │
├───────────────────────────────────────┤
@@ -34,12 +32,12 @@
#### 新建
空闲块不会被主动新建,而是源于分配时富余的部分以及删除后的剩余。
#### 合并
受限于记录长度的数字为uint16一块未被使用的空闲空间大小最大为`65535`,实际使用时不使其超过`4096`。如果确有连续的超过`4096`字节的空闲,应当划分为多个块。块应当是`4k`对齐的。
受限于记录长度的数字为uint16一块未被使用的空闲空间大小最大为`65535`,实际使用时不使其超过`4096`。如果确有连续的超过`4096`字节的空闲,应当划分为多个块。`4096`字节的块应当是`4k`对齐的。
#### 使用
使用时优先从第一个块遍历比较其大小以及页对齐是否符合要求。当使用后仍有剩余对于小于10字节的块直接舍弃不用否则更新块大小与相关链表指针。
### 表
#### 新建
在新建表时将计算表头大小,优先选取一块未被使用的足够大的对齐部分写入表头。当找不到时,在文件末尾附加表头(留出新的对齐)。接下来将上一个表头开头的`下一个表头的指针`指向新表头的开头,然后建立相应数据结构,填充表头字段。
在新建表时将计算表头大小,优先选取一块未被使用的足够大的`4k`对齐部分写入表头。当找不到时,在文件末尾附加表头(留出新的对齐)。接下来将上一个表头开头的`下一个表头的指针`指向新表头的开头,然后建立相应数据结构,填充表头字段。
#### 修改
一旦创建数据表,将不支持修改。可以先删除表再重新创建,但这样数据将会丢失。
#### 删除

View File

@@ -1,6 +1,6 @@
# 数据表格式
## 表头
如下所示其中行类型列表的No.1自动成为主键,强制应用`unique`类型修饰符;`data blocks`可以为任意数据,如索引,表项等。由于数据块均为定长,增加时直接添加或重用已删除区块,修改时直接覆盖,删除时直接在索引中移除该项,将块首地址附加到已删除块的链表即可。
如下所示,加上文件中附加的`ptr of next table`,表头永远是`4k`对齐的,其中行类型列表的No.1自动成为主键,强制应用`unique`类型修饰符;`data blocks`可以为任意数据,如索引,表项等。由于数据块均为定长,增加时直接添加或重用已删除区块,修改时直接覆盖,删除时直接在索引中移除该项,将块首地址附加到已删除块的链表即可。
```
┌──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┬──────────┐
│ 0 - 7 │ 8 - 15 │ 16 -- 23 │ 24 -- 31 │ 32 -- 39 │ 40 -- 47 │ 48 -- 55 │ 56 -- 63 │

24
include/file.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef _FILE_H_
#define _FILE_H_
#include <stdint.h>
// 初始化并写入数据库文件头
int init_file_header_page(int fd);
// 获得数据库版本
uint16_t get_db_version(int fd);
// 设置 ptr of unused blk 字段
int set_first_unused_block(int fd, uint64_t ptr);
// 获得 ptr of unused blk 字段
uint64_t get_first_unused_block(int fd);
// 设置 ptr of next table 字段
int set_first_table(int fd, uint64_t ptr);
// 获得 ptr of next table 字段
uint64_t get_first_table(int fd);
#endif

View File

@@ -7,27 +7,61 @@
#define PAGESZ 4096
#endif
// 获取文件中的第一个空闲页,并将其 mmap 到内存
// 获取文件中的第一个空闲页,并将其到内存
// 如果现有空闲均无整页,则新分配一页
// 返回指针的 -8 字节记录了本页在文件的偏移
// 因此实际上分配了 PAGESZ+8 的空间
// 返回:
// EOF 错误
// NULL 错误,参见 errno
// page 指针
void* alloc_page(int fd);
// 释放分配的页,将其标记为空闲以备使用
// 刷新一页
// 返回:
// EOF 错误
// EOF lseek 错误,参见 errno
// 0/1 write size != PAGESZ
int sync_page(int fd, void* page);
// 刷新并释放 page
// 返回:
// EOF lseek 错误,参见 errno
// 0/1 write size != PAGESZ
int unmount_page(int fd, void* page);
// 释放分配的页,将其标记为空闲以备使用
// 同时将数据刷新到文件
// 返回:
// EOF 错误,参见 errno
// 0 成功
int free_page(int fd, void* page);
// 获取文件中的第一个满足 size 大小的块
// 获取文件中的第一个满足 size 大小的块的位置
// 返回的块大小一定是 size实际上为 size + 8 + 2
// 开头的 8+2 字节记录了真正的块位置与大小以备释放
// 返回的 ptr 已经跳过这 10 个字节
// 返回:
// EOF 错误
void* alloc_block(int fd, size_t size);
// NULL 错误,参见 errno
// blk 指针
void* alloc_block(int fd, uint16_t size);
// 刷新 block 到文件
// 返回:
// EOF lseek 错误或 size 过大,参见 errno
// 0/1 write size != PAGESZ
int sync_block(int fd, void* blk);
// 刷新 block 到文件并释放
// 返回:
// EOF lseek 错误或 size 过大,参见 errno
// 0/1 write size != PAGESZ
int unmount_block(int fd, void* blk);
// 释放块,并将其标记为空闲以备使用
// 值得注意的是,只有在本页最后一块
// 也被释放后,这一页才会被真正释放
// 如果该块前后也有空闲且不跨过4096
// 将会被合并
// 返回:
// EOF 错误
int free_block(int fd, void* page);
// EOF 错误,参见 errno
// 0 成功
int free_block(int fd, void* blk);
#endif

49
src/file.c Normal file
View File

@@ -0,0 +1,49 @@
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
#include "../include/binary.h"
#include "../include/page.h"
#include "../include/file.h"
uint8_t header[PAGESZ] = {'F', 'U', 'M', 'I', 'D', 'B', 1, 0};
int init_file_header_page(int fd) {
lseek(fd, 0, SEEK_SET);
return write(fd, header, PAGESZ) != PAGESZ;
}
uint16_t get_db_version(int fd) {
uint16_t v;
if(lseek(fd, 6, SEEK_SET) < 0) return EOF;
readle16(fd, v);
return v;
}
int set_first_unused_block(int fd, uint64_t ptr) {
uint8_t buf[8];
if(lseek(fd, 8, SEEK_SET) < 0) return EOF;
putle64(buf, ptr);
return write(fd, buf, 8) != 8;
}
uint64_t get_first_unused_block(int fd) {
uint64_t ptr;
if(lseek(fd, 8, SEEK_SET) < 0) return EOF;
readle64(fd, ptr);
return ptr;
}
int set_first_table(int fd, uint64_t ptr) {
uint8_t buf[8];
if(lseek(fd, 16, SEEK_SET) < 0) return EOF;
putle64(buf, ptr);
return write(fd, buf, 8) != 8;
}
uint64_t get_first_table(int fd) {
uint64_t ptr;
if(lseek(fd, 16, SEEK_SET) < 0) return EOF;
readle64(fd, ptr);
return ptr;
}

View File

@@ -1,12 +1,11 @@
// page.c
// 管理文件中的空闲块
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <errno.h>
#include "../include/binary.h"
#include "../include/page.h"
@@ -14,25 +13,239 @@
uint8_t nullpage[PAGESZ];
void* alloc_page(int fd) {
uint64_t ptr, prev_ptr = 8;
uint64_t ptr = 8, prev_ptr = 0, prev_prev_ptr = 0;
void* page;
if(lseek(fd, 8, SEEK_SET) < 0) return EOF;
uint8_t buf[8];
// 对于 page只关心位于第一页 8~15 字节的 ptr of unused blk
readle64(fd, ptr);
while(ptr) {
if(!(ptr%PAGESZ)) { // 找到符合要求的页
page = mmap(NULL, PAGESZ, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, ptr);
if(page < 0) return page;
if(lseek(fd, prev_ptr, SEEK_SET) < 0) return EOF;
write(fd, page, 8); // 从空闲块链表移除本块
if(lseek(fd, ptr, SEEK_SET) < 0) return NULL;
if(read(fd, buf, 8) != 8) return NULL;
page = malloc(PAGESZ+8);
if(page == NULL) return NULL;
putle64(page, ptr);
page += 8;
if(lseek(fd, prev_ptr, SEEK_SET) < 0) return NULL;
if(write(fd, buf, 8) != 8) return NULL; // 从空闲块链表移除本块
return page;
}
if(prev_prev_ptr && ptr < prev_ptr) { // 不符合顺序,进行一次调整
lseek(fd, prev_prev_ptr, SEEK_SET);
putle64(buf, ptr);
if(write(fd, buf, 8) != 8) return NULL; // 1->next = 3
if(lseek(fd, ptr, SEEK_SET) < 0) return NULL;
prev_prev_ptr = ptr; // new1 = 3
readle64(fd, ptr); // ptr(new3) = 3->next
lseek(fd, -8, SEEK_SET);
putle64(buf, prev_ptr); // new2 = 2
if(write(fd, buf, 8) != 8) return NULL; // 3->next = 2
lseek(fd, prev_ptr, SEEK_SET);
putle64(buf, ptr);
if(write(fd, buf, 8) != 8) return NULL; // 2->next = ptr
continue;
}
prev_prev_ptr = prev_ptr;
prev_ptr = ptr;
if(lseek(fd, ptr, SEEK_SET) < 0) return NULL;
readle64(fd, ptr);
}
ptr = lseek(fd, 0, SEEK_END);
if(ptr < 0) return NULL;
if(ptr%PAGESZ) { // 文件没有页对齐
errno = ESPIPE;
return NULL;
}
if(write(fd, nullpage, PAGESZ) != PAGESZ) return NULL;
page = malloc(PAGESZ+8);
if(page == NULL) return NULL;
putle64(page, ptr);
return page+8;
}
int sync_page(int fd, void* page) {
uint64_t ptr = le64(page-8);
if(lseek(fd, ptr, SEEK_SET) < 0) return EOF;
return write(fd, page, PAGESZ) != PAGESZ;
}
int unmount_page(int fd, void* page) {
int r = sync_page(fd, page);
free(page-8);
return r;
}
int free_page(int fd, void* page) {
uint64_t ptr = 8, prev_ptr = 0, prev_prev_ptr = 0, page_ptr = le64(page-8);
uint8_t buf[8];
while(ptr && ptr < page_ptr) {
if(prev_ptr == ptr) return EOF;
if(prev_prev_ptr && ptr < prev_ptr) { // 不符合顺序,进行一次调整
lseek(fd, prev_prev_ptr, SEEK_SET);
putle64(buf, ptr);
if(write(fd, buf, 8) != 8) return EOF; // 1->next = 3
if(lseek(fd, ptr, SEEK_SET) < 0) return EOF;
prev_prev_ptr = ptr; // new1 = 3
readle64(fd, ptr); // ptr(new3) = 3->next
lseek(fd, -8, SEEK_SET);
putle64(buf, prev_ptr); // new2 = 2
if(write(fd, buf, 8) != 8) return EOF; // 3->next = 2
lseek(fd, prev_ptr, SEEK_SET);
putle64(buf, ptr);
if(write(fd, buf, 8) != 8) return EOF; // 2->next = ptr
continue;
}
prev_prev_ptr = prev_ptr;
prev_ptr = ptr;
if(lseek(fd, ptr, SEEK_SET) < 0) return EOF;
readle64(fd, ptr);
}
ptr = lseek(fd, 0, SEEK_END);
if(ptr < 0 || !(ptr%PAGESZ)) return EOF;
if(write(fd, nullpage, PAGESZ) != PAGESZ) return EOF;
return mmap(NULL, PAGESZ, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, ptr);
putle64(page, ptr);
putle16(page+8, PAGESZ);
putle64(buf, page_ptr);
lseek(fd, prev_ptr, SEEK_SET);
if(write(fd, buf, 8) != 8) return EOF; // 将本页附加到链表
sync_page(fd, page);
free(page-8);
return 0;
}
void* alloc_block(int fd, uint16_t size) {
uint64_t ptr = 8, prev_ptr = 0, prev_prev_ptr = 0;
void* blk;
uint8_t buf[8];
uint16_t blksz;
if(size > PAGESZ) return NULL;
// 对于 page只关心位于第一页 8~15 字节的 ptr of unused blk
while(ptr) {
if(lseek(fd, ptr, SEEK_SET) < 0) return NULL;
if(read(fd, buf, 8) != 8) return NULL;
readle16(fd, blksz);
if(blksz >= size) { // 找到符合要求的块
blk = malloc(size+10);
if(blk == NULL) return NULL;
if(blksz - size > 10) { // 分裂块
lseek(fd, ptr+size, SEEK_SET);
write(fd, buf, 8);
blksz -= size;
putle16(buf, blksz);
write(fd, buf, 2);
putle64(buf, ptr+size);
}
putle64(blk, ptr);
putle16(blk+8, size);
blk += 10;
if(lseek(fd, prev_ptr, SEEK_SET) < 0) return NULL;
if(write(fd, buf, 8) != 8) return NULL; // 从空闲块链表移除本块
return blk;
}
if(prev_prev_ptr && ptr < prev_ptr) { // 不符合顺序,进行一次调整
lseek(fd, prev_prev_ptr, SEEK_SET);
putle64(buf, ptr);
if(write(fd, buf, 8) != 8) return NULL; // 1->next = 3
if(lseek(fd, ptr, SEEK_SET) < 0) return NULL;
prev_prev_ptr = ptr; // new1 = 3
readle64(fd, ptr); // ptr(new3) = 3->next
lseek(fd, -8, SEEK_SET);
putle64(buf, prev_ptr); // new2 = 2
if(write(fd, buf, 8) != 8) return NULL; // 3->next = 2
lseek(fd, prev_ptr, SEEK_SET);
putle64(buf, ptr);
if(write(fd, buf, 8) != 8) return NULL; // 2->next = ptr
continue;
}
prev_prev_ptr = prev_ptr;
prev_ptr = ptr;
if(lseek(fd, ptr, SEEK_SET) < 0) return NULL;
readle64(fd, ptr);
}
ptr = lseek(fd, 0, SEEK_END);
if(ptr < 0) return NULL;
if(ptr%PAGESZ) { // 文件没有页对齐
errno = ESPIPE;
return NULL;
}
if(write(fd, nullpage, PAGESZ) != PAGESZ) return NULL;
if(PAGESZ-size > 10) { // 回收冗余
if(lseek(fd, prev_ptr, SEEK_SET) < 0) return NULL;
putle64(buf, ptr+size);
if(write(fd, buf, 8) != 8) return NULL;
if(lseek(fd, ptr+size+8, SEEK_SET) < 0) return NULL;
putle16(buf, PAGESZ - size);
if(write(fd, buf, 2) != 2) return NULL;
}
blk = malloc(size+10);
if(blk == NULL) return NULL;
putle64(blk, ptr);
putle16(blk+8, size);
return blk+10;
}
int sync_block(int fd, void* blk) {
uint64_t off = le64(blk-10);
uint16_t size = le16(blk-2);
if(size > PAGESZ) {
errno = EFBIG;
return EOF;
}
if(lseek(fd, off, SEEK_SET) < 0) return EOF;
return write(fd, blk, size) != size;
}
int unmount_block(int fd, void* blk) {
int r = sync_block(fd, blk);
free(blk-10);
return r;
}
int free_block(int fd, void* blk) {
uint64_t ptr = 8, prev_ptr = 0, prev_prev_ptr = 0, off = le64(blk-10);
uint8_t buf[8];
uint16_t size = le16(blk-2), sz;
while(ptr && ptr < off) {
if(prev_ptr == ptr) return EOF;
if(prev_prev_ptr && ptr < prev_ptr) { // 不符合顺序,进行一次调整
lseek(fd, prev_prev_ptr, SEEK_SET);
putle64(buf, ptr);
if(write(fd, buf, 8) != 8) return EOF; // 1->next = 3
if(lseek(fd, ptr, SEEK_SET) < 0) return EOF;
prev_prev_ptr = ptr; // new1 = 3
readle64(fd, ptr); // ptr(new3) = 3->next
lseek(fd, -8, SEEK_SET);
putle64(buf, prev_ptr); // new2 = 2
if(write(fd, buf, 8) != 8) return EOF; // 3->next = 2
lseek(fd, prev_ptr, SEEK_SET);
putle64(buf, ptr);
if(write(fd, buf, 8) != 8) return EOF; // 2->next = ptr
continue;
}
prev_prev_ptr = prev_ptr;
prev_ptr = ptr;
if(lseek(fd, ptr, SEEK_SET) < 0) return EOF;
readle64(fd, ptr);
}
putle64(blk, ptr);
putle16(blk+8, size);
putle64(buf, off);
lseek(fd, prev_ptr, SEEK_SET);
if(write(fd, buf, 8) != 8) return EOF; // 将本页附加到链表
readle16(fd, sz);
if(prev_ptr+sz == off && prev_ptr%PAGESZ < off%PAGESZ) { // 可以和前一块合并
lseek(fd, prev_ptr, SEEK_SET);
write(fd, blk, 8);
putle16(buf, size+sz);
write(fd, buf, 2);
free(blk-10);
return 0;
}
if(off+size == ptr && off%PAGESZ < ptr%PAGESZ) { // 可以和后一块合并
if(lseek(fd, ptr, SEEK_SET) < 0) return EOF;
readle64(fd, prev_ptr);
readle16(fd, sz);
putle64(blk, prev_ptr);
putle16(blk, size+sz);
}
sync_block(fd, blk);
free(blk-10);
return 0;
}

View File

@@ -1,6 +1,8 @@
cmake_minimum_required(VERSION 3.0.0)
project(fumidb_test VERSION 1.0)
add_executable(binary_test binary_test.c)
add_executable(binary_test binary_test.c)
add_executable(page_test page_test.c ../src/page.c ../src/file.c)
add_test(test_binary binary_test COMMAND binary_test)
add_test(test_binary binary_test COMMAND binary_test)
add_test(test_page page_test COMMAND page_test)

191
tests/page_test.c Normal file
View File

@@ -0,0 +1,191 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "../include/binary.h"
#include "../include/file.h"
#include "../include/page.h"
void* pages[16];
uint8_t nullpage[PAGESZ];
int main() {
int fd = open("page_test_tmp.bin", O_RDWR | O_CREAT | O_TRUNC, 0644);
if(fd < 0) {
perror("create");
return 1;
}
if(init_file_header_page(fd) < 0) return 2;
for(int i = 0; i < 16; i++) {
void* page = alloc_page(fd);
if(page == NULL) {
perror("alloc_page");
return 3;
}
pages[i] = page;
}
puts("free!");
free_page(fd, pages[15]);
if(get_first_unused_block(fd) != 16*PAGESZ) return 5;
free_page(fd, pages[12]);
if(get_first_unused_block(fd) != 13*PAGESZ) return 6;
free_page(fd, pages[1]);
if(get_first_unused_block(fd) != 2*PAGESZ) return 7;
free_page(fd, pages[10]);
if(get_first_unused_block(fd) != 2*PAGESZ) return 8;
free_page(fd, pages[9]);
if(get_first_unused_block(fd) != 2*PAGESZ) return 8;
pages[1] = alloc_page(fd);
if(le64(pages[1]-8) != (uint64_t)(2*PAGESZ)) {
printf("1: %016llx != %016llx\n", le64(pages[1]-8), (uint64_t)(2*PAGESZ));
return 9;
}
pages[9] = alloc_page(fd);
if(le64(pages[9]-8) != (uint64_t)(10*PAGESZ)) {
printf("9: %016llx != %016llx\n", le64(pages[9]-8), (uint64_t)(11*PAGESZ));
return 10;
}
pages[10] = alloc_page(fd);
if(le64(pages[10]-8) != (uint64_t)(11*PAGESZ)) {
printf("10: %016llx != %016llx\n", le64(pages[10]-8), (uint64_t)(11*PAGESZ));
return 11;
}
pages[12] = alloc_page(fd);
if(le64(pages[12]-8) != (uint64_t)(13*PAGESZ)) return 12;
pages[15] = alloc_page(fd);
if(le64(pages[15]-8) != (uint64_t)(16*PAGESZ)) return 13;
for(int i = 0; i < 16; i++) {
if(free_page(fd, pages[i])) {
perror("free_page");
return 14;
}
}
close(fd);
fd = open("page_test_tmp.bin", O_RDWR, 0644);
if(fd < 0) {
perror("open");
return 15;
}
uint8_t* blk1 = alloc_block(fd, 40);
uint8_t* blk2 = alloc_block(fd, 22);
uint8_t* blk3 = alloc_block(fd, 33);
uint8_t* blk4 = alloc_block(fd, 4095);
memcpy(blk1, "hello world!", 13);
sync_block(fd, blk1);
lseek(fd, PAGESZ, SEEK_SET);
read(fd, blk2, 13);
if(strcmp((const char *)blk2, (const char *)blk1)) {
return 16;
}
sync_block(fd, blk2);
lseek(fd, PAGESZ+40, SEEK_SET);
read(fd, blk3, 13);
if(strcmp((const char *)blk3, (const char *)blk1)) {
return 17;
}
sync_block(fd, blk3);
lseek(fd, PAGESZ+40+22, SEEK_SET);
read(fd, blk4+222, 13);
sync_block(fd, blk4);
if(strcmp((const char *)&blk4[222], (const char *)blk1)) {
return 18;
}
memset(blk1, 0, 40);
lseek(fd, PAGESZ*2+222, SEEK_SET);
read(fd, blk1, 13);
if(strcmp((const char *)blk1, (const char *)blk2)) {
return 19;
}
if(free_block(fd, blk1)) {
perror("free_block(fd, blk1)");
return 20;
}
if(free_block(fd, blk2)) {
perror("free_block(fd, blk2)");
return 21;
}
if(free_block(fd, blk3)) {
perror("free_block(fd, blk3)");
return 22;
}
if(free_block(fd, blk4)) {
perror("free_block(fd, blk4)");
return 23;
}
blk1 = alloc_block(fd, 40+22+33);
memcpy(blk1+44, "hello world!", 13);
sync_block(fd, blk1);
lseek(fd, PAGESZ+44, SEEK_SET);
char buf[13];
read(fd, buf, 13);
if(strcmp((const char *)&blk1[44], (const char *)buf)) {
return 24;
}
close(fd);
fd = open("page_test_tmp.bin", O_RDWR | O_CREAT | O_TRUNC, 0644);
if(fd < 0) {
perror("create");
return 25;
}
if(init_file_header_page(fd) < 0) return 26;
blk1 = alloc_block(fd, 40);
blk2 = alloc_block(fd, 22);
blk3 = alloc_block(fd, 33);
blk4 = alloc_block(fd, 4095);
memcpy(blk1, "hello world!", 13);
sync_block(fd, blk1);
lseek(fd, PAGESZ, SEEK_SET);
read(fd, blk2, 13);
if(strcmp((const char *)blk2, (const char *)blk1)) {
return 16;
}
sync_block(fd, blk2);
lseek(fd, PAGESZ+40, SEEK_SET);
read(fd, blk3, 13);
if(strcmp((const char *)blk3, (const char *)blk1)) {
return 17;
}
sync_block(fd, blk3);
lseek(fd, PAGESZ+40+22, SEEK_SET);
read(fd, blk4+222, 13);
sync_block(fd, blk4);
if(strcmp((const char *)&blk4[222], (const char *)blk1)) {
return 18;
}
memset(blk1, 0, 40);
lseek(fd, PAGESZ*2+222, SEEK_SET);
read(fd, blk1, 13);
if(strcmp((const char *)blk1, (const char *)blk2)) {
return 19;
}
if(free_block(fd, blk1)) {
perror("free_block(fd, blk1)");
return 20;
}
if(free_block(fd, blk2)) {
perror("free_block(fd, blk2)");
return 21;
}
if(free_block(fd, blk3)) {
perror("free_block(fd, blk3)");
return 22;
}
if(free_block(fd, blk4)) {
perror("free_block(fd, blk4)");
return 23;
}
blk1 = alloc_block(fd, 40+22+33);
memcpy(blk1+44, "hello world!", 13);
sync_block(fd, blk1);
lseek(fd, PAGESZ+44, SEEK_SET);
memset(buf, 0, 13);
read(fd, buf, 13);
if(strcmp((const char *)&blk1[44], (const char *)buf)) {
return 24;
}
close(fd);
remove("page_test_tmp.bin");
return 0;
}