levelDB understand
Title 1. The process of mining. The Pow algorithm was used to complete mining earlier, which is divided into the following general steps:
- POW mining
- Put the block into the chain (linked list)
- Data persistence storage (levelDB)
- Broadcasting over a wide area network (UDP)
What is LevleDB?
- leveldb is a stand-alone kv storage system implemented by two Google engineers using C++.
- Key and value are arbitrary byte arrays, supporting storage and persistent storage.
- Data is sorted according to key, and users can override the sorting function.
- Contains basic data operation interfaces, Put(key,value),Delete(key)
- Multiple operations can be treated as one atomic operation. –Support things
Limitations of LevleDB
- Leveldb is a non-relational database and does not support SQL queries or indexes.
- Only a single process (supporting multi-threading) is supported to access the db at the same time.
- Client-server mode is not supported, users need to encapsulate it themselves.
LevleDB workflow
Store the data on the hard disk first to ensure that the data will not be lost, and then store it in the memory to facilitate efficient reading of the data.
Simulation writing
First create leveldb.go
package txt2
import "fmt"
// DB的结构体
type DB struct {
//模拟真实的场景
//地址
path string
//数据
data map[string][]byte
}
// 模拟开启链接,通过地址开启
func New(path string) (*DB, error) {
self := DB{
path: path,
data: make(map[string][]byte),
}
return &self, nil
}
// 模拟关闭链接
func (self *DB) Close() error {
return nil
}
func (self *DB) Put(key []byte, value []byte) error {
self.data[string(key)] = value
return nil
}
func (self *DB) Get(key []byte) ([]byte, error) {
if v, ok := self.data[string(key)]; ok {
return v, nil
} else {
return nil, fmt.Errorf("NotFound")
}
}
func (self *DB) Del(key []byte) error {
if _, ok := self.data[string(key)]; ok {
delete(self.data, string(key))
return nil
} else {
return fmt.Errorf("NotFound")
}
}
// 模拟遍历取值
//func (self *DB) Iterator() Iterator {
//
//}
Write another iterator iterator.go
package txt2
import "fmt"
// 写个迭代器
type Iterator interface {
//判断是否有下一个值
Nxet() bool
//遍历键值
Key() []byte
Value() []byte
}
// 定义一个键值的结构体
type Pair struct {
Key []byte
Value []byte
}
// 迭代器的结构体
type DefaultIterator struct {
//键值对
data []Pair
//索引和长度
index int
length int
}
// 创建默认的迭代器
func NewDefaultIterator(data map[string][]byte) *DefaultIterator {
self := new(DefaultIterator)
self.index = -1
self.length = len(data)
for k, v := range data {
p := Pair{
Key: []byte(k),
Value: v,
}
//把遍历到的数据添加到data里面
self.data = append(self.data, p)
}
return self
}
func (self *DefaultIterator) Next() bool {
//判断是否有下一个
if self.index < self.length-1 {
self.index++
return true
}
return false
}
func (self *DefaultIterator) Key() []byte {
//做个判断
if self.index == -1 || self.index >= self.length {
panic(fmt.Errorf("IndexOutofBoundError"))
}
return self.data[self.index].Key
}
func (self *DefaultIterator) Value() []byte {
//做个判断
if self.index >= self.length {
panic(fmt.Errorf("IndexOutofBoundError"))
}
return self.data[self.index].Value
}
Then write a test
package txt2
import (
"fmt"
"testing"
)
// 测试默认迭代器iterator_test.go
func TestNewDefaultIterator(t *testing.T) {
data := make(map[string][]byte)
data["K1"] = []byte("v1")
data["K2"] = []byte("v2")
data["K3"] = []byte("v3")
iter := NewDefaultIterator(data)
if iter.length != 3 {
t.Fatal()
}
for iter.Next() {
fmt.Printf("%s:%s\n", iter.Key(), string(iter.Value()))
}
}
Test results:
Create leveldb_test.go
package txt2
import (
"bytes"
"fmt"
"testing"
)
func Test_leveldb(t *testing.T) {
//先测试链接
db, err := New("")
check(err)
err = db.Put([]byte("K1"), []byte("v1"))
check(err)
err = db.Put([]byte("K2"), []byte("v2"))
check(err)
err = db.Put([]byte("K3"), []byte("v3"))
check(err)
//俩个K重复,看看效果
err = db.Put([]byte("K1"), []byte("v11"))
check(err)
err = db.Put([]byte("K8"), []byte("v8"))
check(err)
//取数据测试
v, err := db.Get([]byte("K8"))
fmt.Printf("%s\n", v)
//如果取的值不是v8
if !bytes.Equal(v, []byte("v8")) {
t.Fatal()
}
v, err = db.Get([]byte("K1"))
//(v, []byte("v1")) 会捕获到,,实际上k1是获取到v11的
if !bytes.Equal(v, []byte("v11")) {
t.Fatal()
}
//删除
err = db.Del([]byte("K1"))
check(err)
iter := db.Iterator()
for iter.Nxet() {
fmt.Printf("%s - %s\n", string(iter.Key()), string(iter.Value()))
}
}
func check(err error) {
if err != nil {
panic(err)
}
}
Subsequent code addition: leveldb.go
package txt2
import "fmt"
// DB的结构体
type DB struct {
//模拟真实的场景
//地址
path string
//数据
data map[string][]byte
}
// 模拟开启链接,通过地址开启
func New(path string) (*DB, error) {
self := DB{
path: path,
data: make(map[string][]byte),
}
return &self, nil
}
// 模拟关闭链接
func (self *DB) Close() error {
return nil
}
func (self *DB) Put(key []byte, value []byte) error {
self.data[string(key)] = value
return nil
}
func (self *DB) Get(key []byte) ([]byte, error) {
if v, ok := self.data[string(key)]; ok {
return v, nil
} else {
return nil, fmt.Errorf("NotFound")
}
}
func (self *DB) Del(key []byte) error {
if _, ok := self.data[string(key)]; ok {
delete(self.data, string(key))
return nil
} else {
return fmt.Errorf("NotFound")
}
}
// 模拟遍历取值
func (self *DB) Iterator() Iterator {
return NewDefaultIterator(self.data)
}
Supplement: iterator_test.go
package txt2
import (
"fmt"
"testing"
)
// 测试默认迭代器
func TestNewDefaultIterator(t *testing.T) {
data := make(map[string][]byte)
data["K1"] = []byte("v1")
data["K2"] = []byte("v2")
data["K3"] = []byte("v3")
iter := NewDefaultIterator(data)
if iter.length != 3 {
t.Fatal()
}
for iter.Nxet() {
fmt.Printf("%s:%s\n", iter.Key(), string(iter.Value()))
}
}
Running leveldb_test.go results
There is a lot of code. If you don’t understand it, I suggest you use AI to read it.
In short, it is to implement a simple kv storage, memory level.