From d17f36b255eca5db6cae65bd62b9bea8be38e4d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Tue, 3 May 2022 21:14:30 +0800 Subject: [PATCH] add some funcs of table --- api/table.md | 10 ++-- include/file.h | 4 ++ include/table.h | 12 +++-- include/types.h | 3 ++ src/file.c | 12 +++++ src/table.c | 131 +++++++++++++++++++++++++++++++++++++++++++++--- src/types.c | 18 +++++++ 7 files changed, 174 insertions(+), 16 deletions(-) diff --git a/api/table.md b/api/table.md index 35259fc..42fa2c6 100644 --- a/api/table.md +++ b/api/table.md @@ -8,16 +8,16 @@ │ table name length │ name of the table ( variable length ) │ ├─────────────────────┼──────────┬──────────┬──────────┬──────────┬──────────┬──────────┤ │ │ type of │ type of │ type of │ type of │ type of │ type of │ -│ table column length │ column │ column │ column │ column │ column │ column │ +│ table row length │ row │ row │ row │ row │ row │ row │ │ │ No.1 │ No.2 │ No.3 │ No.4 │ No... │ No.N │ ├─────────────────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┤ │ index pointer of pk ( this pointer will never be zero ) │ ├───────────────────────────────────────────────────────────────────────────────────────┤ -│ index pointer of column No.2 ( if it's zero, there is no index for this column ) │ +│ index pointer of row No.2 ( if it's zero, there is no index for this row ) │ ├───────────────────────────────────────────────────────────────────────────────────────┤ -│ index pointer of column No... ( if it's zero, there is no index for this column ) │ +│ index pointer of row No... ( if it's zero, there is no index for this row ) │ ├───────────────────────────────────────────────────────────────────────────────────────┤ -│ index pointer of column No.N ( if it's zero, there is no index for this column ) │ +│ index pointer of row No.N ( if it's zero, there is no index for this row ) │ ├───────────────────────────────────────────────────────────────────────────────────────┤ │ index pointer of first foreign key ( if available ) │ ├───────────────────────────────────────────────────────────────────────────────────────┤ @@ -31,7 +31,7 @@ > 区块长度固定,但是不同索引类型有所不同 详见[索引格式](/api/index.md)。 ### 表项 -> 区块长度固定,为`8+len(column1)+len(column2)+...+len(columnN)`字节 +> 区块长度固定,为`8+len(row 1)+len(row 2)+...+len(row N)`字节 为方便遍历,数据表项以uint64的指针开头,代表下一项的地址。接下来按照[数据类型](/api/types.md)中规定的存储格式依次附加第一项、第二项直到第N项的值。 #### 表项的增加 优先附加到上一个表项末尾。如无法实现,则从空区块选取一个,或附加到整个文件末尾。 diff --git a/include/file.h b/include/file.h index 2e2fb03..f64fd71 100644 --- a/include/file.h +++ b/include/file.h @@ -25,6 +25,8 @@ int set_first_unused_block(int fd, uint64_t ptr); // 获得 ptr of unused blk 字段 uint64_t get_first_unused_block(int fd); +uint64_t get_next_unused_block(int fd, uint64_t ptr); + // 设置 ptr of next table 字段 // 返回: // 0 成功 @@ -35,4 +37,6 @@ int set_first_table(int fd, uint64_t ptr); // 获得 ptr of next table 字段 uint64_t get_first_table(int fd); +uint64_t get_next_table(int fd, uint64_t ptr); + #endif \ No newline at end of file diff --git a/include/table.h b/include/table.h index dbca2ee..8cb4e86 100644 --- a/include/table.h +++ b/include/table.h @@ -7,16 +7,18 @@ // 创建表,可变参数为本表的一行的 types,详见 types.h // 如果 types 为外键,需要紧跟一个 uint64_t ptr // 指示外键链接到的表位置 +// len(buf) >= 4096+8+2=4106 // 返回: // NULL 失败,详见 errno // table 指向表头的指针 -void* create_table(int fd, const char* name, ...); +void* create_table(int fd, char* buf, const char* name, uint16_t row_len, ...); // 加载 ptr 位置的表 +// len(buf) >= 4096+8+2=4106 // 返回: // NULL 失败,详见 errno // table 指向表头的指针 -void* load_table(int fd, uint64_t ptr); +void* load_table(int fd, char* buf, uint64_t ptr); // 获得表名长度,包含结尾0 uint16_t get_table_name_length(void* table); @@ -45,7 +47,7 @@ int remove_table_index(int fd, void* table, uint16_t pos); // 返回: // 0 失败,详见 errno // ptr 本行插入的位置 -uint64_t insert_row(int fd, void* table, ...); +uint64_t insert_row(int fd, void* table, uint16_t row_len, ...); // 根据主键的匹配值查找行 // 如果主键不为 string,k 直接装填其值 @@ -63,7 +65,7 @@ uint64_t find_row_by_pk(int fd, void* table, key_t k); // 返回: // 非 0 失败,详见 errno // 0 成功 -int find_row_by(int fd, void* table, int (*f)(uint64_t), ...); +int find_row_by(int fd, void* table, int (*f)(uint64_t), uint16_t row_len, ...); // 根据主键的匹配值删除行 // 如果主键不为 string,k 直接装填其值 @@ -80,6 +82,6 @@ int remove_row_by_pk(int fd, void* table, key_t k); // 返回: // 非 0 失败,详见 errno // 0 成功 -int remove_row_by(int fd, void* table, ...); +int remove_row_by(int fd, void* table, uint16_t row_len, ...); #endif \ No newline at end of file diff --git a/include/types.h b/include/types.h index 2a95101..9b770f1 100644 --- a/include/types.h +++ b/include/types.h @@ -21,6 +21,9 @@ typedef uint8_t type_t; typedef uint64_t key_t; +// 获得本类型 index 相对于 buffer 头的偏移 +int type_offset(type_t t); + // 为类型 type 创建索引 // 返回:索引头节点的指针 index void* create_index(int fd, type_t t, void* buf); diff --git a/src/file.c b/src/file.c index ed97b95..dde08c2 100644 --- a/src/file.c +++ b/src/file.c @@ -37,6 +37,12 @@ uint64_t get_first_unused_block(int fd) { return ptr; } +uint64_t get_next_unused_block(int fd, uint64_t ptr) { + if(lseek(fd, ptr, 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; @@ -50,3 +56,9 @@ uint64_t get_first_table(int fd) { readle64(fd, ptr); return ptr; } + +uint64_t get_next_table(int fd, uint64_t ptr) { + if(lseek(fd, ptr, SEEK_SET) < 0) return EOF; + readle64(fd, ptr); + return ptr; +} diff --git a/src/table.c b/src/table.c index d65bf34..dd2201b 100644 --- a/src/table.c +++ b/src/table.c @@ -1,23 +1,142 @@ +#include +#include #include #include +#include +#include #include "../include/binary.h" +#include "../include/file.h" +#include "../include/page.h" #include "../include/table.h" +#include "../include/types.h" +#include "../include/types/int8.h" +#include "../include/types/int16.h" + +// 计算索引需要的内存 +static int _calc_index_size(type_t t) { + switch(t&7) { + case TYPE_INT8: + return INT8_INDEX_SZ+10; + case TYPE_INT16: + return INT16_INDEX_SZ+10 + INT16_BITMAP_SZ+8*2; + case TYPE_INT32: + case TYPE_FLOAT: + case TYPE_INT64: + case TYPE_DOUBLE: + case TYPE_STRING: + return PAGESZ+8; + case TYPE_BINARY: // 不能创建索引 + default: + return EOF; + } +} + +// 为 t 类型创建索引,写入 index_ptr +// 返回: +// 1 失败,详见 errno +// 0 成功 +static void* _add_index_type(int fd, uint64_t* index_ptr, type_t t) { + int sz = _calc_index_size(t); + if(sz <= 0) { + errno = EINVAL; + return EINVAL; + } + void* buf = malloc(sz); + if(buf == NULL) return 1; + void* index = create_index(fd, t, buf); + *index_ptr = le64(buf); + free(buf); + return 0; +} // 创建表,可变参数为本表的一行的 types,详见 types.h // 如果 types 为外键,需要紧跟一个 uint64_t ptr // 指示外键链接到的表位置 +// len(buf) >= 4096+8+2=4106 // 返回: // NULL 失败,详见 errno // table 指向表头的指针 -void* create_table(int fd, const char* name, ...) { - return NULL; +void* create_table(int fd, char* buf, const char* name, uint16_t row_len, ...) { + va_list list; + + if(!row_len || row_len > 128) { + errno = EINVAL; + return NULL; + } + + int len = strlen(name); + if(len <= 0 || len >= UINT16_MAX) { + errno = EINVAL; + return NULL; + } + + void* table = alloc_page(fd, buf+2); + if(table == NULL) return NULL; + + memset(table, 0, PAGESZ); + putle16(table+8, len); + memcpy(table+8+2, name, len); + len += 8+2; + + uint64_t ptr = get_first_table(fd); + while(ptr > 0) ptr = get_next_table(fd, ptr); // 结束时,fd位于最后一个表头+8 + if(ptr) return NULL; // 发生错误 + lseek(fd, -8, SEEK_CUR); + if(write(fd, buf+2, 8) != 8) return NULL; // 写入新表位置 + + putle16(table+len, row_len); + len += 2; + + int foreign_cnt = 0; + va_start(list, row_len); + + type_t t = va_arg(list, type_t); // 是主键,检查是否有 unique + nonnull 类型修饰符 + if(!(t&EXTYPE_NONNULL) || !(t&EXTYPE_UNIQUE)) { + errno = EINVAL; + return NULL; + } + ((type_t*)table)[len] = t; // 填充 type of row No.0 + if(t & EXTYPE_FOREIGNKEY) { // 是外键,还有一个参数 + ptr = va_arg(list, uint64_t); + putle64(table+len+(int)row_len*(8+1)+8*(foreign_cnt++), ptr); + } + + // 为 pk 创建索引 + if(_add_index_type(fd, table+len+(int)row_len, t)) return NULL; + for(int i = 1; i < (int)row_len; i++) { + t = va_arg(list, type_t); + ((type_t*)table)[len+i] = t; // 填充 type of row No.i + if(t & EXTYPE_FOREIGNKEY) { // 是外键,还有一个参数 + ptr = va_arg(list, uint64_t); + putle64(table+len+(int)row_len*(8+1)+8*(foreign_cnt++), ptr); + } + } + + va_end(list); + + len += (int)row_len*(8+1) + 8*foreign_cnt; + if(len > PAGESZ-2) { + errno = EFBIG; + return NULL; + } + + // 写回文件 + if(sync_page(fd, table)) return NULL; + // 回收剩余空间 + ptr = le64(buf+2); + if(PAGESZ - len > 10) add_block(fd, PAGESZ - len, ptr+(uint64_t)len); + // 将 page 变为 block + putle64(buf, ptr); + putle16(buf+8, len); + return buf+10; } // 加载 ptr 位置的表 +// len(buf) >= 4096+8+2=4106 // 返回: // NULL 失败,详见 errno // table 指向表头的指针 -void* load_table(int fd, uint64_t ptr) { +void* load_table(int fd, char* buf, uint64_t ptr) { return NULL; } @@ -59,7 +178,7 @@ int remove_table_index(int fd, void* table, uint16_t pos) { // 返回: // 0 失败,详见 errno // ptr 本行插入的位置 -uint64_t insert_row(int fd, void* table, ...) { +uint64_t insert_row(int fd, void* table, uint16_t row_len, ...) { return 0; } @@ -81,7 +200,7 @@ uint64_t find_row_by_pk(int fd, void* table, key_t k) { // 返回: // 非 0 失败,详见 errno // 0 成功 -int find_row_by(int fd, void* table, int (*f)(uint64_t), ...) { +int find_row_by(int fd, void* table, int (*f)(uint64_t), uint16_t row_len, ...) { return 1; } @@ -102,6 +221,6 @@ int remove_row_by_pk(int fd, void* table, key_t k) { // 返回: // 非 0 失败,详见 errno // 0 成功 -int remove_row_by(int fd, void* table, ...) { +int remove_row_by(int fd, void* table, uint16_t row_len, ...) { return 1; } diff --git a/src/types.c b/src/types.c index 8adb386..8ad06d0 100644 --- a/src/types.c +++ b/src/types.c @@ -1,3 +1,4 @@ +#include "../include/binary.h" #include "../include/types.h" #include "../include/types/int8.h" #include "../include/types/int16.h" @@ -129,6 +130,23 @@ static _remove_by_key_t _remove_item_by_key[] = { remove_item_by_not_impl_key }; +int type_offset(type_t t) { + switch(t&7) { + case TYPE_INT8: + case TYPE_INT16: + return -10; // block + case TYPE_INT32: + case TYPE_FLOAT: + case TYPE_INT64: + case TYPE_DOUBLE: + case TYPE_STRING: + return -8; // page + case TYPE_BINARY: // 不能创建索引 + default: + return 0; + } +} + void* create_index(int fd, type_t t, void* buf) { return _types_init[t&7](fd, buf); }