]> 127.0.0.1 Git - part/.git/commitdiff
1 v0.28.20240501061452
authorqydysky <qydysky@foxmail.com>
Wed, 1 May 2024 06:09:36 +0000 (06:09 +0000)
committerqydysky <qydysky@foxmail.com>
Wed, 1 May 2024 06:09:36 +0000 (06:09 +0000)
sync/Map.go
sync/Map_test.go

index 734adcf92fb86d61d32571fd0e0b6f9724973d87..18ef018b9881db3eabea617512a3c2356092e52a 100644 (file)
@@ -81,19 +81,20 @@ type MapExceeded[K, V any] struct {
 type mapExceededItem[V any] struct {
        data     *V
        exceeded time.Time
+       wait     sync.RWMutex
 }
 
 func (t *MapExceeded[K, V]) Store(k K, v *V, dur time.Duration) {
-       t.m.Store(k, mapExceededItem[V]{
+       t.m.Store(k, &mapExceededItem[V]{
                data:     v,
                exceeded: time.Now().Add(dur),
        })
 }
 
 func (t *MapExceeded[K, V]) Load(k K) (*V, bool) {
-       if v, ok := t.m.Load(k); ok {
-               if v.(mapExceededItem[V]).exceeded.After(time.Now()) {
-                       return v.(mapExceededItem[V]).data, true
+       if v, ok := t.m.LoadV(k).(*mapExceededItem[V]); ok {
+               if v.exceeded.After(time.Now()) {
+                       return v.data, true
                }
                t.Delete(k)
        }
@@ -102,7 +103,7 @@ func (t *MapExceeded[K, V]) Load(k K) (*V, bool) {
 
 func (t *MapExceeded[K, V]) Range(f func(key K, value *V) bool) {
        t.m.Range(func(key, value any) bool {
-               if value.(mapExceededItem[V]).exceeded.After(time.Now()) {
+               if value.(*mapExceededItem[V]).exceeded.After(time.Now()) {
                        return f(key.(K), value.(*V))
                }
                t.Delete(key.(K))
@@ -116,7 +117,7 @@ func (t *MapExceeded[K, V]) Len() int {
 
 func (t *MapExceeded[K, V]) GC() {
        t.m.Range(func(key, value any) bool {
-               if value.(mapExceededItem[V]).exceeded.Before(time.Now()) {
+               if value.(*mapExceededItem[V]).exceeded.Before(time.Now()) {
                        t.Delete(key.(K))
                }
                return true
@@ -126,3 +127,34 @@ func (t *MapExceeded[K, V]) GC() {
 func (t *MapExceeded[K, V]) Delete(k K) {
        t.m.Delete(k)
 }
+
+func (t *MapExceeded[K, V]) LoadOrStore(k K) (vr *V, loaded bool, store func(v1 *V, dur time.Duration)) {
+       store = func(v1 *V, dur time.Duration) {}
+       var actual any
+       actual, loaded = t.m.LoadOrStore(k, &mapExceededItem[V]{})
+       v := actual.(*mapExceededItem[V])
+       v.wait.RLock()
+       exp := v.exceeded
+       vr = v.data
+       v.wait.RUnlock()
+       if loaded && time.Now().Before(exp) {
+               return
+       }
+       if !loaded || (loaded && !exp.IsZero()) {
+               store = func(v1 *V, dur time.Duration) {
+                       v.wait.Lock()
+                       v.data = v1
+                       v.exceeded = time.Now().Add(dur)
+                       v.wait.Unlock()
+               }
+               return
+       }
+       for loaded && exp.IsZero() {
+               time.Sleep(time.Millisecond * 20)
+               v.wait.RLock()
+               exp = v.exceeded
+               vr = v.data
+               v.wait.RUnlock()
+       }
+       return
+}
index fa71d0f8e8d9e1f5a34f4bd566e874b32e92a3dd..ef821ec6844560a7b5624ce7d565598d6cdb7fed 100644 (file)
@@ -346,3 +346,30 @@ func TestMapExceeded1(t *testing.T) {
                t.Fatal()
        }
 }
+
+func TestMapExceeded2(t *testing.T) {
+       var m MapExceeded[string, []byte]
+       var data = []byte("1")
+       if v, loaded, f := m.LoadOrStore("1"); v != nil || loaded {
+               t.Fatal()
+       } else {
+               f(&data, time.Second)
+               if v, ok := m.Load("1"); !ok || v == nil || !bytes.Equal(data, *v) {
+                       t.Fatal()
+               }
+       }
+
+       var w sync.WaitGroup
+       w.Add(10)
+       for i := 0; i < 10; i++ {
+               go func() {
+                       v, loaded, f := m.LoadOrStore("2")
+                       if (!loaded && v != nil) || (loaded && !bytes.Equal(data, *v)) {
+                               panic("")
+                       }
+                       f(&data, time.Second)
+                       w.Done()
+               }()
+       }
+       w.Wait()
+}