1
0
mirror of https://github.com/fumiama/fumidb.git synced 2026-06-05 00:32:44 +08:00
This commit is contained in:
源文雨
2022-05-01 01:19:38 +08:00
parent f4fad55ca4
commit 1463c1f606
8 changed files with 151 additions and 9 deletions

View File

@@ -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()

View File

@@ -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/)

View File

@@ -34,7 +34,7 @@
#### 新建
空闲块不会被主动新建,而是源于分配时富余的部分以及删除后的剩余。
#### 合并
受限于记录长度的数字为uint16一块未被使用的空闲空间大小最大为`65535`一般则不使其超过`32768`。如果确有连续的超过`32768`字节的空闲,应当划分为多个块。特别地,如果确有连续的超过`32768`字节的空闲且其后的空间不足`4096`字节,应当适当减小前一块的大小,使后一块大小超过`4096`字节
受限于记录长度的数字为uint16一块未被使用的空闲空间大小最大为`65535`实际使用时不使其超过`4096`。如果确有连续的超过`4096`字节的空闲,应当划分为多个块。块应当是`4k`对齐的
#### 使用
使用时优先从第一个块遍历比较其大小以及页对齐是否符合要求。当使用后仍有剩余对于小于10字节的块直接舍弃不用否则更新块大小与相关链表指针。
### 表

View File

@@ -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
View 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
View File

@@ -0,0 +1 @@
option(BUILD_TEST "Whether to build tests" OFF)

38
src/page.c Normal file
View 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);
}

View File

@@ -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;
}