iMIKU.moe
300 字
2 分钟
LMDB - low menory database (only for cache)

LMDB - low menory database (only for cache)#

source#

package lmdb

const defaultFragmentCount = 128
const fragmentSize = 128

type LMDBIndex struct {
	Fragment uint
	Index    uint
}

type Item[T any] struct {
	realItem T
	deleted  bool
}

type Items[T any] struct {
	items        []Item[T]
	deletedCount uint
}

type LMDB[K comparable, V any] struct {
	length  uint
	m       map[K]LMDBIndex
	storage []Items[V]
}

func NewLMDB[K comparable, V any]() *LMDB[K, V] {
	return &LMDB[K, V]{
		length:  0,
		m:       make(map[K]LMDBIndex),
		storage: make([]Items[V], 0, defaultFragmentCount),
	}
}

func (m *LMDB[K, V]) Get(key K) (*V, bool) {
	index, ok := m.m[key]
	if !ok {
		return nil, false
	}

	t := m.storage[index.Fragment].items[index.Index]
	return &t.realItem, true
}

func (m *LMDB[K, V]) getNextIndex() LMDBIndex {
	for fi, fragment := range m.storage {
		if fragment.deletedCount == 0 {
			continue
		}

		for ii := range fragmentSize {
			if ii >= len(fragment.items) {
				fragment.items = append(fragment.items, Item[V]{deleted: true})
				m.storage[fi] = fragment
				return LMDBIndex{
					Fragment: uint(fi),
					Index:    uint(ii - 1),
				}
			}
			item := fragment.items[ii]
			if !item.deleted {
				continue
			}
			return LMDBIndex{
				Fragment: uint(fi),
				Index:    uint(ii - 1),
			}
		}
	}

	m.storage = append(m.storage, Items[V]{
		items:        make([]Item[V], 1, fragmentSize),
		deletedCount: fragmentSize,
	})

	return LMDBIndex{
		Fragment: uint(len(m.storage) - 1),
		Index:    0,
	}
}

func (m *LMDB[K, V]) Set(key K, value V) {
	index, ok := m.m[key]
	if ok {
		m.storage[index.Fragment].items[index.Index] = Item[V]{
			realItem: value,
			deleted:  false,
		}
	} else {
		index = m.getNextIndex()
		m.m[key] = index
		fragment := m.storage[index.Fragment]
		fragment.items[index.Index] = Item[V]{
			realItem: value,
			deleted:  false,
		}
		m.storage[index.Fragment] = fragment
	}
	m.length++
}

func (m *LMDB[K, V]) Delete(key K) {
	index, ok := m.m[key]
	if !ok {
		return
	}
	fragment := m.storage[index.Fragment]
	fragment.items[index.Index] = Item[V]{
		deleted: true,
	}
	fragment.deletedCount++
	m.storage[index.Fragment] = fragment
	m.length--
	delete(m.m, key)
}

func (m *LMDB[K, V]) Len() uint {
	return m.length
}

type TestStruct struct {
	Str string
	Num int
}
LMDB - low menory database (only for cache)
https://blog.imiku.moe/posts/lmdb/
作者
delichik
发布于
2024-06-24
许可协议
CC BY-NC-SA 4.0