db.go 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. package DB
  2. import (
  3. "TsDB2/DB/core"
  4. "TsDB2/DB/core/types"
  5. "fmt"
  6. "reflect"
  7. "strings"
  8. "time"
  9. )
  10. // DB ORM 层数据库入口
  11. type DB struct {
  12. coreDB *core.DB
  13. }
  14. // Open 打开或创建数据库
  15. func Open(path string) (*DB, error) {
  16. cdb, err := core.Open(path)
  17. if err != nil {
  18. return nil, fmt.Errorf("tsdb: open %s: %w", path, err)
  19. }
  20. return &DB{coreDB: cdb}, nil
  21. }
  22. // Close 关闭数据库
  23. func (db *DB) Close() error {
  24. return db.coreDB.Close()
  25. }
  26. // Commit 显式提交 — 通过 WAL 保证原子性
  27. func (db *DB) Commit() error {
  28. return db.coreDB.Commit()
  29. }
  30. // SetAutoCommitDelay 设置防抖自动提交延迟
  31. // delay=0 表示禁用自动提交 (仅手动 Commit)
  32. // 默认值为 1 秒: 每次写操作重置计时器, 停止操作 1 秒后自动 Commit
  33. func (db *DB) SetAutoCommitDelay(d time.Duration) {
  34. db.coreDB.SetAutoCommitDelay(d)
  35. }
  36. // SetDirtyThreshold 设置脏页阈值(页数),超过此值自动触发 Commit
  37. func (db *DB) SetDirtyThreshold(threshold int) {
  38. db.coreDB.SetDirtyThreshold(threshold)
  39. }
  40. // SetCommitPreset 设置提交策略预设
  41. // preset: "batch" | "online" | "safe" | "ultra-safe"
  42. // - batch: 离线批量导入 (500页, 1s超时) - 高吞吐,可接受少量数据丢失风险
  43. // - online: 在线业务默认 (100页, 500ms超时) - 平衡性能和安全性
  44. // - safe: 金融/医疗关键数据 (20页, 100ms超时) - 最高安全性,性能较低
  45. // - ultra-safe: 极端安全场景 (40页, 50ms超时) - 极致安全,性能很低(慢5-8倍)
  46. func (db *DB) SetCommitPreset(preset string) {
  47. switch preset {
  48. case "batch":
  49. // 离线批量导入:高吞吐
  50. db.SetDirtyThreshold(500) // 8MB
  51. db.SetAutoCommitDelay(time.Second) // 1s
  52. case "online":
  53. // 在线业务默认:平衡
  54. db.SetDirtyThreshold(100) // 1.6MB
  55. db.SetAutoCommitDelay(500 * time.Millisecond) // 500ms
  56. case "safe":
  57. // 关键数据:最高安全
  58. db.SetDirtyThreshold(20) // 320KB
  59. db.SetAutoCommitDelay(100 * time.Millisecond) // 100ms
  60. case "ultra-safe":
  61. // 极端安全:每40页 Commit,断电最多丢失 ~800行
  62. db.SetDirtyThreshold(40) // 640KB
  63. db.SetAutoCommitDelay(50 * time.Millisecond) // 50ms
  64. default:
  65. // 未知预设,使用默认值
  66. db.SetDirtyThreshold(500)
  67. db.SetAutoCommitDelay(time.Second)
  68. }
  69. }
  70. // LockWrites 锁定写入(禁止 Insert/Update/Delete)
  71. // 适用场景:批量导入前、维护操作期间、备份时
  72. func (db *DB) LockWrites() {
  73. db.coreDB.LockWrites()
  74. }
  75. // UnlockWrites 解锁写入(允许 Insert/Update/Delete)
  76. func (db *DB) UnlockWrites() {
  77. db.coreDB.UnlockWrites()
  78. }
  79. // SetBufferPoolCapacity 设置 BufferPool 容量(页数)
  80. func (db *DB) SetBufferPoolCapacity(capacity int) {
  81. db.coreDB.SetBufferPoolCapacity(capacity)
  82. }
  83. // BeginTransaction 开启新事务
  84. // 返回 Transaction 对象,用于 Commit/Rollback
  85. //
  86. // 使用示例:
  87. //
  88. // txn := db.BeginTransaction()
  89. // defer func() {
  90. // if err := recover(); err != nil {
  91. // txn.Rollback() // 异常时回滚
  92. // panic(err)
  93. // }
  94. // }()
  95. //
  96. // tbl.Insert(&Record{...})
  97. // tbl.Update(...)
  98. //
  99. // if err := txn.Commit(); err != nil {
  100. // return err // 提交失败
  101. // }
  102. func (db *DB) BeginTransaction() *core.Transaction {
  103. return db.coreDB.BeginTransaction()
  104. }
  105. // DebugDBState 打印数据库调试信息 (调试用)
  106. func (db *DB) DebugDBState() {
  107. db.coreDB.DebugDBState()
  108. }
  109. // DebugTableState 打印表调试信息 (调试用)
  110. func (db *DB) DebugTableState(tableName string) {
  111. db.coreDB.DebugTableState(tableName)
  112. }
  113. // UseTable 获取或创建泛型表
  114. // 如果表不存在,会自动创建表和索引
  115. // 如果表已存在,会自动同步 schema:struct 多的字段自动添加,少的字段自动删除
  116. //
  117. // 用法1: 自动推导表名(推荐)
  118. //
  119. // tbl, _ := DB.UseTable[Employee](db) // 表名自动为 "employee"
  120. //
  121. // 用法2: 手动指定表名
  122. //
  123. // tbl, _ := DB.UseTable[Employee](db, "emp_table") // 自定义表名
  124. func UseTable[T any](db *DB, name ...string) (*Table[T], error) {
  125. var zero T
  126. model, err := ParseModel(&zero)
  127. if err != nil {
  128. return nil, fmt.Errorf("tsdb: parse model: %w", err)
  129. }
  130. // 自动推导表名:从类型名转为小写(如 Employee -> employee)
  131. tableName := typeNameToTableName(zero)
  132. if len(name) > 0 && name[0] != "" {
  133. tableName = name[0] // 用户指定的表名优先
  134. }
  135. // 尝试查找已有表
  136. coreTbl, ok := db.coreDB.FindTable(tableName)
  137. if !ok {
  138. // 表不存在,创建新表
  139. coreTbl, err = db.coreDB.CreateTable(tableName, model.CoreFields)
  140. if err != nil {
  141. return nil, fmt.Errorf("tsdb: create table %s: %w", tableName, err)
  142. }
  143. // 创建一级索引
  144. idxName := "pk_" + tableName
  145. _, err = coreTbl.CreateIndex(idxName, model.GetIndexType(), []byte{model.CorePKField})
  146. if err != nil {
  147. return nil, fmt.Errorf("tsdb: create index for %s: %w", tableName, err)
  148. }
  149. } else {
  150. // 表已存在,自动同步 schema
  151. syncSchema(coreTbl, model)
  152. }
  153. tbl := &Table[T]{
  154. coreTable: coreTbl,
  155. model: model,
  156. name: tableName,
  157. }
  158. tbl.refreshActiveColumns()
  159. return tbl, nil
  160. }
  161. // syncSchema 将 DB schema 同步为与 struct 一致
  162. // struct 多 → AddField;struct 少 → DropField
  163. func syncSchema(coreTbl *core.Table, model *ModelInfo) {
  164. // 构建 struct 字段名集合 (不含自动主键)
  165. structCols := make(map[string]FieldDef, len(model.Fields))
  166. for _, fd := range model.Fields {
  167. structCols[fd.ColName] = fd
  168. }
  169. // 获取 DB 当前活跃列 (排除自动主键 _id / _ts)
  170. dbCols := coreTbl.GetActiveFieldNames()
  171. dbColSet := make(map[string]bool, len(dbCols))
  172. for _, name := range dbCols {
  173. if name == "_id" || name == "_ts" {
  174. continue
  175. }
  176. dbColSet[name] = true
  177. }
  178. // 1. struct 有但 DB 没有 → 添加列
  179. for _, fd := range model.Fields {
  180. if !dbColSet[fd.ColName] {
  181. coreTbl.AddField(types.FieldInfo{
  182. FieldType: fd.FieldType,
  183. FieldName: []byte(fd.ColName),
  184. })
  185. }
  186. }
  187. // 2. DB 有但 struct 没有 → 删除列
  188. for _, name := range dbCols {
  189. if name == "_id" || name == "_ts" {
  190. continue
  191. }
  192. if _, ok := structCols[name]; !ok {
  193. coreTbl.DropField(name)
  194. }
  195. }
  196. }
  197. // DropTable 删除表
  198. func (db *DB) DropTable(name string) error {
  199. return db.coreDB.DropTable(name)
  200. }
  201. // CoreDB 返回底层 core.DB (用于高级操作如创建二级索引)
  202. func (db *DB) CoreDB() *core.DB {
  203. return db.coreDB
  204. }
  205. // typeNameToTableName 从类型名推导表名(Employee -> employee)
  206. func typeNameToTableName(v any) string {
  207. t := reflect.TypeOf(v)
  208. name := t.Name()
  209. if name == "" {
  210. return "table"
  211. }
  212. // 首字母小写:Employee -> employee, OrderItem -> orderItem
  213. return strings.ToLower(name[:1]) + name[1:]
  214. }