mirror of
https://github.com/fumiama/fumidb.git
synced 2026-06-05 00:32:44 +08:00
add page
This commit is contained in:
@@ -8,7 +8,8 @@ if(${isBigEndian})
|
||||
add_definitions(-DWORDS_BIGENDIAN)
|
||||
endif()
|
||||
|
||||
option(BUILD_TEST "Whether to build tests" OFF)
|
||||
include(option.txt)
|
||||
|
||||
if(${BUILD_TEST})
|
||||
message(STATUS "Building tests...")
|
||||
enable_testing()
|
||||
|
||||
@@ -13,5 +13,8 @@ Most part of this README and the docs in `api` folder is written in Chinese. If
|
||||
- [ ] 按索引[删除表项](/api/table.md#表项的删除)
|
||||
- [ ] 对非主键(无[unique约束](/api/types.md#类型修饰符))进行[索引](/api/index.md)
|
||||
|
||||
## 关于并发
|
||||
不支持并发,如需要并发,请自行加锁以免数据损坏。
|
||||
|
||||
## Thanks
|
||||
- [asciiflow](https://asciiflow.com/)
|
||||
@@ -34,7 +34,7 @@
|
||||
#### 新建
|
||||
空闲块不会被主动新建,而是源于分配时富余的部分以及删除后的剩余。
|
||||
#### 合并
|
||||
受限于记录长度的数字为uint16,一块未被使用的空闲空间大小最大为`65535`,一般则不使其超过`32768`。如果确有连续的超过`32768`字节的空闲,应当划分为多个块。特别地,如果确有连续的超过`32768`字节的空闲且其后的空间不足`4096`字节,应当适当减小前一块的大小,使后一块大小超过`4096`字节。
|
||||
受限于记录长度的数字为uint16,一块未被使用的空闲空间大小最大为`65535`,实际使用时不使其超过`4096`。如果确有连续的超过`4096`字节的空闲,应当划分为多个块。块应当是`4k`对齐的。
|
||||
#### 使用
|
||||
使用时优先从第一个块遍历,比较其大小以及页对齐是否符合要求。当使用后仍有剩余,对于小于10字节的块,直接舍弃不用;否则更新块大小与相关链表指针。
|
||||
### 表
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#ifndef _BINARY_H_
|
||||
#define _BINARY_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@@ -48,19 +51,53 @@
|
||||
#define putle16(buf, x) (*(uint16_t*)(buf) = _byteswap_ushort((uint16_t)(x)))
|
||||
#define putle32(buf, x) (*(uint32_t*)(buf) = _byteswap_ulong((uint32_t)(x)))
|
||||
#define putle64(buf, x) (*(uint64_t*)(buf) = _byteswap_uint64((uint64_t)(x)))
|
||||
|
||||
#define readle16(fd, num) ((~read((fd), &(num), 2))?((num)=_byteswap_ushort((uint16_t)(num))):EOF)
|
||||
#define readle32(fd, num) ((~read((fd), &(num), 4))?((num)=_byteswap_ulong((uint32_t)(num))):EOF)
|
||||
#define readle64(fd, num) ((~read((fd), &(num), 8))?((num)=_byteswap_uint64((uint64_t)(num))):EOF)
|
||||
|
||||
#define le16(buf) _byteswap_ushort(*(uint16_t*)(buf))
|
||||
#define le32(buf) _byteswap_ulong(*(uint32_t*)(buf))
|
||||
#define le64(buf) _byteswap_uint64(*(uint64_t*)(buf))
|
||||
#else
|
||||
#define putle16(buf, x) (*(uint16_t*)(buf) = (uint16_t)(x))
|
||||
#define putle32(buf, x) (*(uint32_t*)(buf) = (uint32_t)(x))
|
||||
#define putle64(buf, x) (*(uint64_t*)(buf) = (uint64_t)(x))
|
||||
|
||||
#define readle16(fd, num) read((fd), &(num), 2)
|
||||
#define readle32(fd, num) read((fd), &(num), 4)
|
||||
#define readle64(fd, num) read((fd), &(num), 8)
|
||||
|
||||
#define le16(buf) (*(uint16_t*)(buf))
|
||||
#define le32(buf) (*(uint32_t*)(buf))
|
||||
#define le64(buf) (*(uint64_t*)(buf))
|
||||
#endif
|
||||
#else
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define putle16(buf, x) (*(uint16_t*)(buf) = __builtin_bswap16((uint16_t)(x)))
|
||||
#define putle32(buf, x) (*(uint32_t*)(buf) = __builtin_bswap32((uint32_t)(x)))
|
||||
#define putle64(buf, x) (*(uint64_t*)(buf) = __builtin_bswap64((uint64_t)(x)))
|
||||
|
||||
#define readle16(fd, num) ((~read((fd), &(num), 2))?((num)=__builtin_bswap16((uint16_t)(num))):EOF)
|
||||
#define readle32(fd, num) ((~read((fd), &(num), 4))?((num)=__builtin_bswap32((uint32_t)(num))):EOF)
|
||||
#define readle64(fd, num) ((~read((fd), &(num), 8))?((num)=__builtin_bswap64((uint64_t)(num))):EOF)
|
||||
|
||||
#define le16(buf) __builtin_bswap16(*(uint16_t*)(buf))
|
||||
#define le32(buf) __builtin_bswap32(*(uint32_t*)(buf))
|
||||
#define le64(buf) __builtin_bswap64(*(uint64_t*)(buf))
|
||||
#else
|
||||
#define putle16(buf, x) (*(uint16_t*)(buf) = (uint16_t)(x))
|
||||
#define putle32(buf, x) (*(uint32_t*)(buf) = (uint32_t)(x))
|
||||
#define putle64(buf, x) (*(uint64_t*)(buf) = (uint64_t)(x))
|
||||
|
||||
#define readle16(fd, num) read((fd), &(num), 2)
|
||||
#define readle32(fd, num) read((fd), &(num), 4)
|
||||
#define readle64(fd, num) read((fd), &(num), 8)
|
||||
|
||||
#define le16(buf) (*(uint16_t*)(buf))
|
||||
#define le32(buf) (*(uint32_t*)(buf))
|
||||
#define le64(buf) (*(uint64_t*)(buf))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
33
include/page.h
Normal file
33
include/page.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef _PAGE_H_
|
||||
#define _PAGE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef PAGESZ
|
||||
#define PAGESZ 4096
|
||||
#endif
|
||||
|
||||
// 获取文件中的第一个空闲页,并将其 mmap 到内存
|
||||
// 如果现有空闲均无整页,则新分配一页
|
||||
// 返回:
|
||||
// EOF 错误
|
||||
void* alloc_page(int fd);
|
||||
|
||||
// 释放分配的页,将其标记为空闲以备使用
|
||||
// 返回:
|
||||
// EOF 错误
|
||||
int free_page(int fd, void* page);
|
||||
|
||||
// 获取文件中的第一个满足 size 大小的块
|
||||
// 返回:
|
||||
// EOF 错误
|
||||
void* alloc_block(int fd, size_t size);
|
||||
|
||||
// 释放块,并将其标记为空闲以备使用
|
||||
// 值得注意的是,只有在本页最后一块
|
||||
// 也被释放后,这一页才会被真正释放
|
||||
// 返回:
|
||||
// EOF 错误
|
||||
int free_block(int fd, void* page);
|
||||
|
||||
#endif
|
||||
1
option.txt
Normal file
1
option.txt
Normal file
@@ -0,0 +1 @@
|
||||
option(BUILD_TEST "Whether to build tests" OFF)
|
||||
38
src/page.c
Normal file
38
src/page.c
Normal file
@@ -0,0 +1,38 @@
|
||||
// page.c
|
||||
// 管理文件中的空闲块
|
||||
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "../include/binary.h"
|
||||
#include "../include/page.h"
|
||||
|
||||
uint8_t nullpage[PAGESZ];
|
||||
|
||||
void* alloc_page(int fd) {
|
||||
uint64_t ptr, prev_ptr = 8;
|
||||
void* page;
|
||||
if(lseek(fd, 8, SEEK_SET) < 0) return EOF;
|
||||
// 对于 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); // 从空闲块链表移除本块
|
||||
return page;
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -1,12 +1,41 @@
|
||||
#include "../src/binary.h"
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "../include/binary.h"
|
||||
|
||||
int main() {
|
||||
char buf[8];
|
||||
unsigned char buf[8];
|
||||
putle16(buf, 1);
|
||||
if(buf[0] != 1) return 1;
|
||||
putle32(buf, 2);
|
||||
if(buf[0] != 2) return 2;
|
||||
putle64(buf, 3);
|
||||
if(buf[0] != 3) return 3;
|
||||
if(buf[0] != 1 || le16(buf) != 0x01) return 1;
|
||||
putle32(buf+1, 2);
|
||||
if(buf[1] != 2 || le32(buf+1) != 0x02) return 2;
|
||||
putle64(buf, 0xff0000);
|
||||
if(buf[2] != 0xff || le64(buf) != 0xff0000) return 3;
|
||||
|
||||
int fd = open("binary_test_tmp.bin", O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if(fd < 0) {
|
||||
perror("create");
|
||||
return 4;
|
||||
}
|
||||
write(fd, "\001\002\003\004\005\006\a\b", 8);
|
||||
close(fd);
|
||||
fd = open("binary_test_tmp.bin", O_RDONLY | O_NONBLOCK);
|
||||
if(fd < 0) {
|
||||
perror("open");
|
||||
return 5;
|
||||
}
|
||||
uint64_t ptr = 0;
|
||||
readle16(fd, ptr);
|
||||
printf("%04x\n", (uint16_t)ptr);
|
||||
if((uint16_t)ptr != 0x0201) return 6;
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
readle32(fd, ptr);
|
||||
printf("%08x\n", (uint32_t)ptr);
|
||||
if((uint32_t)ptr != 0x04030201) return 7;
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
readle64(fd, ptr);
|
||||
printf("%016llx\n", (uint64_t)ptr);
|
||||
if((uint64_t)ptr != 0x0807060504030201) return 8;
|
||||
close(fd);
|
||||
remove("binary_test_tmp.bin");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user