1
0
mirror of https://github.com/fumiama/fumidb.git synced 2026-06-06 17:20:33 +08:00
Files
fumidb/src/page.c
2022-05-03 23:45:45 +08:00

350 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// page.c
// 管理文件中的空闲块
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "../include/binary.h"
#include "../include/page.h"
static const uint8_t nullpage[PAGESZ];
void* alloc_page(int fd, void* page) {
uint64_t ptr = 8, prev_ptr = 0, prev_prev_ptr = 0;
uint8_t buf[8];
if(page == NULL) return NULL;
// 对于 page只关心位于第一页 8~15 字节的 ptr of unused blk
while(ptr) {
if(unlikely(ptr == prev_ptr)) { // 文件损坏
errno = ESPIPE;
return NULL;
}
if(!(ptr%PAGESZ)) { // 找到符合要求的页
if(lseek(fd, ptr, SEEK_SET) < 0) return NULL;
if(read(fd, buf, 8) != 8) 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 && ptr != 8) { // 不符合顺序,进行一次调整
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((int)ptr < 0) return NULL;
if(ptr%PAGESZ) { // 文件没有页对齐
errno = ESPIPE;
return NULL;
}
if(write(fd, nullpage, PAGESZ) != PAGESZ) return NULL;
putle64(page, ptr);
return page+8;
}
void* get_page(int fd, uint64_t ptr, void* page) {
if(page == NULL) return NULL;
if(ptr%PAGESZ) return NULL;
if(lseek(fd, ptr, SEEK_SET) < 0) return NULL;
putle64(page, ptr);
page += 8;
if(read(fd, page, PAGESZ) != PAGESZ) return NULL;
return page;
}
int sync_page(int fd, void* page) {
if(page == NULL) return EOF;
uint64_t ptr = le64(page-8);
if(lseek(fd, ptr, SEEK_SET) < 0) return EOF;
return write(fd, page, PAGESZ) != PAGESZ;
}
int free_page(int fd, void* page) {
if(page == NULL) return EOF;
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(unlikely(ptr == prev_ptr)) { // 文件损坏
errno = ESPIPE;
return EOF;
}
if(prev_prev_ptr && ptr < prev_ptr && ptr != 8) { // 不符合顺序,进行一次调整
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(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);
return 0;
}
void* alloc_block(int fd, uint16_t size, void* blk) {
uint64_t ptr = 8, prev_ptr = 0, prev_prev_ptr = 0;
uint8_t buf[8];
uint16_t blksz;
if(unlikely(blk == NULL)) {
errno = EINVAL;
return NULL;
}
if(unlikely(size > PAGESZ)) {
errno = EFBIG;
return NULL;
}
// 对于 page只关心位于第一页 8~15 字节的 ptr of unused blk
while(ptr) {
if(unlikely(lseek(fd, ptr, SEEK_SET) < 0)) return NULL;
if(unlikely(read(fd, buf, 8) != 8)) {
errno = ENOSR;
return NULL;
}
if(unlikely(ptr == prev_ptr)) { // 文件损坏
errno = ESPIPE;
return NULL;
}
if(ptr == 8) blksz = 0;
else readle16(fd, blksz);
#ifdef DEBUG
printf("ptr: %016llx, blksize: %d\n", ptr, blksz);
#endif
if(blksz >= size) { // 找到符合要求的块
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);
#ifdef DEBUG
printf("find match: ptr: %016llx, size: %d\n", ptr, size);
#endif
blk += 10;
if(lseek(fd, prev_ptr, SEEK_SET) < 0) return NULL;
if(write(fd, buf, 8) != 8) { // 从空闲块链表移除本块
errno = ENOSR;
return NULL;
}
return blk;
}
if(prev_prev_ptr && ptr < prev_ptr && ptr != 8) { // 不符合顺序,进行一次调整
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((int)ptr < 0) return NULL;
if(ptr%PAGESZ) { // 文件没有页对齐
errno = ESPIPE;
return NULL;
}
if(write(fd, nullpage, PAGESZ) != PAGESZ) {
errno = ENOSR;
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;
}
putle64(blk, ptr);
putle16(blk+8, size);
return blk+10;
}
void* get_block(int fd, uint16_t size, uint64_t ptr, void* blk) {
if(blk == NULL) return NULL;
if(lseek(fd, ptr, SEEK_SET) < 0) return NULL;
putle64(blk, ptr);
putle16(blk+8, size);
blk += 10;
if(read(fd, blk, size) != size) return NULL;
return blk;
}
int sync_block(int fd, void* blk) {
if(blk == NULL) return EOF;
uint64_t off = le64(blk-10);
uint16_t size = le16(blk-2);
if(size > PAGESZ) {
errno = EFBIG;
return EOF;
}
#ifdef DEBUG
printf("off: %016llx, size: %d\n", off, size);
#endif
if(lseek(fd, off, SEEK_SET) < 0) return EOF;
return write(fd, blk, size) != size;
}
int free_block(int fd, void* blk) {
if(blk == NULL) return EOF;
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(unlikely(ptr == prev_ptr)) { // 文件损坏
errno = ESPIPE;
return EOF;
}
if(prev_prev_ptr && ptr < prev_ptr && ptr != 8) { // 不符合顺序,进行一次调整
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);
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);
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(unlikely(ptr == prev_ptr)) { // 文件损坏
errno = ESPIPE;
return EOF;
}
if(prev_prev_ptr && ptr < prev_ptr && ptr != 8) { // 不符合顺序,进行一次调整
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;
}