mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-07 21:47:02 +09:00
GO-2076 Add TryRemove method to Ocache
This commit is contained in:
parent
8e0e8ae47f
commit
e31b078c69
2 changed files with 113 additions and 0 deletions
|
@ -89,6 +89,8 @@ type OCache interface {
|
|||
Add(id string, value Object) (err error)
|
||||
// Remove closes and removes object
|
||||
Remove(ctx context.Context, id string) (ok bool, err error)
|
||||
// TryRemove Tries to close and to remove the object
|
||||
TryRemove(id string) (ok bool, err error)
|
||||
// ForEach iterates over all loaded objects, breaks when callback returns false
|
||||
ForEach(f func(v Object) (isContinue bool))
|
||||
// GC frees not used and expired objects
|
||||
|
@ -212,6 +214,45 @@ func (c *oCache) remove(ctx context.Context, e *entry) (ok bool, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (c *oCache) TryRemove(id string) (ok bool, err error) {
|
||||
c.mu.Lock()
|
||||
|
||||
if c.closed {
|
||||
c.mu.Unlock()
|
||||
return false, ErrClosed
|
||||
}
|
||||
|
||||
e, contains := c.data[id]
|
||||
if !contains {
|
||||
c.mu.Unlock()
|
||||
return false, ErrNotExists
|
||||
}
|
||||
|
||||
c.mu.Unlock()
|
||||
|
||||
prevState, _ := e.setClosing(false)
|
||||
if prevState == entryStateClosing || prevState == entryStateClosed {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
closed, err := e.value.TryClose(c.ttl)
|
||||
if err != nil {
|
||||
c.log.With("object_id", e.id).Warnf("try remove err: %v", err)
|
||||
return closed, err
|
||||
}
|
||||
|
||||
if !closed {
|
||||
e.setActive(true)
|
||||
return false, nil
|
||||
}
|
||||
|
||||
c.mu.Lock()
|
||||
e.setClosed()
|
||||
delete(c.data, e.id)
|
||||
c.mu.Unlock()
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (c *oCache) DoLockedIfNotExists(id string, action func() error) error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
|
|
@ -317,6 +317,78 @@ func Test_OCache_Remove(t *testing.T) {
|
|||
<-getCh
|
||||
require.Equal(t, []string{"close", "get"}, events)
|
||||
})
|
||||
t.Run("tryRemove simple", func(t *testing.T) {
|
||||
closeCh := make(chan struct{})
|
||||
getCh := make(chan struct{})
|
||||
c := New(func(ctx context.Context, id string) (value Object, err error) {
|
||||
return NewTestObject(id, true, closeCh), nil
|
||||
}, WithTTL(time.Millisecond*10))
|
||||
|
||||
val, err := c.Get(context.TODO(), "id")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, val)
|
||||
assert.Equal(t, 1, c.Len())
|
||||
// try removing the object, so we will wait on closing
|
||||
go func() {
|
||||
_, err := c.TryRemove("id")
|
||||
require.Equal(t, 0, c.Len())
|
||||
require.NoError(t, err)
|
||||
}()
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
|
||||
var events []string
|
||||
go func() {
|
||||
_, err := c.Get(context.TODO(), "id")
|
||||
require.Equal(t, 1, c.Len())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, val)
|
||||
events = append(events, "get")
|
||||
close(getCh)
|
||||
}()
|
||||
// sleeping to make sure that Get is called
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
events = append(events, "close")
|
||||
close(closeCh)
|
||||
|
||||
<-getCh
|
||||
require.Equal(t, []string{"close", "get"}, events)
|
||||
})
|
||||
t.Run("tryRemove simple - can't be removed", func(t *testing.T) {
|
||||
closeCh := make(chan struct{})
|
||||
getCh := make(chan struct{})
|
||||
c := New(func(ctx context.Context, id string) (value Object, err error) {
|
||||
return NewTestObject(id, false, closeCh), nil
|
||||
}, WithTTL(time.Millisecond*10))
|
||||
|
||||
val, err := c.Get(context.TODO(), "id")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, val)
|
||||
assert.Equal(t, 1, c.Len())
|
||||
// try removing the object, so we will wait on closing
|
||||
go func() {
|
||||
_, err := c.TryRemove("id")
|
||||
require.Equal(t, 1, c.Len())
|
||||
require.NoError(t, err)
|
||||
}()
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
|
||||
var events []string
|
||||
go func() {
|
||||
_, err := c.Get(context.TODO(), "id")
|
||||
require.Equal(t, 1, c.Len())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, val)
|
||||
events = append(events, "get")
|
||||
close(getCh)
|
||||
}()
|
||||
// sleeping to make sure that Get is called
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
events = append(events, "close")
|
||||
close(closeCh)
|
||||
|
||||
<-getCh
|
||||
require.Equal(t, []string{"close", "get"}, events)
|
||||
})
|
||||
t.Run("test remove while gc, tryClose false", func(t *testing.T) {
|
||||
closeCh := make(chan struct{})
|
||||
removeCh := make(chan struct{})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue