diff --git a/include/page.h b/include/page.h index 9b1e7b9..bdafa50 100644 --- a/include/page.h +++ b/include/page.h @@ -7,20 +7,23 @@ #define PAGESZ 4096 #endif -// 获取文件中的第一个空闲页,并将其读到内存 +// 获取文件中的第一个空闲页,并将其读到 buf +// buf 的大小为 PAGESZ+8 = 4104 // 如果现有空闲均无整页,则新分配一页 -// 返回指针的 -8 字节记录了本页在文件的偏移 -// 因此实际上分配了 PAGESZ+8 的空间 +// 返回指针 page = buf+8 +// 其 -8 字节记录了本页在文件的偏移 +// 以备释放之用 // 返回: // NULL 错误,参见 errno // page 指针 -void* alloc_page(int fd); +void* alloc_page(int fd, void* buf); // 获取 ptr 处的页 +// buf 的大小为 PAGESZ+8 = 4104 // 返回: // NULL 错误,参见 errno // page 指针 -void* get_page(int fd, uint64_t ptr); +void* get_page(int fd, uint64_t ptr, void* buf); // 刷新一页 // 返回: @@ -28,12 +31,6 @@ void* get_page(int fd, uint64_t ptr); // 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); - // 释放分配的页,将其标记为空闲以备使用 // 同时将数据刷新到文件 // 返回: @@ -42,32 +39,29 @@ int unmount_page(int fd, void* page); int free_page(int fd, void* page); // 获取文件中的第一个满足 size 大小的块的位置 -// 返回的块大小一定是 size,实际上为 size + 8 + 2 +// 返回的块 blk = buf + 10 +// len(buf) >= size + 8 + 2 // 开头的 8+2 字节记录了真正的块位置与大小以备释放 // 返回的 ptr 已经跳过这 10 个字节 // 返回: // NULL 错误,参见 errno // blk 指针 -void* alloc_block(int fd, uint16_t size); +void* alloc_block(int fd, uint16_t size, void* buf); // 获取 ptr 处的块 +// 返回的块 blk = buf + 10 +// len(buf) >= size + 8 + 2 // 返回: // NULL 错误,参见 errno // blk 指针 -void* get_block(int fd, uint16_t size, uint64_t ptr); +void* get_block(int fd, uint16_t size, uint64_t ptr, void* buf); // 刷新 block 到文件 // 返回: // EOF lseek 错误或 size 过大,参见 errno -// 0/1 write size != PAGESZ +// 0/1 write size != real size 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 // 将会被合并 @@ -76,4 +70,10 @@ int unmount_block(int fd, void* blk); // 0 成功 int free_block(int fd, void* blk); +// 将 ptr 处的块纳入空闲块链表 +// 返回: +// EOF lseek 错误或 size 过大,参见 errno +// 0/1 write size != real size +int add_block(int fd, uint16_t size, uint64_t ptr); + #endif \ No newline at end of file diff --git a/include/types.h b/include/types.h index 231737e..65b00c7 100644 --- a/include/types.h +++ b/include/types.h @@ -23,11 +23,11 @@ typedef uint64_t key_t; // 为类型 type 创建索引 // 返回:索引头节点的指针 index -void* create_index(int fd, type_t t); +void* create_index(int fd, type_t t, void* buf); // 加载类型 type 的索引 // 返回:索引头节点的指针 index -void* load_index(int fd, type_t t, uint64_t ptr); +void* load_index(int fd, type_t t, uint64_t ptr, void* buf); // 插入一条索引 int insert_item(int fd, type_t t, void* index, key_t k, uint64_t ptr); diff --git a/include/types/int8.h b/include/types/int8.h index cc5076c..ca449ed 100644 --- a/include/types/int8.h +++ b/include/types/int8.h @@ -1,13 +1,16 @@ #ifndef _TYPE_INT8_H_ #define _TYPE_INT8_H_ +#include #include "../types.h" #define INT8_INDEX_SZ (256*8) -void* create_int8_index(int fd); +// len(buf) >= INT8_INDEX_SZ+10 +void* create_int8_index(int fd, void* buf); -void* load_int8_index(int fd, uint64_t ptr); +// len(buf) >= INT8_INDEX_SZ+10 +void* load_int8_index(int fd, uint64_t ptr, void* buf); int insert_int8_item(int fd, void* index, key_t k, uint64_t ptr); diff --git a/src/file.c b/src/file.c index e359dab..ed97b95 100644 --- a/src/file.c +++ b/src/file.c @@ -13,12 +13,7 @@ int init_file_header_page(int fd) { lseek(fd, 0, SEEK_SET); if(write(fd, header, PAGESZ) != PAGESZ) return 1; // 将头的 HEADERSZ 字节之后的空间纳入空闲块 - if(lseek(fd, 8, SEEK_SET) < 0) return EOF; - putle64(buf, HEADERSZ); - if(write(fd, buf, 8) != 8) return 1; - if(lseek(fd, HEADERSZ+8, SEEK_SET) < 0) return EOF; - putle16(buf, PAGESZ - HEADERSZ); - return write(fd, buf, 2) != 2; + return add_block(fd, PAGESZ-HEADERSZ, HEADERSZ); } uint16_t get_db_version(int fd) { diff --git a/src/page.c b/src/page.c index 8c5fa11..8639c9a 100644 --- a/src/page.c +++ b/src/page.c @@ -2,7 +2,6 @@ // 管理文件中的空闲块 #include -#include #include #include #include @@ -12,17 +11,14 @@ static const uint8_t nullpage[PAGESZ]; -void* alloc_page(int fd) { +void* alloc_page(int fd, void* page) { uint64_t ptr = 8, prev_ptr = 0, prev_prev_ptr = 0; - void* page; uint8_t buf[8]; // 对于 page,只关心位于第一页 8~15 字节的 ptr of unused blk while(ptr) { if(!(ptr%PAGESZ)) { // 找到符合要求的页 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; @@ -56,23 +52,16 @@ void* alloc_page(int fd) { 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; } -void* get_page(int fd, uint64_t ptr) { +void* get_page(int fd, uint64_t ptr, void* page) { if(ptr%PAGESZ) return NULL; if(lseek(fd, ptr, SEEK_SET) < 0) return NULL; - void* page = malloc(PAGESZ+8); - if(page == NULL) return NULL; putle64(page, ptr); page += 8; - if(read(fd, page, PAGESZ) != PAGESZ) { - free(page-8); - return NULL; - } + if(read(fd, page, PAGESZ) != PAGESZ) return NULL; return page; } @@ -82,12 +71,6 @@ int sync_page(int fd, void* page) { 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]; @@ -119,13 +102,11 @@ int free_page(int fd, void* page) { 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) { +void* alloc_block(int fd, uint16_t size, void* blk) { uint64_t ptr = 8, prev_ptr = 0, prev_prev_ptr = 0; - void* blk; uint8_t buf[8]; uint16_t blksz; @@ -136,8 +117,6 @@ void* alloc_block(int fd, uint16_t size) { 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); @@ -188,24 +167,17 @@ void* alloc_block(int fd, uint16_t size) { 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; } -void* get_block(int fd, uint16_t size, uint64_t ptr) { +void* get_block(int fd, uint16_t size, uint64_t ptr, void* blk) { if(lseek(fd, ptr, SEEK_SET) < 0) return NULL; - void* blk = malloc(size+10); - if(blk == NULL) return NULL; putle64(blk, ptr); putle16(blk+8, size); blk += 10; - if(read(fd, blk, size) != size) { - free(blk); - return NULL; - } + if(read(fd, blk, size) != size) return NULL; return blk; } @@ -220,12 +192,6 @@ int sync_block(int fd, void* blk) { 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]; @@ -263,7 +229,6 @@ int free_block(int fd, void* blk) { 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) { // 可以和后一块合并 @@ -274,6 +239,61 @@ int free_block(int fd, void* blk) { putle16(blk, size+sz); } sync_block(fd, blk); - free(blk-10); + return 0; +} + +int add_block(int fd, uint16_t size, uint64_t off) { + uint64_t ptr = 8, prev_ptr = 0, prev_prev_ptr = 0; + uint8_t buf[8]; + uint16_t 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); + } + if(lseek(fd, off, SEEK_SET) < 0) return EOF; + putle64(buf, ptr); + write(fd, buf, 8); + putle16(buf, size); + write(fd, buf, 2); + lseek(fd, prev_ptr, SEEK_SET); + putle64(buf, off); + 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); + putle64(buf, ptr); + write(fd, buf, 8); + putle16(buf, size+sz); + write(fd, buf, 2); + 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); + lseek(fd, off, SEEK_SET); + putle64(buf, prev_ptr); + write(fd, buf, 8); + putle16(buf, size+sz); + write(fd, buf, 2); + } return 0; } diff --git a/src/types.c b/src/types.c index 0220abc..2729b77 100644 --- a/src/types.c +++ b/src/types.c @@ -2,9 +2,9 @@ #include "../include/types/int8.h" // ptr = init(fd) -typedef void* (*_type_init_t)(int); +typedef void* (*_type_init_t)(int, void*); // ptr = load(fd, ptr) -typedef void* (*_type_load_t)(int, uint64_t); +typedef void* (*_type_load_t)(int, uint64_t, void*); // ret = insert_item(fd, index, k, ptr) typedef int (*_insert_item_t)(int, void*, key_t, uint64_t); // ptr = find_by_key(fd, index, k) @@ -13,13 +13,13 @@ typedef uint64_t (*_find_by_key_t)(int, void*, key_t); typedef int (*_remove_by_key_t)(int, void*, key_t); // Function not implemented -static void* create_not_impl_index(int fd) { +static void* create_not_impl_index(int fd, void* buf) { errno = ENOSYS; return 0; } // Function not implemented -static void* load_not_impl_index(int fd, uint64_t ptr) { +static void* load_not_impl_index(int fd, uint64_t ptr, void* buf) { errno = ENOSYS; return 0; } @@ -92,12 +92,12 @@ static _remove_by_key_t _remove_item_by_key[] = { remove_item_by_not_impl_key }; -void* create_index(int fd, type_t t) { - return _types_init[t&7](fd); +void* create_index(int fd, type_t t, void* buf) { + return _types_init[t&7](fd, buf); } -void* load_index(int fd, type_t t, uint64_t ptr) { - return _types_load[t&7](fd, ptr); +void* load_index(int fd, type_t t, uint64_t ptr, void* buf) { + return _types_load[t&7](fd, ptr, buf); } int insert_item(int fd, type_t t, void* index, key_t k, uint64_t ptr) { diff --git a/src/types/int8.c b/src/types/int8.c index cfd98e9..b770676 100644 --- a/src/types/int8.c +++ b/src/types/int8.c @@ -4,16 +4,16 @@ #include "../../include/page.h" #include "../../include/types/int8.h" -void* create_int8_index(int fd) { - uint64_t* blk = alloc_block(fd, INT8_INDEX_SZ); +void* create_int8_index(int fd, void* buf) { + uint64_t* blk = alloc_block(fd, INT8_INDEX_SZ, buf); if(blk == NULL) return 0; memset(blk, 0, INT8_INDEX_SZ); sync_block(fd, blk); return blk; } -void* load_int8_index(int fd, uint64_t ptr) { - return get_block(fd, INT8_INDEX_SZ, ptr); +void* load_int8_index(int fd, uint64_t ptr, void* buf) { + return get_block(fd, INT8_INDEX_SZ, ptr, buf); } int insert_int8_item(int fd, void* index, key_t k, uint64_t ptr) { diff --git a/tests/page_test.c b/tests/page_test.c index 8f8b9c0..1f3c99e 100644 --- a/tests/page_test.c +++ b/tests/page_test.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,7 +7,8 @@ #include "../include/page.h" void* pages[16]; -uint8_t nullpage[PAGESZ]; +uint8_t zeropage[PAGESZ]; +uint8_t nullpages[16][PAGESZ+8]; static uint64_t get_second_unused_block(int fd) { uint64_t ptr = get_first_unused_block(fd); @@ -24,7 +26,7 @@ int main() { } if(init_file_header_page(fd) < 0) return 2; for(int i = 0; i < 16; i++) { - void* page = alloc_page(fd); + void* page = alloc_page(fd, nullpages[i]); if(page == NULL) { perror("alloc_page"); return 3; @@ -47,24 +49,24 @@ int main() { free_page(fd, pages[9]); if(get_second_unused_block(fd) != 2*PAGESZ) return 8; puts("free 9!"); - pages[1] = alloc_page(fd); + pages[1] = alloc_page(fd, nullpages[1]); 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); + pages[9] = alloc_page(fd, nullpages[9]); 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); + pages[10] = alloc_page(fd, nullpages[10]); 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); + pages[12] = alloc_page(fd, nullpages[12]); if(le64(pages[12]-8) != (uint64_t)(13*PAGESZ)) return 12; - pages[15] = alloc_page(fd); + pages[15] = alloc_page(fd, nullpages[15]); if(le64(pages[15]-8) != (uint64_t)(16*PAGESZ)) return 13; for(int i = 0; i < 16; i++) { if(free_page(fd, pages[i])) { @@ -79,10 +81,10 @@ int main() { 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); + uint8_t* blk1 = alloc_block(fd, 40, nullpages[0]); + uint8_t* blk2 = alloc_block(fd, 22, nullpages[1]); + uint8_t* blk3 = alloc_block(fd, 33, nullpages[2]); + uint8_t* blk4 = alloc_block(fd, 4095, nullpages[3]); memcpy(blk1, "hello world!", 13); sync_block(fd, blk1); lseek(fd, HEADERSZ, SEEK_SET); @@ -130,7 +132,7 @@ int main() { perror("free_block(fd, blk4)"); return 23; } - blk1 = alloc_block(fd, 40+22+33); + blk1 = alloc_block(fd, 40+22+33, nullpages[4]); memcpy(blk1+44, "hello world!", 13); sync_block(fd, blk1); lseek(fd, HEADERSZ+44, SEEK_SET); @@ -147,10 +149,10 @@ int main() { 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); + blk1 = alloc_block(fd, 40, nullpages[5]); + blk2 = alloc_block(fd, 22, nullpages[6]); + blk3 = alloc_block(fd, 33, nullpages[7]); + blk4 = alloc_block(fd, 4095, nullpages[8]); memcpy(blk1, "hello world!", 13); sync_block(fd, blk1); lseek(fd, HEADERSZ, SEEK_SET); @@ -193,7 +195,7 @@ int main() { perror("free_block(fd, blk4)"); return 23; } - blk1 = alloc_block(fd, 40+22+33); + blk1 = alloc_block(fd, 40+22+33, nullpages[9]); memcpy(blk1+44, "hello world!", 13); sync_block(fd, blk1); lseek(fd, HEADERSZ+44, SEEK_SET); diff --git a/tests/types_test.c b/tests/types_test.c index 7f16ccb..52b8f39 100644 --- a/tests/types_test.c +++ b/tests/types_test.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include "../include/binary.h" @@ -6,6 +8,8 @@ #include "../include/types.h" #include "../include/types/int8.h" +uint8_t int8buf[INT8_INDEX_SZ+10]; + int main() { /* test int8 */ int fd = open("types_test_tmp.bin", O_RDWR | O_CREAT | O_TRUNC, 0644); @@ -14,7 +18,7 @@ int main() { return 1; } if(init_file_header_page(fd) < 0) return 2; - void* index = create_index(fd, TYPE_INT8); + void* index = create_index(fd, TYPE_INT8, int8buf); if(!index) { perror("create_index"); return 3; @@ -38,11 +42,11 @@ int main() { if(find_item_by_key(fd, TYPE_INT8, index, 67) != 56787145) return 9; if(find_item_by_key(fd, TYPE_INT8, index, 123) != 123567854424) return 10; if(find_item_by_key(fd, TYPE_INT8, index, 255) != 0) return 11; - unmount_block(fd, index); index = NULL; close(fd); fd = open("types_test_tmp.bin", O_RDWR, 0644); - index = load_index(fd, TYPE_INT8, HEADERSZ); + memset(int8buf, 0, INT8_INDEX_SZ+10); + index = load_index(fd, TYPE_INT8, HEADERSZ, int8buf); if(find_item_by_key(fd, TYPE_INT8, index, 1) != 3456432) return 6; if(find_item_by_key(fd, TYPE_INT8, index, 3) != 7654323456) return 7; if(find_item_by_key(fd, TYPE_INT8, index, 45) != 345743415) return 8;