Blockchain Learning Day05 (Implementing levelDB)

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:

  1. POW mining
  2. Put the block into the chain (linked list)
  3. Data persistence storage (levelDB)
  4. 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()))
	}
}

Insert image description here

Test results:
Insert image description here
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

Insert image description here

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.

Guess you like

Origin blog.csdn.net/weixin_44774466/article/details/135165675