mydb

package module
v0.0.0-...-7dff01a Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 7, 2022 License: Apache-2.0 Imports: 14 Imported by: 0

README

mydb

my database practice (B+tree, mmap, transaction)

代码阅读顺序

page -> node -> freelist -> cursor -> tx -> bucket -> db

关于mmap相关代码,可以去bolt那边看bolt_*相关的文件,因为都是平台相关代码,所以就不拷过来,

这里基本把核心的都看了,注释也翻译完了

参考

https://github.com/boltdb/bolt

Documentation

Index

Constants

View Source
const (
	// MaxKeySize 一个键的最大字节数
	MaxKeySize = 32768

	// MaxValueSize 一个值的最大字节数
	MaxValueSize = (1 << 31) - 2
)
View Source
const (
	DefaultMaxBatchSize  int = 1000
	DefaultMaxBatchDelay     = 10 * time.Millisecond
	DefaultAllocSize         = 16 * 1024 * 1024
)

如果没有设置到DB实例,那就用下面的默认值

View Source
const DefaultFillPercent = 0.5

DefaultFillPercent 默认拆分一个页的百分比阀值, 这个可以通过Bucket.FillPercent来修改

View Source
const IgnoreNoSync = runtime.GOOS == "openbsd"

IgnoreNoSync 表示当要同步改动到文件时,DB里面的NoSync字段是否被忽略 因为有些操作系统例如OpenBSD,它没有联合缓冲缓存(UBC),每次写都必须用msync(2)系统调用同步

Variables

View Source
var DefaultOptions = &Options{
	Timeout:    0,
	NoGrowSync: false,
}

DefaultOptions 默认选项,当nil传入open()的时候用这个默认选项 这里timeout为0,将会无限等待一个文件锁的释放

Functions

This section is empty.

Types

type Bucket

type Bucket struct {

	// 这个值不会保存进磁盘,所以必须每个事务都要设置
	// 默认情况下页里面装到50%的数据时就会拆分,但是如果你大部分的写都是后面插入(append-only)的话,
	// 增加这个值大小非常有用
	FillPercent float64
	// contains filtered or unexported fields
}

Bucket 代表一个在数据库对键值对集合。

func (*Bucket) Bucket

func (b *Bucket) Bucket(name []byte) *Bucket

Bucket 通过名字搜索桶里面的子桶 如果桶不存在,返回nil 桶只在事务生命周期内有效

func (*Bucket) CreateBucket

func (b *Bucket) CreateBucket(key []byte) (*Bucket, error)

CreateBucket 给定一个键创建一个桶,并返回这个新桶 如果键已经存在,名字是空或者太长,则返回错误 桶实例只在事务的生命周期里面有效

func (*Bucket) CreateBucketIfNotExists

func (b *Bucket) CreateBucketIfNotExists(key []byte) (*Bucket, error)

CreateBucketIfNotExists 给定一个键创建一个桶,并返回这个新桶,如果桶已经存在,则返回该桶 如果名字是空或者太长,则返回错误 桶实例只在事务的生命周期里面有效

func (*Bucket) Cursor

func (b *Bucket) Cursor() *Cursor

Cursor 创建一个游标关联这个桶 游标只在事务打开的时候有效 事务关闭就别用游标了

func (*Bucket) Delete

func (b *Bucket) Delete(key []byte) error

Delete 在桶里面删除一个键 如果键不存在,什么都没有发生并返回错误 如果事务是只读事务,也会报错

func (*Bucket) DeleteBucket

func (b *Bucket) DeleteBucket(key []byte) error

DeleteBucket 删除给定的键对应的桶 如果桶不存在或者给定的键对应的不是个桶,就返回错误

func (*Bucket) ForEach

func (b *Bucket) ForEach(fn func(k, v []byte) error) error

ForEach 给桶里面的所有键值执行一个函数fn 如果函数fn返回错误,则循环结束,并返回这个错误给调用者 在函数fn里面不要修改这个桶,否则会导致未定义的行为

func (*Bucket) Get

func (b *Bucket) Get(key []byte) []byte

Get 获取桶里面键对应的值 如果键不存在,或者键是个桶,则返回nil 返回值只在事务生命周期下有效

func (*Bucket) NextSequence

func (b *Bucket) NextSequence() (uint64, error)

NextSequence 为这个桶返回下个自增的值

func (*Bucket) Put

func (b *Bucket) Put(key []byte, value []byte) error

Put 设置值到桶的键里面 如果键已经存在,则之前的值会被覆盖 传进来的value必须要在整个事务中有效 如果桶所在的事务是只读事务,键是空,键太大,或者键的值太大,则返回错误

func (*Bucket) Root

func (b *Bucket) Root() pgid

Root 返回桶的根页

func (*Bucket) Sequence

func (b *Bucket) Sequence() uint64

Sequence 返回桶当前的自增值(还没有增加它)

func (*Bucket) SetSequence

func (b *Bucket) SetSequence(v uint64) error

SetSequence 更新桶的自增值

func (*Bucket) Stats

func (b *Bucket) Stats() BucketStats

Stat 返回桶的统计数据 (统计相关就不翻译了)

func (*Bucket) Tx

func (b *Bucket) Tx() *Tx

Tx 返回桶的事务

func (*Bucket) Writable

func (b *Bucket) Writable() bool

Writable 返回是否这个桶可写

type BucketStats

type BucketStats struct {
	// Page count statistics.
	BranchPageN     int // number of logical branch pages
	BranchOverflowN int // number of physical branch overflow pages
	LeafPageN       int // number of logical leaf pages
	LeafOverflowN   int // number of physical leaf overflow pages

	// Tree statistics.
	KeyN  int // number of keys/value pairs
	Depth int // number of levels in B+tree

	// Page size utilization.
	BranchAlloc int // bytes allocated for physical branch pages
	BranchInuse int // bytes actually used for branch data
	LeafAlloc   int // bytes allocated for physical leaf pages
	LeafInuse   int // bytes actually used for leaf data

	// Bucket statistics
	BucketN           int // total number of buckets including the top bucket
	InlineBucketN     int // total number on inlined buckets
	InlineBucketInuse int // bytes used for inlined buckets (also accounted for in LeafInuse)
}

BucketStats records statistics about resources used by a bucket. (统计相关不翻译了)

func (*BucketStats) Add

func (s *BucketStats) Add(other BucketStats)

type Cursor

type Cursor struct {
	// contains filtered or unexported fields
}

Cursor (游标)用来有序的遍历一个桶里面所有的key/value, 游标看到桶类型的页时返回的value是nil 游标从一个事务中获得,而且只在这个事务中有效 同理游标返回的key/value也是只在当前事务中有效 改变游标返回的key/value可能会使游标无效 并返回不符合期望的key/value。在改变数据之后,你必须重置你的游标

func (*Cursor) Bucket

func (c *Cursor) Bucket() *Bucket

返回创建游标的桶

func (*Cursor) Delete

func (c *Cursor) Delete() error

从桶中移除当前游标所在的键值 如果删除的是个桶或者事务只读的时候会删除失败

func (*Cursor) First

func (c *Cursor) First() (key []byte, value []byte)

移动游标到桶里的第一个元素并返回key和value 如果桶是空的,返回nil 这返回的key和value只在当前事务有效

func (*Cursor) Last

func (c *Cursor) Last() (key []byte, value []byte)

移动游标到桶里的最后一个元素并返回key和value 如果桶是空的,返回nil 这返回的key和value只在当前事务有效

func (*Cursor) Next

func (c *Cursor) Next() (key []byte, value []byte)

移动游标到下一个元素并返回key和value 如果游标已经在桶的底部了,则返回nil 这返回的key和value只在当前事务有效

func (*Cursor) Prev

func (c *Cursor) Prev() (key []byte, value []byte)

移动游标到前一个元素并返回key和value 如果游标已经在桶的开始,则返回nil 这返回的key和value只在当前事务有效

func (*Cursor) Seek

func (c *Cursor) Seek(seek []byte) (key []byte, value []byte)

移动游标到给定的键所在的位置并返回它 如果这个键不存在,那返回它下一个键,如果也没有就返回nil 这返回的键值只在当前事务有效

type DB

type DB struct {
	// 如果启用,数据库会在每次提交的时候调用Check()
	// 如果数据库处于不一致状态就会报panic
	// 因为这个标志有很大性能影响,所以应该只用在调试的时候
	StrictMode bool

	// 设置NoSync标志将导致数据库在每次提交时跳过fsync()
	// 这对于批量加载数据进数据库非常有用,这样你可以重启这个批量加载,即使发生了系统错误或数据库损害
	// 尽可能正常使用时不要设置这个标志位
	//
	// 如果包全局常量IgnoreNoSync是true,则这个值被忽略
	// 详情可以看看这个常量到注释
	//
	// 这个不安全,请谨慎使用
	NoSync bool

	// 当这个为true时,当扩张数据库时,跳过调用truncate
	// 当这个为true时,只在non-ext3/ext4 系统安全
	// 跳过truncate可以避免预分配硬盘空间和绕过在重新映射时truncate()和fsync()这两个系统调用
	//
	// https://github.com/boltdb/bolt/issues/284
	NoGrowSync bool

	// MmapFlags设置内存映射时的标志位
	// 如果你想读取数据库快点,并且你的linux版本是2.6.23+,
	// 请设置syscall.MAP_POPULATE,开启文件预读(sequential read-ahead)
	MmapFlags int

	// MaxBatchSize 是一个batch的最大容量
	// 默认值是DefaultMaxBatchSize
	// 如果小于等于0,则batch功能不可用
	// 不要在调用Batch的时候改这个值
	MaxBatchSize int

	// MaxBatchDelay 是开始一个batch之前的等待时间
	// 默认值是DefaultMaxBatchDelay
	// 如果小于等于0,则batch功能不可用
	// 不要在调用Batch的时候改这个值
	MaxBatchDelay time.Duration

	// 当数据库需要创建新当页时,AllocSize 是每次数据库扩张的时候加的量
	// 当扩张数据文件时,这样做是用来分摊调用truncate()和fsync()成本
	AllocSize int
	// contains filtered or unexported fields
}

DB 表示一个桶集合,并把桶持久化到文件里面 所有数据访问都是通过事务,而这个事务又可以从DB里面获得 如果访问之前没有打开Open(),则DB里面的所有函数都会返回ErrDatabaseNotOpen

func Open

func Open(path string, mode os.FileMode, options *Options) (*DB, error)

Open 给定一个路径,创建和打开一个数据库 如果数据库文件不存在,自动创建一个 options参数传入nil的话,数据库会用默认配置创建

func (*DB) Batch

func (db *DB) Batch(fn func(*Tx) error) error

Batch 调用一个函数fn,它的行为类似Update 除了:

1. 并发调用Batch,会合并到一个事务执行

2. 传给Batch的函数有可能被执行多次,无论这个函数报错没报错

这意味着Batch执行的函数必须是幂等的,而且在执行成功后数据才能持久化和被调用者看到

最大批大小和延迟时间可以通过这两个配置修改,DB.MaxBatchSize,DB.MaxBatchDelay

Batch 只有在多协程调用它时,有用

func (*DB) Begin

func (db *DB) Begin(writable bool) (*Tx, error)

Begin 开始一个新的事务 多个只读事务可以并发使用,但是一次只能有一个写事务 多个写事务会造成阻塞直到当前写事务完成为止

事务不应该依赖另外一个。如果一个协程里面有一个读事务和写事务,有可能会造成写事务死锁, 因为数据库会周期性变大然后重新映射,如果这时候有个读事务打开的时候,写事务就有可能死锁了

如果一个长时间运行的读事务,你可能需要设置DB.InitialMmapSize为一个足够大的值 这样就可以避免潜在的来自写事务的阻塞

重要:你在使用完之后必须关闭只读事务,否则数据库没办法重复利用那些旧的页

func (*DB) Close

func (db *DB) Close() error

Close 释放所有数据库资源 所有事务必须在数据库关闭之前关闭

func (*DB) GoString

func (db *DB) GoString() string

GoString 返回数据库的Go字符串的表示

func (*DB) Info

func (db *DB) Info() *Info

Info 这个是给内部去访问原始数据的,因为是通过c指针来访问,所以要小心点,或者就尽量别用吧

func (*DB) IsReadOnly

func (db *DB) IsReadOnly() bool

IsReadOnly 返回数据库是否为只读

func (*DB) Path

func (db *DB) Path() string

Path 返回当前打开的数据库文件的路径

func (*DB) Stats

func (db *DB) Stats() Stats

Stats 返回数据库的性能统计数据 这个只会在事务关闭后更新

func (*DB) String

func (db *DB) String() string

String 返回数据库的字符串的表示

func (*DB) Sync

func (db *DB) Sync() error

Sync 执行fdatasync()去同步数据到磁盘 在正常操作下是不需要调用这个方法到。但是如果设置了NoSync,则你就要手动调用这个方法来同步了

func (*DB) Update

func (db *DB) Update(fn func(*Tx) error) error

Update 在读写事务上下文下执行一个函数 如果函数没有错误返回,则事务会被提交 如果函数有错误返回,则事务回滚 任何错误从函数或者提交时候返回都会作为Update的返回值 尝试在函数里面手动提交或回滚事务都会报panic

func (*DB) View

func (db *DB) View(fn func(*Tx) error) error

View 在只读事务上下文下执行一个函数 任何错误从函数返回都会作为View的返回值 尝试在函数里面手动回滚事务都会报panic

type Info

type Info struct {
	Data     uintptr
	PageSize int
}

Info 内部使用的一个数据结构

type Options

type Options struct {
	// Timeout 是等文件锁的时间,如果设置为0,则会无限等下去。
	// 这个选项只有在Dawin和Linux下有效
	Timeout time.Duration

	// 在内存映射文件之前设置DB.NoGrowSync
	NoGrowSync bool

	// 以只读打开数据库。用flock(..., LOCK_SH |LOCK_NB)来获取一个共享锁
	ReadOnly bool

	// 在内存映射之前设置DB.MmapFlags
	MmapFlags int

	// InitialMmapSize 数据库的初始映射大小
	// 如果这个大小足够大,则读事务不会阻塞写事务(详情可以看DB.Begin)
	//
	// 如果小于等于0,则初始映射大小为0
	// 如果小于数据库文件大小,则它没有任何作用了
	InitialMmapSize int
}

Options 代表打开数据库是可设置的选项

type PageInfo

type PageInfo struct {
	ID            int
	Type          string
	Count         int
	OverflowCount int
}

一个用来更清晰描述页的页信息结构

type Stats

type Stats struct {
	// Freelist stats
	FreePageN     int // total number of free pages on the freelist
	PendingPageN  int // total number of pending pages on the freelist
	FreeAlloc     int // total bytes allocated in free pages
	FreelistInuse int // total bytes used by the freelist

	// Transaction stats
	TxN     int // total number of started read transactions
	OpenTxN int // number of currently open read transactions

	TxStats TxStats // global, ongoing stats.
}

Stats 数据库的统计数据

func (*Stats) Sub

func (s *Stats) Sub(other *Stats) Stats

Sub calculates and returns the difference between two sets of database stats. This is useful when obtaining stats at two different points and time and you need the performance counters that occurred within that time span. (统计相关就不翻译了)

type Tx

type Tx struct {

	// 这个标志是专门给写相关方法用的,例如WriteTo()
	// 设置这个标志,事务就用指定的标志位(syscall.O_DIRECT)来打开数据库文件来拷贝数据
	//
	// 默认这个标志是不设值的,因为没有这个标志已经满足大部分情况了
	// 但是如果数据库文件很大,大过可用内存的时候,要读出整个数据库的话,
	// 设置这个标志,那就可以利用syscall.O_DIRECT来避免损坏页高速缓存
	WriteFlag int
	// contains filtered or unexported fields
}

Tx 表示一个在数据库里的只读或者读写事务 只读事务只用来通过键获取值和创建游标 读写事务用来创建和删除桶,还有创建和删除键

重要:如果你用完了事务,你必须提交或回滚事务 否则页不能被回收,那就不能被读写事务去申请 一个长时间的读事务可能造成数据库大小很快的变大

func (*Tx) Bucket

func (tx *Tx) Bucket(name []byte) *Bucket

Bucket 通过名字返回桶 如果桶不存在返回nil 桶实例只在当前事务有效

func (*Tx) Check

func (tx *Tx) Check() <-chan error

Check 为这个事务在数据库上执行一堆一致性检查 如果找到不一致的,就返回一个错误

It can be safely run concurrently on a writable transaction. However, this incurs a high cost for large databases and databases with a lot of subbuckets because of caching. This overhead can be removed if running on a read-only transaction, however, it is not safe to execute other writer transactions at the same time.

func (*Tx) Commit

func (tx *Tx) Commit() error

Commit 在写事务到时候用来写所有改动到磁盘并更新meta页,如果写入磁盘时发生错误,就返回错误 Commit 也用来在只读事务中调用

func (*Tx) Copy

func (tx *Tx) Copy(w io.Writer) error

Copy 写完整的数据库到一个Writer 这个函数存在是为了向后兼容

废弃;请用WriteTo()代替

func (*Tx) CopyFile

func (tx *Tx) CopyFile(path string, mode os.FileMode) error

CopyFile 拷贝完整的数据库到指定路径下到文件 一个可读的事务用来拷贝可以使得在拷贝过程中安全的被其他事务使用数据库而不受影响

func (*Tx) CreateBucket

func (tx *Tx) CreateBucket(name []byte) (*Bucket, error)

CreateBucket 创建一个新桶 如果一个桶存在,桶名为空或者太长,就返回错误 桶实例只在当前事务有效

func (*Tx) CreateBucketIfNotExists

func (tx *Tx) CreateBucketIfNotExists(name []byte) (*Bucket, error)

CreateBucketIfNotExists 如果桶不存在就创建一个新桶 如果桶名为空或者太长,就返回错误 桶实例只在当前事务有效

func (*Tx) Cursor

func (tx *Tx) Cursor() *Cursor

Cursor 创建一个跟根桶关联的游标 游标返回的只有键,值是nil,因为根桶的键都是指向桶 游标只在事务打开的时候有效 事务关闭后不要使用游标了

func (*Tx) DB

func (tx *Tx) DB() *DB

DB 返回一个创建当前事务的数据库引用

func (*Tx) DeleteBucket

func (tx *Tx) DeleteBucket(name []byte) error

DeleteBucket 删除一个桶 如果桶不存在或者根据桶名搜索这个桶时返回的不是一个桶该返回的值时报错

func (*Tx) ForEach

func (tx *Tx) ForEach(fn func(name []byte, b *Bucket) error) error

ForEach 循环在根上的所有桶执行一个函数 如果函数返回错误,则循环停止,并返回该错误给调用者

func (*Tx) ID

func (tx *Tx) ID() int

ID 返回事务标识

func (*Tx) OnCommit

func (tx *Tx) OnCommit(fn func())

OnCommit 加一个回调函数,这个回调函数会在事务成功提交时执行

func (*Tx) Page

func (tx *Tx) Page(id int) (*PageInfo, error)

Page 通过页ID,返回一个页信息 在并发环境下,这是唯一安全的使用写事务的方法

func (*Tx) Rollback

func (tx *Tx) Rollback() error

Rollback 关闭事务并忽略所有之前的改动, 只读事务必须回滚和没有提交

func (*Tx) Size

func (tx *Tx) Size() int64

Size 返回当前事务下的数据库大小(字节)

func (*Tx) Stats

func (tx *Tx) Stats() TxStats

Stats 返回当前事务统计数据的一个拷贝

func (*Tx) Writable

func (tx *Tx) Writable() bool

Writable 返回事务是否可以执行写操作

func (*Tx) WriteTo

func (tx *Tx) WriteTo(w io.Writer) (n int64, err error)

WriteTo 写完整的数据库到一个Writer 如果 err == nil 则写入 tx.Size() 字节到 writer.

type TxStats

type TxStats struct {
	// Page statistics.
	PageCount int // number of page allocations
	PageAlloc int // total bytes allocated

	// Cursor statistics.
	CursorCount int // number of cursors created

	// Node statistics
	NodeCount int // number of node allocations
	NodeDeref int // number of node dereferences

	// Rebalance statistics.
	Rebalance     int           // number of node rebalances
	RebalanceTime time.Duration // total time spent rebalancing

	// Split/Spill statistics.
	Split     int           // number of nodes split
	Spill     int           // number of nodes spilled
	SpillTime time.Duration // total time spent spilling

	// Write statistics.
	Write     int           // number of writes performed
	WriteTime time.Duration // total time spent writing to disk
}

TxStats 代表这个事务执行的动作的统计数据

func (*TxStats) Sub

func (s *TxStats) Sub(other *TxStats) TxStats

Sub calculates and returns the difference between two sets of transaction stats. This is useful when obtaining stats at two different points and time and you need the performance counters that occurred within that time span.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL