2017-03-14 15:10:45 +00:00
|
|
|
package maptracker
|
|
|
|
|
|
|
|
import (
|
2018-04-18 04:53:41 +00:00
|
|
|
"context"
|
2018-05-04 11:18:30 +00:00
|
|
|
"errors"
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
"math/rand"
|
|
|
|
"sync"
|
2017-03-14 15:10:45 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
cid "github.com/ipfs/go-cid"
|
2018-10-17 13:28:03 +00:00
|
|
|
rpc "github.com/libp2p/go-libp2p-gorpc"
|
2017-03-14 15:10:45 +00:00
|
|
|
peer "github.com/libp2p/go-libp2p-peer"
|
|
|
|
|
|
|
|
"github.com/ipfs/ipfs-cluster/api"
|
|
|
|
"github.com/ipfs/ipfs-cluster/test"
|
|
|
|
)
|
|
|
|
|
2018-05-04 11:18:30 +00:00
|
|
|
var (
|
2019-02-27 20:19:10 +00:00
|
|
|
pinCancelCid = test.Cid3
|
|
|
|
unpinCancelCid = test.Cid2
|
2018-05-04 11:18:30 +00:00
|
|
|
ErrPinCancelCid = errors.New("should not have received rpc.IPFSPin operation")
|
|
|
|
ErrUnpinCancelCid = errors.New("should not have received rpc.IPFSUnpin operation")
|
|
|
|
)
|
|
|
|
|
2018-04-18 04:53:41 +00:00
|
|
|
type mockService struct {
|
|
|
|
rpcClient *rpc.Client
|
|
|
|
}
|
|
|
|
|
|
|
|
func mockRPCClient(t *testing.T) *rpc.Client {
|
|
|
|
s := rpc.NewServer(nil, "mock")
|
|
|
|
c := rpc.NewClientWithServer(nil, "mock", s)
|
|
|
|
err := s.RegisterName("Cluster", &mockService{})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2019-02-27 17:04:35 +00:00
|
|
|
func (mock *mockService) IPFSPin(ctx context.Context, in *api.Pin, out *struct{}) error {
|
|
|
|
switch in.Cid.String() {
|
2019-02-27 20:19:10 +00:00
|
|
|
case test.SlowCid1.String():
|
2018-04-18 04:53:41 +00:00
|
|
|
time.Sleep(2 * time.Second)
|
2019-02-27 20:09:31 +00:00
|
|
|
case pinCancelCid.String():
|
2018-05-04 11:18:30 +00:00
|
|
|
return ErrPinCancelCid
|
2018-04-18 04:53:41 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-02-27 20:09:31 +00:00
|
|
|
func (mock *mockService) IPFSUnpin(ctx context.Context, in *api.Pin, out *struct{}) error {
|
|
|
|
switch in.Cid.String() {
|
2019-02-27 20:19:10 +00:00
|
|
|
case test.SlowCid1.String():
|
2018-04-18 04:53:41 +00:00
|
|
|
time.Sleep(2 * time.Second)
|
2019-02-27 20:09:31 +00:00
|
|
|
case unpinCancelCid.String():
|
2018-05-04 11:18:30 +00:00
|
|
|
return ErrUnpinCancelCid
|
2018-04-18 04:53:41 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-02-27 17:04:35 +00:00
|
|
|
func testPin(c cid.Cid, min, max int, allocs ...peer.ID) *api.Pin {
|
2018-07-23 09:14:43 +00:00
|
|
|
pin := api.PinCid(c)
|
|
|
|
pin.ReplicationFactorMin = min
|
|
|
|
pin.ReplicationFactorMax = max
|
|
|
|
pin.Allocations = allocs
|
|
|
|
return pin
|
|
|
|
}
|
|
|
|
|
2018-04-18 04:53:41 +00:00
|
|
|
func testSlowMapPinTracker(t *testing.T) *MapPinTracker {
|
|
|
|
cfg := &Config{}
|
|
|
|
cfg.Default()
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
cfg.ConcurrentPins = 1
|
2019-02-27 20:19:10 +00:00
|
|
|
mpt := NewMapPinTracker(cfg, test.PeerID1, test.PeerName1)
|
2018-04-18 04:53:41 +00:00
|
|
|
mpt.SetClient(mockRPCClient(t))
|
|
|
|
return mpt
|
|
|
|
}
|
|
|
|
|
2017-03-14 15:10:45 +00:00
|
|
|
func testMapPinTracker(t *testing.T) *MapPinTracker {
|
2017-11-29 13:32:26 +00:00
|
|
|
cfg := &Config{}
|
|
|
|
cfg.Default()
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
cfg.ConcurrentPins = 1
|
2019-02-27 20:19:10 +00:00
|
|
|
mpt := NewMapPinTracker(cfg, test.PeerID1, test.PeerName1)
|
2017-03-14 15:10:45 +00:00
|
|
|
mpt.SetClient(test.NewMockRPCClient(t))
|
|
|
|
return mpt
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNew(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2017-03-14 15:10:45 +00:00
|
|
|
mpt := testMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2017-03-14 15:10:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestShutdown(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2017-03-14 15:10:45 +00:00
|
|
|
mpt := testMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
err := mpt.Shutdown(ctx)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Shutdown(ctx)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrack(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2017-03-14 15:10:45 +00:00
|
|
|
mpt := testMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
h := test.Cid1
|
2017-03-14 15:10:45 +00:00
|
|
|
|
|
|
|
// Let's tart with a local pin
|
2018-07-23 09:14:43 +00:00
|
|
|
c := testPin(h, -1, -1)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err := mpt.Track(context.Background(), c)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-04-18 04:53:41 +00:00
|
|
|
time.Sleep(200 * time.Millisecond) // let it be pinned
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
st := mpt.Status(context.Background(), h)
|
2017-03-14 15:10:45 +00:00
|
|
|
if st.Status != api.TrackerStatusPinned {
|
|
|
|
t.Fatalf("cid should be pinned and is %s", st.Status)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unpin and set remote
|
2019-02-27 20:19:10 +00:00
|
|
|
c = testPin(h, 1, 1, test.PeerID2)
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Track(context.Background(), c)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-04-18 04:53:41 +00:00
|
|
|
time.Sleep(200 * time.Millisecond) // let it be unpinned
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
st = mpt.Status(context.Background(), h)
|
2017-03-14 15:10:45 +00:00
|
|
|
if st.Status != api.TrackerStatusRemote {
|
|
|
|
t.Fatalf("cid should be pinned and is %s", st.Status)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUntrack(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2017-03-14 15:10:45 +00:00
|
|
|
mpt := testMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
h1 := test.Cid1
|
|
|
|
h2 := test.Cid2
|
2017-03-14 15:10:45 +00:00
|
|
|
|
|
|
|
// LocalPin
|
2018-07-23 09:14:43 +00:00
|
|
|
c := testPin(h1, -1, -1)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err := mpt.Track(context.Background(), c)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remote pin
|
2019-02-27 20:19:10 +00:00
|
|
|
c = testPin(h2, 1, 1, test.PeerID2)
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Track(context.Background(), c)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-03-21 12:27:04 +00:00
|
|
|
time.Sleep(time.Second / 2)
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Untrack(context.Background(), h2)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Untrack(context.Background(), h1)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Untrack(context.Background(), h1)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-03-21 12:27:04 +00:00
|
|
|
time.Sleep(time.Second / 2)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
st := mpt.Status(context.Background(), h1)
|
2017-03-14 15:10:45 +00:00
|
|
|
if st.Status != api.TrackerStatusUnpinned {
|
|
|
|
t.Fatalf("cid should be unpinned and is %s", st.Status)
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
st = mpt.Status(context.Background(), h2)
|
2017-03-14 15:10:45 +00:00
|
|
|
if st.Status != api.TrackerStatusUnpinned {
|
|
|
|
t.Fatalf("cid should be unpinned and is %s", st.Status)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestStatusAll(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2017-03-14 15:10:45 +00:00
|
|
|
mpt := testMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
h1 := test.Cid1
|
|
|
|
h2 := test.Cid2
|
2017-03-14 15:10:45 +00:00
|
|
|
|
|
|
|
// LocalPin
|
2018-07-23 09:14:43 +00:00
|
|
|
c := testPin(h1, -1, -1)
|
2018-06-27 04:03:15 +00:00
|
|
|
mpt.Track(context.Background(), c)
|
2018-07-23 09:14:43 +00:00
|
|
|
c = testPin(h2, 1, 1)
|
2018-06-27 04:03:15 +00:00
|
|
|
mpt.Track(context.Background(), c)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2018-04-18 04:53:41 +00:00
|
|
|
time.Sleep(200 * time.Millisecond)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
stAll := mpt.StatusAll(context.Background())
|
2017-03-14 15:10:45 +00:00
|
|
|
if len(stAll) != 2 {
|
|
|
|
t.Logf("%+v", stAll)
|
|
|
|
t.Fatal("expected 2 pins")
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, st := range stAll {
|
|
|
|
if st.Cid.Equals(h1) && st.Status != api.TrackerStatusPinned {
|
|
|
|
t.Fatal("expected pinned")
|
|
|
|
}
|
|
|
|
if st.Cid.Equals(h2) && st.Status != api.TrackerStatusRemote {
|
|
|
|
t.Fatal("expected remote")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSyncAndRecover(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2017-03-14 15:10:45 +00:00
|
|
|
mpt := testMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
h1 := test.Cid1
|
|
|
|
h2 := test.Cid2
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2018-07-23 09:14:43 +00:00
|
|
|
c := testPin(h1, -1, -1)
|
2018-06-27 04:03:15 +00:00
|
|
|
mpt.Track(context.Background(), c)
|
2018-07-23 09:14:43 +00:00
|
|
|
c = testPin(h2, -1, -1)
|
2018-06-27 04:03:15 +00:00
|
|
|
mpt.Track(context.Background(), c)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
// IPFSPinLS RPC returns unpinned for anything != Cid1 or Cid3
|
2018-06-27 04:03:15 +00:00
|
|
|
info, err := mpt.Sync(context.Background(), h2)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if info.Status != api.TrackerStatusPinError {
|
|
|
|
t.Error("expected pin_error")
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
info, err = mpt.Sync(context.Background(), h1)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if info.Status != api.TrackerStatusPinned {
|
|
|
|
t.Error("expected pinned")
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
info, err = mpt.Recover(context.Background(), h1)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if info.Status != api.TrackerStatusPinned {
|
|
|
|
t.Error("expected pinned")
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
_, err = mpt.Recover(context.Background(), h2)
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
info = mpt.Status(context.Background(), h2)
|
2017-03-14 15:10:45 +00:00
|
|
|
if info.Status != api.TrackerStatusPinned {
|
|
|
|
t.Error("expected pinned")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-30 00:53:31 +00:00
|
|
|
func TestRecoverAll(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2017-11-30 00:53:31 +00:00
|
|
|
mpt := testMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2017-11-30 00:53:31 +00:00
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
h1 := test.Cid1
|
2017-11-30 00:53:31 +00:00
|
|
|
|
2018-07-23 09:14:43 +00:00
|
|
|
c := testPin(h1, -1, -1)
|
2018-06-27 04:03:15 +00:00
|
|
|
mpt.Track(context.Background(), c)
|
2017-11-30 00:53:31 +00:00
|
|
|
time.Sleep(100 * time.Millisecond)
|
2018-06-27 04:03:15 +00:00
|
|
|
mpt.optracker.SetError(context.Background(), h1, errors.New("fakeerror"))
|
|
|
|
pins, err := mpt.RecoverAll(context.Background())
|
2017-11-30 00:53:31 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if len(pins) != 1 {
|
|
|
|
t.Fatal("there should be only one pin")
|
|
|
|
}
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
2018-06-27 04:03:15 +00:00
|
|
|
info := mpt.Status(context.Background(), h1)
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
|
|
|
|
if info.Status != api.TrackerStatusPinned {
|
2017-11-30 00:53:31 +00:00
|
|
|
t.Error("the pin should have been recovered")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-14 15:10:45 +00:00
|
|
|
func TestSyncAll(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2017-03-14 15:10:45 +00:00
|
|
|
mpt := testMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
synced, err := mpt.SyncAll(context.Background())
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
// This relies on the rpc mock implementation
|
|
|
|
|
|
|
|
if len(synced) != 0 {
|
|
|
|
t.Fatal("should not have synced anything when it tracks nothing")
|
|
|
|
}
|
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
h1 := test.Cid1
|
|
|
|
h2 := test.Cid2
|
2017-03-14 15:10:45 +00:00
|
|
|
|
2018-07-23 09:14:43 +00:00
|
|
|
c := testPin(h1, -1, -1)
|
2018-06-27 04:03:15 +00:00
|
|
|
mpt.Track(context.Background(), c)
|
2018-07-23 09:14:43 +00:00
|
|
|
c = testPin(h2, -1, -1)
|
2018-06-27 04:03:15 +00:00
|
|
|
mpt.Track(context.Background(), c)
|
2017-03-14 15:10:45 +00:00
|
|
|
|
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
synced, err = mpt.SyncAll(context.Background())
|
2017-03-14 15:10:45 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if len(synced) != 1 || synced[0].Status != api.TrackerStatusPinError {
|
|
|
|
t.Logf("%+v", synced)
|
|
|
|
t.Fatal("should have synced h2")
|
|
|
|
}
|
|
|
|
}
|
2018-04-18 04:53:41 +00:00
|
|
|
|
|
|
|
func TestUntrackTrack(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2018-04-18 04:53:41 +00:00
|
|
|
mpt := testMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2018-04-18 04:53:41 +00:00
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
h1 := test.Cid1
|
2018-04-18 04:53:41 +00:00
|
|
|
|
|
|
|
// LocalPin
|
2018-07-23 09:14:43 +00:00
|
|
|
c := testPin(h1, -1, -1)
|
2018-06-27 04:03:15 +00:00
|
|
|
err := mpt.Track(context.Background(), c)
|
2018-04-18 04:53:41 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(time.Second / 2)
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Untrack(context.Background(), h1)
|
2018-04-18 04:53:41 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrackUntrackWithCancel(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2018-05-02 14:06:27 +00:00
|
|
|
mpt := testSlowMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2018-04-18 04:53:41 +00:00
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
slowPinCid := test.SlowCid1
|
2018-04-18 04:53:41 +00:00
|
|
|
|
|
|
|
// LocalPin
|
2018-07-23 09:14:43 +00:00
|
|
|
slowPin := testPin(slowPinCid, -1, -1)
|
2018-04-18 04:53:41 +00:00
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err := mpt.Track(context.Background(), slowPin)
|
2018-04-18 04:53:41 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-05-02 14:06:27 +00:00
|
|
|
time.Sleep(100 * time.Millisecond) // let pinning start
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
pInfo := mpt.Status(context.Background(), slowPin.Cid)
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
if pInfo.Status == api.TrackerStatusUnpinned {
|
2018-05-02 14:06:27 +00:00
|
|
|
t.Fatal("slowPin should be tracked")
|
2018-04-18 04:53:41 +00:00
|
|
|
}
|
|
|
|
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
if pInfo.Status == api.TrackerStatusPinning {
|
2018-05-04 11:18:30 +00:00
|
|
|
go func() {
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Untrack(context.Background(), slowPinCid)
|
2018-05-04 11:18:30 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
select {
|
2018-06-27 04:03:15 +00:00
|
|
|
case <-mpt.optracker.OpContext(context.Background(), slowPinCid).Done():
|
2018-05-04 11:18:30 +00:00
|
|
|
return
|
|
|
|
case <-time.Tick(100 * time.Millisecond):
|
|
|
|
t.Errorf("operation context should have been cancelled by now")
|
2018-05-02 14:06:27 +00:00
|
|
|
}
|
|
|
|
} else {
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
t.Error("slowPin should be pinning and is:", pInfo.Status)
|
2018-05-02 14:06:27 +00:00
|
|
|
}
|
2018-04-18 04:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrackUntrackWithNoCancel(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2018-04-18 04:53:41 +00:00
|
|
|
mpt := testSlowMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2018-04-18 04:53:41 +00:00
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
slowPinCid := test.SlowCid1
|
2019-02-27 20:09:31 +00:00
|
|
|
fastPinCid := pinCancelCid
|
2018-04-18 04:53:41 +00:00
|
|
|
|
|
|
|
// SlowLocalPin
|
2018-07-23 09:14:43 +00:00
|
|
|
slowPin := testPin(slowPinCid, -1, -1)
|
2018-04-18 04:53:41 +00:00
|
|
|
|
|
|
|
// LocalPin
|
2018-07-23 09:14:43 +00:00
|
|
|
fastPin := testPin(fastPinCid, -1, -1)
|
2018-04-18 04:53:41 +00:00
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err := mpt.Track(context.Background(), slowPin)
|
2018-04-18 04:53:41 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Track(context.Background(), fastPin)
|
2018-04-18 04:53:41 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-05-02 14:06:27 +00:00
|
|
|
// fastPin should be queued because slow pin is pinning
|
2018-06-27 04:03:15 +00:00
|
|
|
pInfo := mpt.Status(context.Background(), fastPinCid)
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
if pInfo.Status == api.TrackerStatusPinQueued {
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Untrack(context.Background(), fastPinCid)
|
2018-05-02 14:06:27 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-06-27 04:03:15 +00:00
|
|
|
pi := mpt.Status(context.Background(), fastPinCid)
|
2018-05-04 11:18:30 +00:00
|
|
|
if pi.Error == ErrPinCancelCid.Error() {
|
|
|
|
t.Fatal(ErrPinCancelCid)
|
|
|
|
}
|
2018-05-02 14:06:27 +00:00
|
|
|
} else {
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
t.Error("fastPin should be queued to pin:", pInfo.Status)
|
2018-05-02 14:06:27 +00:00
|
|
|
}
|
|
|
|
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
time.Sleep(100 * time.Millisecond)
|
2018-06-27 04:03:15 +00:00
|
|
|
pInfo = mpt.Status(context.Background(), fastPinCid)
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
if pInfo.Status != api.TrackerStatusUnpinned {
|
|
|
|
t.Error("fastPin should have been removed from tracker:", pInfo.Status)
|
2018-05-02 14:06:27 +00:00
|
|
|
}
|
2018-04-18 04:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestUntrackTrackWithCancel(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2018-05-02 14:06:27 +00:00
|
|
|
mpt := testSlowMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2018-04-18 04:53:41 +00:00
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
slowPinCid := test.SlowCid1
|
2018-04-18 04:53:41 +00:00
|
|
|
|
|
|
|
// LocalPin
|
2018-07-23 09:14:43 +00:00
|
|
|
slowPin := testPin(slowPinCid, -1, -1)
|
2018-04-18 04:53:41 +00:00
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err := mpt.Track(context.Background(), slowPin)
|
2018-04-18 04:53:41 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(time.Second / 2)
|
|
|
|
|
2018-05-02 14:06:27 +00:00
|
|
|
// Untrack should cancel the ongoing request
|
|
|
|
// and unpin right away
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Untrack(context.Background(), slowPinCid)
|
2018-04-18 04:53:41 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-05-02 14:06:27 +00:00
|
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
pInfo := mpt.Status(context.Background(), slowPinCid)
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
if pInfo.Status == api.TrackerStatusUnpinned {
|
2018-05-02 14:06:27 +00:00
|
|
|
t.Fatal("expected slowPin to be tracked")
|
|
|
|
}
|
|
|
|
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
if pInfo.Status == api.TrackerStatusUnpinning {
|
2018-05-04 11:18:30 +00:00
|
|
|
go func() {
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Track(context.Background(), slowPin)
|
2018-05-04 11:18:30 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
select {
|
2018-06-27 04:03:15 +00:00
|
|
|
case <-mpt.optracker.OpContext(context.Background(), slowPinCid).Done():
|
2018-05-04 11:18:30 +00:00
|
|
|
return
|
|
|
|
case <-time.Tick(100 * time.Millisecond):
|
|
|
|
t.Errorf("operation context should have been cancelled by now")
|
2018-04-18 04:53:41 +00:00
|
|
|
}
|
2018-05-02 14:06:27 +00:00
|
|
|
} else {
|
|
|
|
t.Error("slowPin should be in unpinning")
|
2018-04-18 04:53:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUntrackTrackWithNoCancel(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
2018-04-18 04:53:41 +00:00
|
|
|
mpt := testSlowMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
2018-04-18 04:53:41 +00:00
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
slowPinCid := test.SlowCid1
|
2019-02-27 20:09:31 +00:00
|
|
|
fastPinCid := unpinCancelCid
|
2018-04-18 04:53:41 +00:00
|
|
|
|
|
|
|
// SlowLocalPin
|
2018-07-23 09:14:43 +00:00
|
|
|
slowPin := testPin(slowPinCid, -1, -1)
|
2018-04-18 04:53:41 +00:00
|
|
|
|
|
|
|
// LocalPin
|
2018-07-23 09:14:43 +00:00
|
|
|
fastPin := testPin(fastPinCid, -1, -1)
|
2018-04-18 04:53:41 +00:00
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err := mpt.Track(context.Background(), slowPin)
|
2018-04-18 04:53:41 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Track(context.Background(), fastPin)
|
2018-04-18 04:53:41 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(3 * time.Second)
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Untrack(context.Background(), slowPin.Cid)
|
2018-04-18 04:53:41 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Untrack(context.Background(), fastPin.Cid)
|
2018-04-18 04:53:41 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
pInfo := mpt.Status(context.Background(), fastPinCid)
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
if pInfo.Status == api.TrackerStatusUnpinned {
|
2018-05-02 14:06:27 +00:00
|
|
|
t.Fatal("c untrack operation should be tracked")
|
|
|
|
}
|
|
|
|
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
if pInfo.Status == api.TrackerStatusUnpinQueued {
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Track(context.Background(), fastPin)
|
2018-05-02 14:06:27 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
2018-04-18 04:53:41 +00:00
|
|
|
}
|
|
|
|
|
2018-06-27 04:03:15 +00:00
|
|
|
pi := mpt.Status(context.Background(), fastPinCid)
|
2018-05-04 11:18:30 +00:00
|
|
|
if pi.Error == ErrUnpinCancelCid.Error() {
|
|
|
|
t.Fatal(ErrUnpinCancelCid)
|
|
|
|
}
|
2018-05-02 14:06:27 +00:00
|
|
|
} else {
|
|
|
|
t.Error("c should be queued to unpin")
|
|
|
|
}
|
2018-04-18 04:53:41 +00:00
|
|
|
}
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
|
|
|
|
func TestTrackUntrackConcurrent(t *testing.T) {
|
2018-06-27 04:03:15 +00:00
|
|
|
ctx := context.Background()
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
mpt := testMapPinTracker(t)
|
2018-06-27 04:03:15 +00:00
|
|
|
defer mpt.Shutdown(ctx)
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
|
2019-02-27 20:19:10 +00:00
|
|
|
h1 := test.Cid1
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
|
|
|
|
// LocalPin
|
2018-07-23 09:14:43 +00:00
|
|
|
c := testPin(h1, -1, -1)
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
|
|
|
|
for i := 0; i < 50; i++ {
|
|
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
for j := 0; j < 50; j++ {
|
|
|
|
var err error
|
|
|
|
op := rand.Intn(2)
|
|
|
|
if op == 1 {
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Track(context.Background(), c)
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
} else {
|
2018-06-27 04:03:15 +00:00
|
|
|
err = mpt.Untrack(context.Background(), c.Cid)
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
time.Sleep(200 * time.Millisecond)
|
2018-06-27 04:03:15 +00:00
|
|
|
st := mpt.Status(context.Background(), h1)
|
Fix: maptracker race issues
This commit attempts to fix race issues in the maptracker since the
introduction of the OperationTracker.
There were two main problems:
* Duplicity tracking the state both in the state map and the opTracker
* Non atomiciy of operations with different threads being able to affect
other threads operations.
A test performing random Track/Untracks on the same Cid quickly showed
that items would sometimes stay as pin_queued or pin_unqueued. That happened
because operations could be cancelled under the hood by a different request,
while leaving the map status untouched.
It was not simply to deal with this issues without a refactoring.
First, the state map has been removed, and the operation tracker now provides
status information for any Cid. This implies that the tracker keeps all
operations and operations have a `PhaseDone`. There's also a
new `OperationRemote` type.
Secondly, operations are only created in the tracker and can only be removed
by their creators (they can be overwritten by other operations though).
Operations cannot be accessed directly and modifications are limited to setting
Error for PhaseDone operations.
After created, *Operations are queued in the pinWorker queues which handle any
status updates. This means, that, even when an operation has been removed from
the tracker, status updates will not interfere with any other newer operations.
In the maptracker, only the Unpin worker Cleans operations once processed. A
sucessful unpin is the only way that a delete() happens in the tracker map.
Otherwise, operations stay there until a newer operation for the Cid arrives
and 1) cancels the existing one 2) takes its place. The tracker refuses to
create a new operation if a similar "ongoing" operation of the same type
exists.
The final change is that Recover and RecoverAll() are not async and play by the
same rules as Track() and Untrack(), queueing the items to be recovered.
Note: for stateless pintracker, the tracker will need to Clean() operation
of type OperationPin as well, and complement the Status reported
by the tracker with those coming from IPFS.
License: MIT
Signed-off-by: Hector Sanjuan <code@hector.link>
2018-05-25 16:32:10 +00:00
|
|
|
t.Log(st.Status)
|
|
|
|
if st.Status != api.TrackerStatusUnpinned && st.Status != api.TrackerStatusPinned {
|
|
|
|
t.Fatal("should be pinned or unpinned")
|
|
|
|
}
|
|
|
|
}
|