区块链学习Day05(实现levelDB)

levelDB了解

标题1.挖矿的过程,前面利用Pow算法完成挖矿,分为以下几个大概步骤:

  1. Pow挖矿
  2. 将区块放到链中(链表)
  3. 数据持久化存储(levelDB)
  4. 在广域网中做广播(UDP)

LevleDB是什么?

  • leveldb是google俩位工程师使用C++实现的单机版k-v存储系统。
  • key和value是任意的字节数组,支持存储和持久化存储。
  • 数据都是按照key排序,用户可以重写排序函数。
  • 包含基本的数据操作接口,Put(key,value),Delete(key)
  • 多操作可以当成一次原子操作。–支持事物

LevleDB的局限性

  • leveldb是非关系型数据库,不支持SQL查询也不支持索引。
  • 同一时间只支持单进程(支持多线程)访问db。
  • 不支持客户端-服务器模式,用户需要自己封装。

LevleDB的工作流程

先存硬盘,保证数据不会丢失,再存内存中,便于高效读取数据

模拟写法

先创建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 {
    
    
//
//}

再写一个迭代器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
}

然后再写一个测试

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()))
	}
}

在这里插入图片描述

测试结果:
在这里插入图片描述
创建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)
	}
}

后续代码补充: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)
}

补充: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()))
	}

}

运行leveldb_test.go结果

在这里插入图片描述

代码很多,不懂的建议用AI读一下,
简单来说就是实现一个简单的k-v存储,内存级的。

猜你喜欢

转载自blog.csdn.net/weixin_44774466/article/details/135165675