From e0b01c802e39c06004f67a3fcd010c5280828138 Mon Sep 17 00:00:00 2001 From: Dustin Long Date: Tue, 17 Mar 2020 13:15:52 -0400 Subject: [PATCH] fix(dsync): Don't call the finalize hook more than once --- dsync/dsync.go | 4 ++-- dsync/session.go | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/dsync/dsync.go b/dsync/dsync.go index 88d8286..b9a7c4e 100644 --- a/dsync/dsync.go +++ b/dsync/dsync.go @@ -393,8 +393,8 @@ func (ds *Dsync) ReceiveBlock(sid, hash string, data []byte) ReceiveResponse { res := sess.ReceiveBlock(hash, bytes.NewReader(data)) log.Debugf("received block: %s", res.Hash) - // if we're done transferring, finalize! - if res.Status == StatusOk && sess.Complete() { + // check if transfer has completed, if so finalize it, but only once + if res.Status == StatusOk && sess.IsFinalizedOnce() { if err := ds.finalizeReceive(sess); err != nil { return ReceiveResponse{ Hash: sess.info.RootCID().String(), diff --git a/dsync/session.go b/dsync/session.go index 583479c..65559fc 100644 --- a/dsync/session.go +++ b/dsync/session.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "math/rand" + "sync" ipld "github.com/ipfs/go-ipld-format" coreiface "github.com/ipfs/interface-go-ipfs-core" @@ -23,6 +24,8 @@ type session struct { diff *dag.Manifest prog dag.Completion progCh chan dag.Completion + lock sync.Mutex + fin bool } // newSession creates a receive state machine @@ -99,6 +102,22 @@ func (s *session) completionChanged() { s.progCh <- s.prog } +// IsFinalizedOnce will return true if the session is complete, but only the first time it is +// called, even if multiple threads call this function at the same time +func (s *session) IsFinalizedOnce() bool { + if !s.Complete() { + return false + } + ret := false + s.lock.Lock() + if !s.fin { + ret = true + s.fin = true + } + defer s.lock.Unlock() + return ret +} + // the best stack overflow answer evaarrr: https://stackoverflow.com/a/22892986/9416066 const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" const (