@@ -2,6 +2,7 @@ package storagemarket
2
2
3
3
import (
4
4
"context"
5
+ "errors"
5
6
"fmt"
6
7
"io"
7
8
"os"
@@ -28,49 +29,44 @@ import (
28
29
"github.com/libp2p/go-libp2p-core/event"
29
30
)
30
31
31
- func (p * Provider ) doDeal (deal * types.ProviderDealState ) {
32
+ func (p * Provider ) doDeal (deal * types.ProviderDealState , dh * dealHandler ) {
32
33
// Set up pubsub for deal updates
33
- bus := eventbus .NewBus ()
34
- pub , err := bus .Emitter (& types.ProviderDealState {}, eventbus .Stateful )
34
+ pub , err := dh .bus .Emitter (& types.ProviderDealState {}, eventbus .Stateful )
35
35
if err != nil {
36
- err := fmt .Errorf ("failed to create event emitter: %w" , err )
36
+ err = fmt .Errorf ("failed to create event emitter: %w" , err )
37
+ p .cleanupDeal (deal )
37
38
p .failDeal (pub , deal , err )
38
39
return
39
40
}
40
41
41
- // Create a context that can be cancelled for this deal if the user wants
42
- // to cancel the deal early
43
- ctx , stop := context .WithCancel (p .ctx )
44
- defer stop ()
45
-
46
- stopped := make (chan struct {})
47
- defer close (stopped )
48
-
49
- // Keep track of the fields to subscribe to or cancel the deal
50
- p .dealHandlers .track (& dealHandler {
51
- dealUuid : deal .DealUuid ,
52
- ctx : ctx ,
53
- stop : stop ,
54
- stopped : stopped ,
55
- bus : bus ,
56
- })
57
-
58
42
// build in-memory state
59
43
fi , err := os .Stat (deal .InboundFilePath )
60
44
if err != nil {
61
45
err := fmt .Errorf ("failed to stat output file: %w" , err )
46
+ p .cleanupDeal (deal )
62
47
p .failDeal (pub , deal , err )
63
48
return
64
49
}
65
50
deal .NBytesReceived = fi .Size ()
66
51
67
52
// Execute the deal synchronously
68
- if err := p .execDeal (ctx , pub , deal ); err != nil {
53
+ if err := p .execDealUptoAddPiece (dh .providerCtx , pub , deal , dh ); err != nil {
54
+ p .cleanupDeal (deal )
69
55
p .failDeal (pub , deal , err )
56
+ return
70
57
}
58
+
59
+ // deal has been sent for sealing -> we can cleanup the deal state now and simply watch the deal on chain
60
+ // to wait for deal completion/slashing and update the state in DB accordingly.
61
+ p .cleanupDeal (deal )
62
+
63
+ // TODO
64
+ // Watch deal on chain and change state in DB and emit notifications.
65
+ // Given that cleanup deal above also gets rid of the deal handler, subscriptions to deal updates from here on
66
+ // will fail, we can look into it when we implement deal completion.
71
67
}
72
68
73
- func (p * Provider ) execDeal (ctx context.Context , pub event.Emitter , deal * types.ProviderDealState ) error {
69
+ func (p * Provider ) execDealUptoAddPiece (ctx context.Context , pub event.Emitter , deal * types.ProviderDealState , dh * dealHandler ) error {
74
70
// publish "new deal" event
75
71
p .fireEventDealNew (deal )
76
72
@@ -81,10 +77,13 @@ func (p *Provider) execDeal(ctx context.Context, pub event.Emitter, deal *types.
81
77
82
78
// Transfer Data
83
79
if deal .Checkpoint < dealcheckpoints .Transferred {
84
- if err := p .transferAndVerify (ctx , pub , deal ); err != nil {
80
+ if err := p .transferAndVerify (dh .transferCtx , pub , deal ); err != nil {
81
+ dh .transferCancelled (nil )
85
82
return fmt .Errorf ("failed data transfer: %w" , err )
86
83
}
87
84
}
85
+ // transfer can no longer be cancelled
86
+ dh .transferCancelled (errors .New ("transfer already complete" ))
88
87
89
88
// Publish
90
89
if deal .Checkpoint <= dealcheckpoints .Published {
@@ -100,10 +99,6 @@ func (p *Provider) execDeal(ctx context.Context, pub event.Emitter, deal *types.
100
99
}
101
100
}
102
101
103
- // Watch deal on chain and change state in DB and emit notifications.
104
-
105
- // TODO: Clean up deal when it completes
106
- //d.cleanupDeal()
107
102
return nil
108
103
}
109
104
@@ -319,19 +314,11 @@ func (p *Provider) addPiece(ctx context.Context, pub event.Emitter, deal *types.
319
314
320
315
p .addDealLog (deal .DealUuid , "Deal handed off to sealer successfully" )
321
316
322
- // Now that the deal has been handed off to sealer, we should untag storage from the staging area.
323
- err = p .storageManager .Untag (ctx , deal .DealUuid )
324
- if err != nil {
325
- log .Errorw ("untagging storage" , "uuid" , deal .DealUuid , "err" , err )
326
- return err
327
- }
328
-
329
317
return p .updateCheckpoint (ctx , pub , deal , dealcheckpoints .AddedPiece )
330
318
}
331
319
332
320
func (p * Provider ) failDeal (pub event.Emitter , deal * types.ProviderDealState , err error ) {
333
- p .cleanupDeal (p .ctx , deal )
334
-
321
+ log .Errorw ("deal failed" , "id" , deal .DealUuid , "err" , err )
335
322
// Update state in DB with error
336
323
deal .Checkpoint = dealcheckpoints .Complete
337
324
if xerrors .Is (err , context .Canceled ) {
@@ -350,29 +337,34 @@ func (p *Provider) failDeal(pub event.Emitter, deal *types.ProviderDealState, er
350
337
if pub != nil {
351
338
p .fireEventDealUpdate (pub , deal )
352
339
}
353
-
354
- select {
355
- case p .failedDealsChan <- failedDealReq {deal , err }:
356
- case <- p .ctx .Done ():
357
- }
358
340
}
359
341
360
- func (p * Provider ) cleanupDeal (ctx context.Context , deal * types.ProviderDealState ) {
342
+ func (p * Provider ) cleanupDeal (deal * types.ProviderDealState ) {
343
+ // remove the temp file created for inbound deal data
361
344
_ = os .Remove (deal .InboundFilePath )
362
345
363
- // clean up tagged funds
364
- err := p .fundManager .UntagFunds (ctx , deal .DealUuid )
365
- if err != nil {
366
- log .Errorw ("untagging funds" , "id" , deal .DealUuid , "err" , err )
346
+ // close and clean up the deal handler
347
+ dh := p .getDealHandler (deal .DealUuid )
348
+ if dh != nil {
349
+ dh .transferCancelled (errors .New ("deal cleaned up" ))
350
+ dh .close ()
351
+ p .delDealHandler (deal .DealUuid )
367
352
}
368
353
369
- // clean up storage tag
370
- err = p .storageManager .Untag (ctx , deal .DealUuid )
371
- if err != nil {
372
- log .Errorw ("untagging storage" , "id" , deal .DealUuid , "err" , err )
354
+ done := make (chan struct {}, 1 )
355
+ // submit req to event loop to untag tagged funds and storage space
356
+ select {
357
+ case p .finishedDealsChan <- finishedDealsReq {deal : deal , done : done }:
358
+ case <- p .ctx .Done ():
373
359
}
374
360
375
- p .dealHandlers .del (deal .DealUuid )
361
+ // wait for event loop to finish cleanup and return before we return from here
362
+ // so caller is guaranteed that all resources associated with the deal have been cleanedup before
363
+ // taking further action.
364
+ select {
365
+ case <- done :
366
+ case <- p .ctx .Done ():
367
+ }
376
368
}
377
369
378
370
func (p * Provider ) fireEventDealNew (deal * types.ProviderDealState ) {
0 commit comments