第七节 db.allocate()和db.grow()分析

1. // allocate returns a contiguous block of memory starting at a given page.
2. func (db *DB) allocate(count int) (*page, error) {
3. // Allocate a temporary buffer for the page.
4. var buf []byte
5. if count == 1 {
6. buf = db.pagePool.Get().([]byte)
7. } else {
8. buf = make([]byte, count*db.pageSize)
9. }
10. // 转成*page
11. p := (*page)(unsafe.Pointer(&buf[0]))
12. p.overflow = uint32(count - 1)

14. // Use pages from the freelist if they are available.
15. // 先从空闲列表中找
16. if p.id = db.freelist.allocate(count); p.id != 0 {
17. return p, nil
18. }

20. // 找不到的话,就按照事务的pgid来分配
21. // 表示需要从文件内部扩大

23. // Resize mmap() if we're at the end.
24. p.id = db.rwtx.meta.pgid
25. // 因此需要判断是否目前所有的页数已经大于了mmap映射出来的空间
26. // 这儿计算的页面总数是从当前的id后还要计算count+1个
27. var minsz = int((p.id+pgid(count))+1) * db.pageSize
28. if minsz >= db.datasz {
29. if err := db.mmap(minsz); err != nil {
30. return nil, fmt.Errorf("mmap allocate error: %s", err)
31. }
32. }

34. // Move the page id high water mark.
35. // 如果不是从freelist中找到的空间的话,更新meta的id,也就意味着是从文件中新扩展的页
36. db.rwtx.meta.pgid += pgid(count)

38. return p, nil
39. }

41. // grow grows the size of the database to the given sz.
42. func (db *DB) grow(sz int) error {
43. // Ignore if the new size is less than available file size.
44. if sz <= db.filesz {
45. return nil
46. }

48. // 满足这个条件sz>filesz

50. // If the data is smaller than the alloc size then only allocate what's needed.
51. // Once it goes over the allocation size then allocate in chunks.
52. if db.datasz < db.AllocSize {
53. sz = db.datasz
54. } else {
55. sz += db.AllocSize
56. }

58. // Truncate and fsync to ensure file size metadata is flushed.
59. // https://github.com/boltdb/bolt/issues/284
60. if !db.NoGrowSync && !db.readOnly {
61. if runtime.GOOS != "windows" {
62. if err := db.file.Truncate(int64(sz)); err != nil {
63. return fmt.Errorf("file resize error: %s", err)
64. }
65. }
66. if err := db.file.Sync(); err != nil {
67. return fmt.Errorf("file sync error: %s", err)
68. }
69. }

71. db.filesz = sz
72. return nil
73. }