├── .gitignore ├── linux └── linux.md ├── golang ├── sources │ ├── images │ │ ├── 1_range_map.png │ │ ├── 2_func_reload.png │ │ └── 1_range_map_res.png │ └── code │ │ ├── range_map │ │ └── range_map.go │ │ └── func_reload │ │ └── func_reload.go └── golang.md ├── interview ├── sources │ └── images │ │ ├── index_三次握手.png │ │ ├── index_二叉树.png │ │ ├── index_关系表.png │ │ ├── index_分代回收.png │ │ ├── index_分段机制.png │ │ ├── index_分页机制.png │ │ ├── index_协议表.png │ │ ├── index_四次挥手.png │ │ ├── index_异步IO.png │ │ ├── index_阻塞IO.png │ │ ├── index_url历程.png │ │ ├── index_xpath语法.png │ │ ├── index_伯乐网络结构.png │ │ ├── index_多路复用IO.png │ │ ├── index_排序复杂度.jpg │ │ ├── index_数据库分类.png │ │ ├── index_非阻塞IO.png │ │ ├── index_xpath_谓语.png │ │ ├── index_xpath语法_.png │ │ └── index_redis与memcached.png └── index.md ├── k8sandkubeflow ├── sources │ └── images │ │ ├── cuda1.jpg │ │ ├── cuda2.jpg │ │ ├── cudnn1.png │ │ ├── cudnn2.png │ │ ├── cudnn3.png │ │ ├── nvida_web.png │ │ ├── notebook_view.png │ │ └── 企业微信截图_15553274233731.png └── k8sandkubeflow.md ├── deeplearning ├── deeplearning.md └── deeplearning.html └── databases ├── 从零开始写数据库.md └── 从零开始写数据库.html /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode -------------------------------------------------------------------------------- /linux/linux.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /golang/sources/images/1_range_map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/golang/sources/images/1_range_map.png -------------------------------------------------------------------------------- /golang/sources/images/2_func_reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/golang/sources/images/2_func_reload.png -------------------------------------------------------------------------------- /interview/sources/images/index_三次握手.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_三次握手.png -------------------------------------------------------------------------------- /interview/sources/images/index_二叉树.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_二叉树.png -------------------------------------------------------------------------------- /interview/sources/images/index_关系表.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_关系表.png -------------------------------------------------------------------------------- /interview/sources/images/index_分代回收.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_分代回收.png -------------------------------------------------------------------------------- /interview/sources/images/index_分段机制.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_分段机制.png -------------------------------------------------------------------------------- /interview/sources/images/index_分页机制.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_分页机制.png -------------------------------------------------------------------------------- /interview/sources/images/index_协议表.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_协议表.png -------------------------------------------------------------------------------- /interview/sources/images/index_四次挥手.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_四次挥手.png -------------------------------------------------------------------------------- /interview/sources/images/index_异步IO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_异步IO.png -------------------------------------------------------------------------------- /interview/sources/images/index_阻塞IO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_阻塞IO.png -------------------------------------------------------------------------------- /k8sandkubeflow/sources/images/cuda1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/k8sandkubeflow/sources/images/cuda1.jpg -------------------------------------------------------------------------------- /k8sandkubeflow/sources/images/cuda2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/k8sandkubeflow/sources/images/cuda2.jpg -------------------------------------------------------------------------------- /golang/sources/images/1_range_map_res.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/golang/sources/images/1_range_map_res.png -------------------------------------------------------------------------------- /interview/sources/images/index_url历程.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_url历程.png -------------------------------------------------------------------------------- /interview/sources/images/index_xpath语法.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_xpath语法.png -------------------------------------------------------------------------------- /interview/sources/images/index_伯乐网络结构.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_伯乐网络结构.png -------------------------------------------------------------------------------- /interview/sources/images/index_多路复用IO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_多路复用IO.png -------------------------------------------------------------------------------- /interview/sources/images/index_排序复杂度.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_排序复杂度.jpg -------------------------------------------------------------------------------- /interview/sources/images/index_数据库分类.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_数据库分类.png -------------------------------------------------------------------------------- /interview/sources/images/index_非阻塞IO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_非阻塞IO.png -------------------------------------------------------------------------------- /k8sandkubeflow/sources/images/cudnn1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/k8sandkubeflow/sources/images/cudnn1.png -------------------------------------------------------------------------------- /k8sandkubeflow/sources/images/cudnn2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/k8sandkubeflow/sources/images/cudnn2.png -------------------------------------------------------------------------------- /k8sandkubeflow/sources/images/cudnn3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/k8sandkubeflow/sources/images/cudnn3.png -------------------------------------------------------------------------------- /interview/sources/images/index_xpath_谓语.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_xpath_谓语.png -------------------------------------------------------------------------------- /interview/sources/images/index_xpath语法_.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_xpath语法_.png -------------------------------------------------------------------------------- /k8sandkubeflow/sources/images/nvida_web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/k8sandkubeflow/sources/images/nvida_web.png -------------------------------------------------------------------------------- /k8sandkubeflow/sources/images/notebook_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/k8sandkubeflow/sources/images/notebook_view.png -------------------------------------------------------------------------------- /interview/sources/images/index_redis与memcached.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/interview/sources/images/index_redis与memcached.png -------------------------------------------------------------------------------- /k8sandkubeflow/sources/images/企业微信截图_15553274233731.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JK-97/my_note/HEAD/k8sandkubeflow/sources/images/企业微信截图_15553274233731.png -------------------------------------------------------------------------------- /deeplearning/deeplearning.md: -------------------------------------------------------------------------------- 1 | --- 2 | export_on_save: 3 | html: true 4 | html: 5 | toc: true 6 | offline: true 7 | toc: 8 | depth_from: 1 9 | depth_to: 3 10 | ordered: false 11 | 12 | --- 13 | # 深度学习 -------------------------------------------------------------------------------- /golang/golang.md: -------------------------------------------------------------------------------- 1 | # golang 2 | 3 | 4 | ##### 1.golang range map 获取的是值的备份,都是同一个指针 5 |  6 | **result:** 7 |  8 | **solve** 9 | 需要在range体内声明一个变量来存储value,再将指针赋予map -------------------------------------------------------------------------------- /golang/sources/code/range_map/range_map.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type student struct { 8 | Name string 9 | Age int 10 | } 11 | 12 | func main() { 13 | m := make(map[string]*student) 14 | stus := []student{ 15 | {Name: "zhou", Age: 24}, 16 | {Name: "li", Age: 23}, 17 | {Name: "wang", Age: 22}, 18 | } 19 | for _, stu := range stus { 20 | m[stu.Name] = &stu 21 | } 22 | fmt.Println(m) 23 | 24 | m["zhou"] = &stus[0] 25 | m["li"] = &stus[1] 26 | m["wang"] = &stus[2] 27 | fmt.Println(m) 28 | } 29 | -------------------------------------------------------------------------------- /golang/sources/code/func_reload/func_reload.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type People struct{} 6 | 7 | func (p *People) ShowA() { 8 | fmt.Println("showA") 9 | p.ShowB() 10 | } 11 | func (p *People) ShowB() { 12 | fmt.Println("showB") 13 | } 14 | 15 | type Teacher struct { 16 | People 17 | } 18 | 19 | func (t *Teacher) ShowB() { 20 | fmt.Println("teacher showB") 21 | } 22 | 23 | func main() { 24 | t := Teacher{} 25 | t.ShowA() 26 | x := "Aaaaaa" 27 | for index, key := range x { 28 | fmt.Println(index, key) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /databases/从零开始写数据库.md: -------------------------------------------------------------------------------- 1 | --- 2 | export_on_save: 3 | html: true 4 | html: 5 | toc: true 6 | offline: true 7 | toc: 8 | depth_from: 1 9 | depth_to: 3 10 | ordered: false 11 | 12 | --- 13 | 14 | # 从零开始----nosql数据库(golang ) 15 | ## 数据库的需求 16 | * 需要有索引,快速地找到数据 17 | * 需要满足ACID 18 | 19 | 20 | ## 学习路线 21 | 我们首先不先讲什么理论知识,这些东西对于一点都没有概念的人来说会感觉很抽象。现在的开源社区这么多的项目,这些项目就是很好的学习资源。这里先由我通过分析开源项目的源码,来一步一步剖析原理,编写一个简单的数据库需要什么准备。 22 | ## nustdb源码分析 23 | **https://github.com/xujiajun/nutsdb** 24 | 这个一个用golang编写的k/v数据库,该仓库的的社区还持续更新着。 25 | 我们先把这个repo克隆下来,跟着开源作者的思路来一步一步构建数据库的概念。chekout第一次提交。 26 | 27 | ```shell 28 | git clone https://github.com/xujiajun/nutsdb.git 29 | git checkout 7c0a5b6 30 | ``` 31 | 那我们就可以看到以下目录结构(将无关的文件忽略掉了),先大概讲下这里的文件的作用 32 | ```go 33 | ├── bptree.go # 写了一些B+树的操作 34 | ├── datafile.go # 写了存放数据文件抽象 35 | ├── db.go # 数据库的抽象 36 | ├── entry.go # 数据包装 37 | ├── options.go # 数据库的配置选项 38 | ├── tx.go # 事务的包装 39 | └── utils.go 40 | ``` 41 | 那么我们知道的了它们的调用关系 42 | ```bash 43 | options -> db -> tx -> entry -> datafile 44 | -> bptree 45 | ``` 46 | 在这个commit的文件中,我们可以看到example文件夹,我们选择 example/basic/main.go作为分析的大门。 47 | 函数 :db.update() 48 | ```go 49 | func put() { 50 | if err := db.Update( 51 | func(tx *nutsdb.Tx) error { 52 | key := []byte("name1") 53 | val := []byte("val1") 54 | if err := tx.Put(bucket, key, val, 0); err != nil { 55 | return err 56 | } 57 | return nil 58 | }); err != nil { 59 | log.Fatal(err) 60 | } 61 | } 62 | ``` 63 | 函数 :db.Update -> db.managed() ;看到这段代码我 们就大概知道nutsdb数据库写操作时的思路了。看下面的代码注释,主要分为了3步: 64 | * 创建事务 65 | * 预执行 66 | * 提交修改 67 | ```go 68 | // managed calls a block of code that is fully contained in a transactio 69 | func (db *DB) managed(writable bool, fn func(tx *Tx) error) (err error) { 70 | # writeable 是否可写 ,需要对数据库进行修改时 传参为true 71 | var tx *Tx 72 | tx, err = db.Begin(writable) 73 | # 1->创建事务,并且加锁,保证当前事务独占 74 | if err != nil { 75 | return 76 | } 77 | 78 | if err = fn(tx); err != nil { 79 | # 2->执行数据库的操作,还没写入文件,这时执行put操作,用一个切片进行保存 80 | err = tx.Rollback() 81 | # 操作失败,进行回滚 82 | return 83 | } 84 | 85 | if err = tx.Commit(); err != nil { 86 | # 3->提交修改,将切片的数据写入文件,并创建索引 87 | err = tx.Rollback() 88 | return 89 | } 90 | 91 | return 92 | } 93 | ``` 94 | 下面们分析下这3个步里具体做了什么? 95 | 96 | __1--> db.Begin()__ 97 | ```go 98 | # tx的结构题 ->代表事务 99 | type Tx struct { 100 | id uint64 # 事务id 101 | db *DB # 事务所执行的db 102 | writable bool # 是否有写操作 103 | pendingWrites []*Entry # 等待写入的数据 104 | } 105 | 106 | func (db *DB) Begin(writable bool) (tx *Tx, err error) { 107 | tx, err = newTx(db, writable) 108 | # 创建事务实例 109 | if err != nil { 110 | return nil, err 111 | } 112 | 113 | tx.lock() 114 | # 加上事务锁 115 | if db.closed { 116 | tx.unlock() 117 | return nil, ErrDBClosed 118 | } 119 | 120 | return 121 | } 122 | ``` 123 | __2--> db.Put()__ 124 | 第二步是参数传入的函数,即db.update() 里的函数。主要就是创建一对键值数据,然后调用db.Put()函数。 125 | ```go 126 | func (tx *Tx) put(bucket string, key, value []byte, ttl uint32, flag uint16, timestamp uint64) error { 127 | # bucket 相当于mongodb 的collection ,可称表名 128 | # key,value 即将存入的数据 129 | # ttl 过期时间 130 | # timestamp 时间戳 131 | if err := tx.checkTxIsClosed(); err != nil { 132 | return err 133 | } 134 | 135 | if !tx.writable { 136 | return ErrTxNotWritable 137 | } 138 | 139 | if len(key) == 0 { 140 | return ErrKeyEmpty 141 | } 142 | # entry 是每一条数据的包装,将准备要写的数据其append到tx.pendingWrites 待写 143 | tx.pendingWrites = append(tx.pendingWrites, &Entry{ 144 | Key: key, 145 | Value: value, 146 | Meta: &MetaData{ 147 | keySize: uint32(len(key)), 148 | valueSize: uint32(len(value)), 149 | timestamp: timestamp, 150 | Flag: flag, 151 | TTL: ttl, 152 | bucket: []byte(bucket), 153 | bucketSize: uint32(len(bucket)), 154 | status: UnCommitted, 155 | txId: tx.id, 156 | }, 157 | }) 158 | 159 | return nil 160 | } 161 | ``` 162 | 163 | ```go 164 | // 5. Unlock the database and clear the db field. 165 | func (tx *Tx) Commit() error { 166 | # 在函数进行写入操作 167 | var e *Entry 168 | 169 | if tx.db == nil { 170 | return ErrDBClosed 171 | } 172 | 173 | writesLen := len(tx.pendingWrites) 174 | 175 | if writesLen == 0 { 176 | tx.unlock() 177 | tx.db = nil 178 | return nil 179 | } 180 | 181 | for i := 0; i < writesLen; i++ { 182 | entry := tx.pendingWrites[i] 183 | entrySize := entry.Size() 184 | if entrySize > tx.db.opt.SegmentSize { 185 | # 判断每条数据的大小是否超过设定的段大小 186 | return ErrKeyAndValSize 187 | } 188 | 189 | if tx.db.ActiveFile.ActualSize+entrySize > tx.db.opt.SegmentSize { 190 | # 如果当前存储的.dat文件超过大小,则需要进行rotate操作,换一个文件写入 191 | if err := tx.rotateActiveFile(); err != nil { 192 | return err 193 | } 194 | } 195 | 196 | if i == writesLen-1 { 197 | # 更改数据的状态 198 | entry.Meta.status = Committed 199 | } 200 | 201 | off := tx.db.ActiveFile.writeOff 202 | # 当前写入文件的末尾byte数 203 | if _, err := tx.db.ActiveFile.WriteAt(entry.Encode(), off); err != nil { 204 | # 写入当前数据库文件的末尾 205 | return err 206 | } 207 | 208 | tx.db.ActiveFile.ActualSize += entrySize 209 | tx.db.ActiveFile.writeOff += entrySize 210 | # 更新数据库文件的大小信息 , 末尾位置 211 | 212 | if tx.db.opt.EntryIdxMode == HintAndRAMIdxMode { 213 | entry.Meta.status = Committed 214 | e = entry 215 | } else { 216 | e = nil 217 | } 218 | 219 | countFlag := CountFlagEnabled 220 | if tx.db.opt.IsMerging { 221 | countFlag = CountFlagDisabled 222 | } 223 | bucket := string(entry.Meta.bucket) 224 | if _, ok := tx.db.HintIdx[bucket]; !ok { 225 | # 若当前表么有建立索引,则建立一个 226 | tx.db.HintIdx[bucket] = NewTree() 227 | } 228 | _ = tx.db.HintIdx[bucket].Insert(entry.Key, e, &Hint{ 229 | # 插入索引,将数据的位置记录到b+树的数据结构。中 230 | fileId: tx.db.ActiveFile.fileId, 231 | # 数据库源文件的id,对应哪个文件 232 | key: entry.Key, 233 | meta: entry.Meta, 234 | dataPos: uint64(off), 235 | # 直接指向记录在数据库文件的位置,加快了检索速度 236 | }, countFlag) 237 | tx.db.KeyCount++ 238 | } 239 | 240 | tx.unlock() 241 | 242 | tx.db = nil 243 | 244 | return nil 245 | } 246 | ``` 247 | 248 | 249 | ## 小结(编写数据库需要什么知识) 250 | 通过上面的分析,我们可以得出,编写一个最简单数据库需要一些最基本的知识 251 | 252 | * 索引数据结构(b+树,hash索引,lsm树) 253 | 254 | 255 | ## 未来优化的方向,以及所需的知识 256 | * 目前是不能保证并发时ACID性,会出现脏读幻读等错误。 257 | * 随机读写时,速度会相对顺序读写要慢很多,所以需要了解一些硬盘读写的基本知识,或其他的数据结构(当前比较就行的就是LSM树)。 258 | * 存储的数据没有进行压缩,导致很冗余数据会占用大量的存储空间。 -------------------------------------------------------------------------------- /deeplearning/deeplearning.html: -------------------------------------------------------------------------------- 1 |
2 |我们首先不先讲什么理论知识,这些东西对于一点都没有概念的人来说会感觉很抽象。现在的开源社区这么多的项目,这些项目就是很好的学习资源。这里先由我通过分析开源项目的源码,来一步一步剖析原理,编写一个简单的数据库需要什么准备。
277 |https://github.com/xujiajun/nutsdb
280 | 这个一个用golang编写的k/v数据库,该仓库的的社区还持续更新着。
281 | 我们先把这个repo克隆下来,跟着开源作者的思路来一步一步构建数据库的概念。chekout第一次提交。
git clone https://github.com/xujiajun/nutsdb.git 283 | git checkout 7c0a5b6 284 |
那我们就可以看到以下目录结构(将无关的文件忽略掉了),先大概讲下这里的文件的作用
285 |├── bptree.go # 写了一些B+树的操作 286 | ├── datafile.go # 写了存放数据文件抽象 287 | ├── db.go # 数据库的抽象 288 | ├── entry.go # 数据包装 289 | ├── options.go # 数据库的配置选项 290 | ├── tx.go # 事务的包装 291 | └── utils.go 292 |
那么我们知道的了它们的调用关系
293 |options -> db -> tx -> entry -> datafile 294 | -> bptree 295 |
在这个commit的文件中,我们可以看到example文件夹,我们选择 example/basic/main.go作为分析的大门。
296 | 函数 :db.update()
func put() { 298 | if err := db.Update( 299 | func(tx *nutsdb.Tx) error { 300 | key := []byte("name1") 301 | val := []byte("val1") 302 | if err := tx.Put(bucket, key, val, 0); err != nil { 303 | return err 304 | } 305 | return nil 306 | }); err != nil { 307 | log.Fatal(err) 308 | } 309 | } 310 |
函数 :db.Update -> db.managed() ;看到这段代码我 们就大概知道nutsdb数据库写操作时的思路了。看下面的代码注释,主要分为了3步:
311 |// managed calls a block of code that is fully contained in a transactio 317 | func (db *DB) managed(writable bool, fn func(tx *Tx) error) (err error) { 318 | # writeable 是否可写 ,需要对数据库进行修改时 传参为true 319 | var tx *Tx 320 | tx, err = db.Begin(writable) 321 | # 1->创建事务,并且加锁,保证当前事务独占 322 | if err != nil { 323 | return 324 | } 325 | 326 | if err = fn(tx); err != nil { 327 | # 2->执行数据库的操作,还没写入文件,这时执行put操作,用一个切片进行保存 328 | err = tx.Rollback() 329 | # 操作失败,进行回滚 330 | return 331 | } 332 | 333 | if err = tx.Commit(); err != nil { 334 | # 3->提交修改,将切片的数据写入文件,并创建索引 335 | err = tx.Rollback() 336 | return 337 | } 338 | 339 | return 340 | } 341 |
下面们分析下这3个步里具体做了什么?
342 |1--> db.Begin()
343 |# tx的结构题 ->代表事务 344 | type Tx struct { 345 | id uint64 # 事务id 346 | db *DB # 事务所执行的db 347 | writable bool # 是否有写操作 348 | pendingWrites []*Entry # 等待写入的数据 349 | } 350 | 351 | func (db *DB) Begin(writable bool) (tx *Tx, err error) { 352 | tx, err = newTx(db, writable) 353 | # 创建事务实例 354 | if err != nil { 355 | return nil, err 356 | } 357 | 358 | tx.lock() 359 | # 加上事务锁 360 | if db.closed { 361 | tx.unlock() 362 | return nil, ErrDBClosed 363 | } 364 | 365 | return 366 | } 367 |
2--> db.Put()
368 | 第二步是参数传入的函数,即db.update() 里的函数。主要就是创建一对键值数据,然后调用db.Put()函数。
func (tx *Tx) put(bucket string, key, value []byte, ttl uint32, flag uint16, timestamp uint64) error { 370 | # bucket 相当于mongodb 的collection ,可称表名 371 | # key,value 即将存入的数据 372 | # ttl 过期时间 373 | # timestamp 时间戳 374 | if err := tx.checkTxIsClosed(); err != nil { 375 | return err 376 | } 377 | 378 | if !tx.writable { 379 | return ErrTxNotWritable 380 | } 381 | 382 | if len(key) == 0 { 383 | return ErrKeyEmpty 384 | } 385 | # entry 是每一条数据的包装,将准备要写的数据其append到tx.pendingWrites 待写 386 | tx.pendingWrites = append(tx.pendingWrites, &Entry{ 387 | Key: key, 388 | Value: value, 389 | Meta: &MetaData{ 390 | keySize: uint32(len(key)), 391 | valueSize: uint32(len(value)), 392 | timestamp: timestamp, 393 | Flag: flag, 394 | TTL: ttl, 395 | bucket: []byte(bucket), 396 | bucketSize: uint32(len(bucket)), 397 | status: UnCommitted, 398 | txId: tx.id, 399 | }, 400 | }) 401 | 402 | return nil 403 | } 404 |
// 5. Unlock the database and clear the db field. 405 | func (tx *Tx) Commit() error { 406 | # 在函数进行写入操作 407 | var e *Entry 408 | 409 | if tx.db == nil { 410 | return ErrDBClosed 411 | } 412 | 413 | writesLen := len(tx.pendingWrites) 414 | 415 | if writesLen == 0 { 416 | tx.unlock() 417 | tx.db = nil 418 | return nil 419 | } 420 | 421 | for i := 0; i < writesLen; i++ { 422 | entry := tx.pendingWrites[i] 423 | entrySize := entry.Size() 424 | if entrySize > tx.db.opt.SegmentSize { 425 | # 判断每条数据的大小是否超过设定的段大小 426 | return ErrKeyAndValSize 427 | } 428 | 429 | if tx.db.ActiveFile.ActualSize+entrySize > tx.db.opt.SegmentSize { 430 | # 如果当前存储的.dat文件超过大小,则需要进行rotate操作,换一个文件写入 431 | if err := tx.rotateActiveFile(); err != nil { 432 | return err 433 | } 434 | } 435 | 436 | if i == writesLen-1 { 437 | # 更改数据的状态 438 | entry.Meta.status = Committed 439 | } 440 | 441 | off := tx.db.ActiveFile.writeOff 442 | # 当前写入文件的末尾byte数 443 | if _, err := tx.db.ActiveFile.WriteAt(entry.Encode(), off); err != nil { 444 | # 写入当前数据库文件的末尾 445 | return err 446 | } 447 | 448 | tx.db.ActiveFile.ActualSize += entrySize 449 | tx.db.ActiveFile.writeOff += entrySize 450 | # 更新数据库文件的大小信息 , 末尾位置 451 | 452 | if tx.db.opt.EntryIdxMode == HintAndRAMIdxMode { 453 | entry.Meta.status = Committed 454 | e = entry 455 | } else { 456 | e = nil 457 | } 458 | 459 | countFlag := CountFlagEnabled 460 | if tx.db.opt.IsMerging { 461 | countFlag = CountFlagDisabled 462 | } 463 | bucket := string(entry.Meta.bucket) 464 | if _, ok := tx.db.HintIdx[bucket]; !ok { 465 | # 若当前表么有建立索引,则建立一个 466 | tx.db.HintIdx[bucket] = NewTree() 467 | } 468 | _ = tx.db.HintIdx[bucket].Insert(entry.Key, e, &Hint{ 469 | # 插入索引,将数据的位置记录到b+树的数据结构。中 470 | fileId: tx.db.ActiveFile.fileId, 471 | # 数据库源文件的id,对应哪个文件 472 | key: entry.Key, 473 | meta: entry.Meta, 474 | dataPos: uint64(off), 475 | # 直接指向记录在数据库文件的位置,加快了检索速度 476 | }, countFlag) 477 | tx.db.KeyCount++ 478 | } 479 | 480 | tx.unlock() 481 | 482 | tx.db = nil 483 | 484 | return nil 485 | } 486 |
通过上面的分析,我们可以得出,编写一个最简单数据库需要一些最基本的知识
489 |