Skip to content

Commit

Permalink
First steps in IdentityMap implementation (#23)
Browse files Browse the repository at this point in the history
Co-authored-by: Ivan Sushkov
  • Loading branch information
comeuplater authored Jun 4, 2024
1 parent ced92b6 commit 9c5ecba
Show file tree
Hide file tree
Showing 4 changed files with 430 additions and 0 deletions.
63 changes: 63 additions & 0 deletions grade/internal/infrastructure/seedwork/identity/map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package identity

import (
"errors"

"github.com/emacsway/grade/grade/pkg/collections"
)

var (
ErrObjectAlreadyWatched = errors.New("")
ErrObjectNotFound = errors.New("")
)

type IdentityMap[K comparable, V any] struct {
manageable collections.ReplacingMap[K, V]
isolation IsolationStrategy[K, V]
}

func NewIdentityMap[K comparable, V any](size uint) *IdentityMap[K, V] {
manageable := collections.NewReplacingMap[K, V](size)
isolation := serializableStrategy[K, V]{manageable: manageable}

return &IdentityMap[K, V]{
manageable: manageable,
isolation: &isolation,
}
}

func (im *IdentityMap[K, V]) Add(key K, object V) (bool, error) {
if err := im.isolation.add(key, object); err != nil {
return false, err
}

return true, nil
}

func (im *IdentityMap[K, V]) Get(key K) (object V, err error) {
return im.isolation.get(key)
}

func (im *IdentityMap[K, V]) Has(key K) bool {
return im.isolation.has(key)
}

func (im *IdentityMap[K, V]) SetSize(size uint) {
im.manageable.SetSize(size)
}

func (im *IdentityMap[K, V]) SetIsolationLevel(level IsolationLevel) {

switch level {
case ReadUncommitted:
im.isolation = &readUncommittedStrategy[K, V]{manageable: im.manageable}
case RepeatableReads:
im.isolation = &repeatableReadsStrategy[K, V]{manageable: im.manageable}
case Serializable:
im.isolation = &serializableStrategy[K, V]{manageable: im.manageable}
case ReadCommitted:
im.isolation = &readCommittedStrategy[K, V]{manageable: im.manageable}
default:
im.isolation = &serializableStrategy[K, V]{manageable: im.manageable}
}
}
91 changes: 91 additions & 0 deletions grade/internal/infrastructure/seedwork/identity/strategy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package identity

import (
"errors"

"github.com/emacsway/grade/grade/pkg/collections"
)

type IsolationLevel uint

const (
ReadUncommitted IsolationLevel = iota
ReadCommitted = iota
RepeatableReads = iota
Serializable = iota
)

var (
ErrNonexistentObject = errors.New("")
ErrDeniedOperationForStrategy = errors.New("")
)

type IsolationStrategy[K comparable, V any] interface {
add(key K, object V) error
get(key K) (V, error)
has(key K) bool
}

type readUncommittedStrategy[K comparable, V any] struct {
manageable collections.ReplacingMap[K, V]
}

func (r *readUncommittedStrategy[K, V]) add(key K, object V) error {

Check failure on line 33 in grade/internal/infrastructure/seedwork/identity/strategy.go

View workflow job for this annotation

GitHub Actions / lint

func (*readUncommittedStrategy[K, V]).add is unused (unused)
return nil
}

func (r *readUncommittedStrategy[K, V]) get(key K) (object V, err error) {

Check failure on line 37 in grade/internal/infrastructure/seedwork/identity/strategy.go

View workflow job for this annotation

GitHub Actions / lint

func (*readUncommittedStrategy[K, V]).get is unused (unused)
return object, ErrDeniedOperationForStrategy
}

func (r *readUncommittedStrategy[K, V]) has(key K) bool {

Check failure on line 41 in grade/internal/infrastructure/seedwork/identity/strategy.go

View workflow job for this annotation

GitHub Actions / lint

func (*readUncommittedStrategy[K, V]).has is unused (unused)
return false
}

type readCommittedStrategy[K comparable, V any] struct {
manageable collections.ReplacingMap[K, V]
}

func (r *readCommittedStrategy[K, V]) add(key K, object V) error {

Check failure on line 49 in grade/internal/infrastructure/seedwork/identity/strategy.go

View workflow job for this annotation

GitHub Actions / lint

func (*readCommittedStrategy[K, V]).add is unused (unused)
return nil
}

func (r *readCommittedStrategy[K, V]) get(key K) (object V, err error) {

Check failure on line 53 in grade/internal/infrastructure/seedwork/identity/strategy.go

View workflow job for this annotation

GitHub Actions / lint

func (*readCommittedStrategy[K, V]).get is unused (unused)
return object, nil
}

func (r *readCommittedStrategy[K, V]) has(key K) bool {

Check failure on line 57 in grade/internal/infrastructure/seedwork/identity/strategy.go

View workflow job for this annotation

GitHub Actions / lint

func (*readCommittedStrategy[K, V]).has is unused (unused)
return false
}

type repeatableReadsStrategy[K comparable, V any] struct {
manageable collections.ReplacingMap[K, V]
}

func (r *repeatableReadsStrategy[K, V]) add(key K, object V) error {

Check failure on line 65 in grade/internal/infrastructure/seedwork/identity/strategy.go

View workflow job for this annotation

GitHub Actions / lint

func (*repeatableReadsStrategy[K, V]).add is unused (unused)
return nil
}

func (r *repeatableReadsStrategy[K, V]) get(key K) (V, error) {

Check failure on line 69 in grade/internal/infrastructure/seedwork/identity/strategy.go

View workflow job for this annotation

GitHub Actions / lint

func (*repeatableReadsStrategy[K, V]).get is unused (unused)
return r.manageable.Get(key)
}

func (r *repeatableReadsStrategy[K, V]) has(key K) bool {

Check failure on line 73 in grade/internal/infrastructure/seedwork/identity/strategy.go

View workflow job for this annotation

GitHub Actions / lint

func (*repeatableReadsStrategy[K, V]).has is unused (unused)
return r.manageable.Has(key)
}

type serializableStrategy[K comparable, V any] struct {
manageable collections.ReplacingMap[K, V]
}

func (s *serializableStrategy[K, V]) add(key K, object V) error {
return nil
}

func (s *serializableStrategy[K, V]) get(key K) (V, error) {
return s.manageable.Get(key)
}

func (s *serializableStrategy[K, V]) has(key K) bool {
return s.manageable.Has(key)
}
103 changes: 103 additions & 0 deletions grade/pkg/collections/map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package collections

import (
"container/list"
"errors"
)

var (
ErrKeyDoesNotContains = errors.New("")
)

type CachedMap[K comparable, V any] struct {
m map[K]V
}

func NewCachedMap[K comparable, V any]() CachedMap[K, V] {
return CachedMap[K, V]{
m: map[K]V{},
}
}

func (m CachedMap[K, V]) Add(key K, value V) {
m.m[key] = value
}

func (m CachedMap[K, V]) Get(key K) (value V, err error) {
if value, found := m.m[key]; found {
return value, nil
}

return value, ErrKeyDoesNotContains
}

func (m CachedMap[K, V]) Remove(key K) {
delete(m.m, key)
}

func (m CachedMap[K, V]) Has(key K) bool {
_, found := m.m[key]
return found
}

type item[K comparable, V any] struct {
key K
value V
}

type ReplacingMap[K comparable, V any] struct {
items map[K]*list.Element
order *list.List
size uint
}

func NewReplacingMap[K comparable, V any](size uint) ReplacingMap[K, V] {
return ReplacingMap[K, V]{
items: make(map[K]*list.Element, size),
order: list.New(),
size: size,
}
}

func (m *ReplacingMap[K, V]) Add(key K, value V) {
element := m.order.PushBack(item[K, V]{key, value})
m.items[key] = element

if (uint)(len(m.items)) > m.size {

Check failure on line 66 in grade/pkg/collections/map.go

View workflow job for this annotation

GitHub Actions / lint

typeUnparen: could simplify (uint) to uint (gocritic)
element = m.order.Front()
m.order.Remove(element)
delete(m.items, element.Value.(item[K, V]).key)
}
}

func (m *ReplacingMap[K, V]) Get(key K) (value V, err error) {
if element, found := m.items[key]; found {
return element.Value.(item[K, V]).value, nil
}

return value, ErrKeyDoesNotContains
}

func (m *ReplacingMap[K, V]) Touch(key K) {
element := m.items[key]
m.order.MoveToBack(element)
}

func (m *ReplacingMap[K, V]) Remove(key K) {
element, found := m.items[key]
if !found {
return
}

delete(m.items, key)
m.order.Remove(element)
}

func (m *ReplacingMap[K, V]) Has(key K) bool {
_, found := m.items[key]
return found
}

func (m *ReplacingMap[K, V]) SetSize(size uint) {
m.size = size
}
Loading

0 comments on commit 9c5ecba

Please sign in to comment.