欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis內(nèi)存數(shù)據(jù)庫(kù)示例分析

 更新時(shí)間:2022年12月19日 12:17:13   作者:上后左愛  
Redis本身的內(nèi)容比較復(fù)雜。如果你上來(lái),你應(yīng)該研究一個(gè)細(xì)節(jié)點(diǎn),比如連接池和數(shù)據(jù)結(jié)構(gòu)。雖然可以直接了解某一點(diǎn)的詳細(xì)來(lái)源內(nèi)容,甚至盡快解決一些意外,但是容易淹沒在失眠的細(xì)節(jié)中,整體控制不了Redis

redies dict字典

這是 Redis 最底層的結(jié)構(gòu),比如 1個(gè)DB 下面有 16個(gè)Dict

1. 使用接口方式, 基礎(chǔ)實(shí)現(xiàn)是simple_dict ,sync_dict ,后續(xù)用戶可以根據(jù)自己的需求進(jìn)行自定義的實(shí)現(xiàn)屬于自己的Dict , 在 forEach 方法 支持匿名函數(shù)方式
type Dict interface {
  Get(key string) (val interface {}, exists bool)
  Len()
  // 回復(fù)上次 put 放入
  Put(key string, val interface{}) (result int)
  PutIfAbsent(key string, val interface {}) (result int)
  PutIfExists(key string, val interface{}) (result int)
  Remove(key string) (result int)
  ForEach(consumer Consumer) // 傳入是方法, 返回 bool = true j繼續(xù)遍歷 
  Keys() []string
  RandomKeys(limit int) []string
  // 返回多個(gè)不重復(fù)的鍵
  RandomDistinctKeys(limit int) []string
  Clear()
}
// Consumer is used to traversal dict, if it returns false the traversal will be break
type Consumer func(key string, val interface{}) bool
package dict
// SimpleDict wraps a map, it is not thread safe
type SimpleDict struct {
	m map[string]interface{}
}
// MakeSimple makes a new map
func MakeSimple() *SimpleDict {
	return &SimpleDict{
		m: make(map[string]interface{}),
	}
}
// Get returns the binding value and whether the key is exist
func (dict *SimpleDict) Get(key string) (val interface{}, exists bool) {
	val, ok := dict.m[key]
	return val, ok
}
// Len returns the number of dict
func (dict *SimpleDict) Len() int {
	if dict.m == nil {
		panic("m is nil")
	}
	return len(dict.m)
}
// Put puts key value into dict and returns the number of new inserted key-value
func (dict *SimpleDict) Put(key string, val interface{}) (result int) {
	_, existed := dict.m[key]
	dict.m[key] = val
	if existed {
		return 0
	}
	return 1
}
// PutIfAbsent puts value if the key is not exists and returns the number of updated key-value
func (dict *SimpleDict) PutIfAbsent(key string, val interface{}) (result int) {
	_, existed := dict.m[key]
	if existed {
		return 0
	}
	dict.m[key] = val
	return 1
}
// PutIfExists puts value if the key is exist and returns the number of inserted key-value
func (dict *SimpleDict) PutIfExists(key string, val interface{}) (result int) {
	_, existed := dict.m[key]
	if existed {
		dict.m[key] = val
		return 1
	}
	return 0
}
// Remove removes the key and return the number of deleted key-value
func (dict *SimpleDict) Remove(key string) (result int) {
	_, existed := dict.m[key]
	delete(dict.m, key)
	if existed {
		return 1
	}
	return 0
}
// Keys returns all keys in dict
func (dict *SimpleDict) Keys() []string {
	result := make([]string, len(dict.m))
	i := 0
	for k := range dict.m {
		result[i] = k
	}
	return result
}
// ForEach traversal the dict
func (dict *SimpleDict) ForEach(consumer Consumer) {
	for k, v := range dict.m {
		if !consumer(k, v) {
			break
		}
	}
}
// RandomKeys randomly returns keys of the given number, may contain duplicated key
func (dict *SimpleDict) RandomKeys(limit int) []string {
	result := make([]string, limit)
	for i := 0; i < limit; i++ {
		for k := range dict.m {
			result[i] = k
			break
		}
	}
	return result
}
// RandomDistinctKeys randomly returns keys of the given number, won't contain duplicated key
func (dict *SimpleDict) RandomDistinctKeys(limit int) []string {
	size := limit
	if size > len(dict.m) {
		size = len(dict.m)
	}
	result := make([]string, size)
	i := 0
	for k := range dict.m {
		if i == limit {
			break
		}
		result[i] = k
		i++
	}
	return result
}
// Clear removes all keys in dict
func (dict *SimpleDict) Clear() {
	*dict = *MakeSimple()
}

Redis的DB實(shí)現(xiàn)

針對(duì)其中 Command 的實(shí)現(xiàn), ping, set ,Get 有具體的實(shí)現(xiàn)方法, 采用策略模式形式, 不同的方法 有自己的 Executor 執(zhí)行器

// 指令與結(jié)構(gòu)體之間的關(guān)系
var cmdTable = make(map[string]*command)
type command struct {
	executor ExecFunc
	arity    int // allow number of args, arity < 0 means len(args) >= -arity
}
// RegisterCommand registers a new command
// arity means allowed number of cmdArgs, arity < 0 means len(args) >= -arity.
// for example: the arity of `get` is 2, `mget` is -2
func RegisterCommand(name string, executor ExecFunc, arity int) {
	name = strings.ToLower(name)
	cmdTable[name] = &command{
		executor: executor,
		arity:    arity,
	}
}
// Package database is a memory database with redis compatible interface
package database
import (
	"go-redis/datastruct/dict"
	"go-redis/interface/database"
	"go-redis/interface/resp"
	"go-redis/resp/reply"
	"strings"
)
// DB stores data and execute user's commands
type DB struct {
	index int
	// key -> DataEntity
	data dict.Dict // 底層的實(shí)現(xiàn)可以進(jìn)行切換
}
// ExecFunc is interface for command executor, redis 的 指令實(shí)現(xiàn), 所有的實(shí)現(xiàn) 協(xié)程這種形式
// args don't include cmd line
type ExecFunc func(db *DB, args [][]byte) resp.Reply
// CmdLine is alias for [][]byte, represents a command line
type CmdLine = [][]byte
// makeDB create DB instance
func makeDB() *DB {
	db := &DB{
		data: dict.MakeSyncDict(), // 使用的 sync 的 dict
	}
	return db
}
// Exec executes command within one database
func (db *DB) Exec(c resp.Connection, cmdLine [][]byte) resp.Reply {
	cmdName := strings.ToLower(string(cmdLine[0]))
	cmd, ok := cmdTable[cmdName]
	if !ok {
		return reply.MakeErrReply("ERR unknown command '" + cmdName + "'")
	}
	if !validateArity(cmd.arity, cmdLine) {
		return reply.MakeArgNumErrReply(cmdName)
	}
	fun := cmd.executor
	return fun(db, cmdLine[1:])
}
func validateArity(arity int, cmdArgs [][]byte) bool {
	argNum := len(cmdArgs)
	if arity >= 0 {
		return argNum == arity
	}
	return argNum >= -arity
}
/* ---- data Access ----- */
// GetEntity returns DataEntity bind to given key
func (db *DB) GetEntity(key string) (*database.DataEntity, bool) {
	raw, ok := db.data.Get(key)
	if !ok {
		return nil, false
	}
	entity, _ := raw.(*database.DataEntity)
	return entity, true
}
// PutEntity a DataEntity into DB
func (db *DB) PutEntity(key string, entity *database.DataEntity) int {
	return db.data.Put(key, entity)
}
// PutIfExists edit an existing DataEntity
func (db *DB) PutIfExists(key string, entity *database.DataEntity) int {
	return db.data.PutIfExists(key, entity)
}
// PutIfAbsent insert an DataEntity only if the key not exists
func (db *DB) PutIfAbsent(key string, entity *database.DataEntity) int {
	return db.data.PutIfAbsent(key, entity)
}
// Remove the given key from db
func (db *DB) Remove(key string) {
	db.data.Remove(key)
}
// Removes the given keys from db
func (db *DB) Removes(keys ...string) (deleted int) {
	deleted = 0
	for _, key := range keys {
		_, exists := db.data.Get(key)
		if exists {
			db.Remove(key)
			deleted++
		}
	}
	return deleted
}
// Flush clean database
func (db *DB) Flush() {
	db.data.Clear()
}

具體的實(shí)現(xiàn)器

// Ping Executor
func Ping(db *DB, args [][]byte) resp.Reply {
    if len(args) == 0 {
        return &reply.PongReply{}
    } else if len(args) == 1 {
        return reply.MakeStatusReply(string(args[0]))
    } else {
        return reply.MakeErrReply("ERR wrong number of arguments for 'ping' command")
    }
}
// 初始化 方法
func init() {
    RegisterCommand("ping", Ping, -1)
}

Redis持久化Aof

AOF 則以協(xié)議文本的方式,將所有對(duì)數(shù)據(jù)庫(kù)進(jìn)行過寫入的命令(及其參數(shù))記錄到 AOF 文件,以此達(dá)到記錄數(shù)據(jù)庫(kù)狀態(tài)的目的.

package aof
import (
	"go-redis/config"
	databaseface "go-redis/interface/database"
	"go-redis/lib/logger"
	"go-redis/lib/utils"
	"go-redis/resp/connection"
	"go-redis/resp/parser"
	"go-redis/resp/reply"
	"io"
	"os"
	"strconv"
)
// CmdLine is alias for [][]byte, represents a command line
type CmdLine = [][]byte
const (
	aofQueueSize = 1 << 16
)
type payload struct {
	cmdLine CmdLine
	dbIndex int
}
// AofHandler receive msgs from channel and write to AOF file
type AofHandler struct {
	db          databaseface.Database
	aofChan     chan *payload
	aofFile     *os.File
	aofFilename string
	currentDB   int
}
// NewAOFHandler creates a new aof.AofHandler
func NewAOFHandler(db databaseface.Database) (*AofHandler, error) {
	handler := &AofHandler{}
	handler.aofFilename = config.Properties.AppendFilename
	handler.db = db
	// init Load Aof to Memory
	handler.LoadAof()
	aofFile, err := os.OpenFile(handler.aofFilename, os.O_APPEND|os.O_CREATE|os.O_RDWR, 0600)
	if err != nil {
		return nil, err
	}
	handler.aofFile = aofFile
	handler.aofChan = make(chan *payload, aofQueueSize)
	go func() {
		handler.handleAof()
	}()
	return handler, nil
}
func (handler *AofHandler) AddAof(dbIndex int, cmdLine CmdLine) {
	if config.Properties.AppendOnly && handler.aofChan != nil {
		handler.aofChan <- &payload{
			cmdLine: cmdLine,
			dbIndex: dbIndex,
		}
	}
}
// LoadAof read aof file 數(shù)據(jù)回放的功能
func (handler *AofHandler) LoadAof() {
	file, err := os.Open(handler.aofFilename)
	if err != nil {
		logger.Warn(err)
		return
	}
	defer func(file *os.File) {
		err := file.Close()
		if err != nil {
		}
	}(file)
	ch := parser.ParseStream(file)
	fakeConn := &connection.Connection{} // only used for save dbIndex
	// LoadAof recover data
	for p := range ch {
		if p.Err != nil {
			if p.Err == io.EOF {
				break
			}
			logger.Error("parse error: " + p.Err.Error())
			continue
		}
		if p.Data == nil {
			logger.Error("empty payload")
			continue
		}
		r, ok := p.Data.(*reply.MultiBulkReply)
		if !ok {
			logger.Error("require multi bulk reply")
			continue
		}
		ret := handler.db.Exec(fakeConn, r.Args)
		if reply.IsErrorReply(ret) {
			logger.Error("exec err", err)
		}
	}
}
// handleAof listen aof channel and write into file aof 異步形式的落盤
func (handler *AofHandler) handleAof() {
	handler.currentDB = 0
	for p := range handler.aofChan {
		if p.dbIndex != handler.currentDB {
			// select db
			data := reply.MakeMultiBulkReply(utils.ToCmdLine("SELECT", strconv.Itoa(p.dbIndex))).ToBytes()
			_, err := handler.aofFile.Write(data)
			if err != nil {
				logger.Warn(err)
				continue // skip this command
			}
			handler.currentDB = p.dbIndex
		}
		data := reply.MakeMultiBulkReply(p.cmdLine).ToBytes()
		_, err := handler.aofFile.Write(data)
		if err != nil {
			logger.Warn(err)
		}
	}
}

到此這篇關(guān)于Redis內(nèi)存數(shù)據(jù)庫(kù)示例分析的文章就介紹到這了,更多相關(guān)Redis內(nèi)存數(shù)據(jù)庫(kù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java FileWriter輸出換行操作

    Java FileWriter輸出換行操作

    這篇文章主要介紹了Java FileWriter輸出換行操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 推薦一款I(lǐng)ntelliJ IDEA提示快捷鍵的Key Promoter X插件

    推薦一款I(lǐng)ntelliJ IDEA提示快捷鍵的Key Promoter X插件

    今天小編就為大家分享一篇關(guān)于IntelliJ IDEA提示快捷鍵的Key Promoter X插件,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-10-10
  • 關(guān)于Java從本地文件復(fù)制到網(wǎng)絡(luò)文件上傳

    關(guān)于Java從本地文件復(fù)制到網(wǎng)絡(luò)文件上傳

    這篇文章主要介紹了關(guān)于Java從本地文件復(fù)制到網(wǎng)絡(luò)文件上傳,File?和?IO?流其實(shí)是很相似的,都是將文件從一個(gè)地方轉(zhuǎn)移到另一個(gè)地方,這也是流的特點(diǎn)之一,需要的朋友可以參考下
    2023-04-04
  • 淺談Java多線程編程中Boolean常量的同步問題

    淺談Java多線程編程中Boolean常量的同步問題

    這篇文章主要介紹了淺談Java多線程編程中Boolean常量的同步問題,主要針對(duì)線程之間同步了不同的布爾對(duì)象的問題,需要的朋友可以參考下
    2015-10-10
  • 使用maven?shade插件解決項(xiàng)目版本沖突詳解

    使用maven?shade插件解決項(xiàng)目版本沖突詳解

    這篇文章主要為大家介紹了使用maven?shade插件解決項(xiàng)目版本沖突詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • 詳解elasticsearch之metric聚合實(shí)現(xiàn)示例

    詳解elasticsearch之metric聚合實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了elasticsearch之metric聚合實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • java學(xué)習(xí)之JasperReport踩坑

    java學(xué)習(xí)之JasperReport踩坑

    本篇文章介紹的是在JAVA學(xué)習(xí)中JasperReport遇到的坑以及解決辦法,有需要的朋友參考下吧。
    2018-01-01
  • java代碼實(shí)現(xiàn)mysql分表操作(用戶行為記錄)

    java代碼實(shí)現(xiàn)mysql分表操作(用戶行為記錄)

    這篇文章主要介紹了java代碼實(shí)現(xiàn)mysql分表操作(用戶行為記錄),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧
    2021-02-02
  • 多數(shù)據(jù)源@DS和@Transactional實(shí)戰(zhàn)

    多數(shù)據(jù)源@DS和@Transactional實(shí)戰(zhàn)

    這篇文章主要介紹了多數(shù)據(jù)源@DS和@Transactional實(shí)戰(zhàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java跳出當(dāng)前的多重嵌套循環(huán)的五種方法

    Java跳出當(dāng)前的多重嵌套循環(huán)的五種方法

    在Java編程中,跳出多重嵌套循環(huán)可以使用break語(yǔ)句、標(biāo)號(hào)與break組合、return語(yǔ)句、標(biāo)志變量和異常處理五種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-10-10

最新評(píng)論