package main
import (
"fmt"
"sync"
"time"
)
type Storage interface {
Set(key string, value interface{})
Get(key string) interface{}
}
/*
Please implement Storage interface. Operations should be thread safe.
Get operation should wait for all active Set calls and return most last updated value.
Get/Set of different keys shouldn't affect each other.
Implementation should be encapsulated, no external logic munipulations ouside.
Don't spend time on validation code.
Use only golang standard library, no any 3rd-party packages.
Please fork snippet->do work and save-> send forked link to vlad.troinich@litmus.io
*/
// Thread safe -> lock all and defer unlock of all Set() calls
// Get() should wait for all set()s -> use waitGroup
// Attention! Presume Getters and setters will be called asynchronously
type Store struct {
wg sync.WaitGroup
mu sync.Mutex
storageData map[string]interface{}
}
func (s *Store) Set(key string, value interface{}) {
s.wg.Add(1)
defer s.wg.Done()
s.mu.Lock()
defer s.mu.Unlock()
// printing and sleeping for testing
fmt.Println("running set for key:", key, "value:", value)
// simulating hard work
time.Sleep(time.Second)
s.storageData[key] = value
}
func (s *Store) Get(key string) interface{} {
s.wg.Wait()
// printing for testing
fmt.Println("running get method")
if val, ok := s.storageData[key]; ok {
return val
}
return nil
}
// Test for thread safety
// Test for set() resolution before get()
func main() {
var s Storage
s.storageData = make(map[string]interface{})
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) { s.Set(fmt.Sprint(i), i); wg.Done() }(i)
}
// To test recently updated value
go func() { wg.Add(1); s.Set(fmt.Sprint(1), "replaced"); wg.Done() }()
// Sleeping to protect against race conditions
time.Sleep(time.Second)
go func() { wg.Add(1); fmt.Println(s.Get(fmt.Sprint(1))); wg.Done()}()
wg.Wait()
fmt.Println("done")
}