Skip to content

Commit 9c35f18

Browse files
committed
closer
1 parent a06156c commit 9c35f18

File tree

3 files changed

+191
-116
lines changed

3 files changed

+191
-116
lines changed

bitswap/server/internal/decision/engine.go

+113-84
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
package decision
33

44
import (
5+
"cmp"
56
"context"
7+
"errors"
68
"fmt"
9+
"slices"
710
"sync"
811
"time"
912

1013
"github.com/google/uuid"
11-
1214
wl "github.com/ipfs/boxo/bitswap/client/wantlist"
1315
"github.com/ipfs/boxo/bitswap/internal/defaults"
1416
bsmsg "github.com/ipfs/boxo/bitswap/message"
@@ -131,7 +133,7 @@ type PeerEntry struct {
131133
// PeerLedger is an external ledger dealing with peers and their want lists.
132134
type PeerLedger interface {
133135
// Wants informs the ledger that [peer.ID] wants [wl.Entry].
134-
Wants(p peer.ID, e wl.Entry)
136+
Wants(p peer.ID, e wl.Entry, limit int) bool
135137

136138
// CancelWant returns true if the [cid.Cid] was removed from the wantlist of [peer.ID].
137139
CancelWant(p peer.ID, k cid.Cid) bool
@@ -675,14 +677,12 @@ func (e *Engine) MessageReceived(ctx context.Context, p peer.ID, m bsmsg.BitSwap
675677
return false
676678
}
677679

678-
newWorkExists := false
679-
defer func() {
680-
if newWorkExists {
681-
e.signalNewWork()
682-
}
683-
}()
684-
685-
wants, cancels, denials := e.splitWantsCancelsDenials(p, m)
680+
wants, cancels, denials, err := e.splitWantsCancelsDenials(p, m)
681+
if err != nil {
682+
// This is a truely broken client, let's kill the connection.
683+
log.Warnw(err.Error(), "local", e.self, "remote", p)
684+
return true
685+
}
686686

687687
// Get block sizes
688688
wantKs := cid.NewSet()
@@ -701,90 +701,59 @@ func (e *Engine) MessageReceived(ctx context.Context, p peer.ID, m bsmsg.BitSwap
701701
e.peerLedger.ClearPeerWantlist(p)
702702
}
703703

704+
var overflow []bsmsg.Entry
704705
if len(wants) != 0 {
705706
filteredWants := wants[:0] // shift inplace
706707
for _, entry := range wants {
707-
if entry.Cid.Prefix().MhType == mh.IDENTITY {
708-
// This is a truely broken client, let's kill the connection.
709-
e.lock.Unlock()
710-
log.Warnw("peer wants an identity CID", "local", e.self, "remote", p)
711-
return true
712-
}
713-
if e.maxCidSize != 0 && uint(entry.Cid.ByteLen()) > e.maxCidSize {
714-
// Ignore requests about CIDs that big.
708+
if !e.peerLedger.Wants(p, entry.Entry, int(e.maxQueuedWantlistEntriesPerPeer)) {
709+
// Cannot add entry because it would exceed size limit.
710+
overflow = append(overflow, entry)
715711
continue
716712
}
717713
filteredWants = append(filteredWants, entry)
718-
if len(filteredWants) == int(e.maxQueuedWantlistEntriesPerPeer) {
719-
// filteredWants at limit, ignore remaining wants from request.
720-
log.Debugw("requested wants exceeds max wantlist size", "local", e.self, "remote", p, "ignoring", len(wants)-len(filteredWants))
721-
break
722-
}
723-
}
724-
wants = wants[len(filteredWants):]
725-
for i := range wants {
726-
wants[i] = bsmsg.Entry{} // early GC
727714
}
715+
// Clear truncated entries - early GC.
716+
clear(wants[len(filteredWants):])
728717
wants = filteredWants
718+
}
729719

730-
// Ensure sufficient space for new wants.
731-
s := e.peerLedger.WantlistSizeForPeer(p)
732-
available := int(e.maxQueuedWantlistEntriesPerPeer) - s
733-
if len(wants) > available {
734-
needSpace := len(wants) - available
735-
log.Debugw("wantlist overflow", "local", e.self, "remote", p, "would be", s+len(wants), "canceling", needSpace)
736-
// Cancel any wants that are being requested again. This makes room
737-
// for new wants and minimizes that existing wants to cancel that
738-
// are not in the new request.
739-
for _, entry := range wants {
740-
if e.peerLedger.CancelWant(p, entry.Cid) {
741-
e.peerRequestQueue.Remove(entry.Cid, p)
742-
needSpace--
743-
if needSpace == 0 {
744-
break
745-
}
746-
}
720+
if len(overflow) != 0 {
721+
// Sort wl and overflow from least to most important.
722+
peerWants := e.peerLedger.WantlistForPeer(p)
723+
slices.SortFunc(peerWants, func(a, b wl.Entry) int {
724+
return cmp.Compare(a.Priority, b.Priority)
725+
})
726+
slices.SortFunc(overflow, func(a, b bsmsg.Entry) int {
727+
return cmp.Compare(a.Entry.Priority, b.Entry.Priority)
728+
})
729+
730+
// Put overflow wants onto the request queue by replacing entries that
731+
// have the same or lower priority.
732+
var replace int
733+
for _, entry := range overflow {
734+
if entry.Entry.Priority <= peerWants[replace].Priority {
735+
// Everything in peerWants is equal or more improtant, so this
736+
// overflow entry cannot replace any existing wants.
737+
continue
747738
}
748-
// Cancel additional wants, that are not being replaced, to make
749-
// room for new wants.
750-
if needSpace != 0 {
751-
wl := e.peerLedger.WantlistForPeer(p)
752-
for i := range wl {
753-
entCid := wl[i].Cid
754-
if e.peerLedger.CancelWant(p, entCid) {
755-
e.peerRequestQueue.Remove(entCid, p)
756-
needSpace--
757-
if needSpace == 0 {
758-
break
759-
}
760-
}
761-
}
739+
entCid := peerWants[replace].Cid
740+
replace++
741+
if e.peerLedger.CancelWant(p, entCid) {
742+
e.peerRequestQueue.Remove(entCid, p)
762743
}
763-
}
764-
765-
for _, entry := range wants {
766-
e.peerLedger.Wants(p, entry.Entry)
744+
e.peerLedger.Wants(p, entry.Entry, int(e.maxQueuedWantlistEntriesPerPeer))
745+
wants = append(wants, entry)
767746
}
768747
}
769748

770749
for _, entry := range cancels {
771750
c := entry.Cid
772-
if c.Prefix().MhType == mh.IDENTITY {
773-
// This is a truely broken client, let's kill the connection.
774-
e.lock.Unlock()
775-
log.Warnw("peer canceled an identity CID", "local", e.self, "remote", p)
776-
return true
777-
}
778-
if e.maxCidSize != 0 && uint(c.ByteLen()) > e.maxCidSize {
779-
// Ignore requests about CIDs that big.
780-
continue
781-
}
782-
783751
log.Debugw("Bitswap engine <- cancel", "local", e.self, "from", p, "cid", c)
784752
if e.peerLedger.CancelWant(p, c) {
785753
e.peerRequestQueue.Remove(c, p)
786754
}
787755
}
756+
788757
e.lock.Unlock()
789758

790759
var activeEntries []peertask.Task
@@ -795,7 +764,6 @@ func (e *Engine) MessageReceived(ctx context.Context, p peer.ID, m bsmsg.BitSwap
795764
if e.sendDontHaves && entry.SendDontHave {
796765
c := entry.Cid
797766

798-
newWorkExists = true
799767
isWantBlock := false
800768
if entry.WantType == pb.Message_Wantlist_Block {
801769
isWantBlock = true
@@ -833,8 +801,6 @@ func (e *Engine) MessageReceived(ctx context.Context, p peer.ID, m bsmsg.BitSwap
833801
continue
834802
}
835803
// The block was found, add it to the queue
836-
newWorkExists = true
837-
838804
isWantBlock := e.sendAsBlock(entry.WantType, blockSize)
839805

840806
log.Debugw("Bitswap engine: block found", "local", e.self, "from", p, "cid", c, "isWantBlock", isWantBlock)
@@ -860,19 +826,64 @@ func (e *Engine) MessageReceived(ctx context.Context, p peer.ID, m bsmsg.BitSwap
860826
})
861827
}
862828

863-
// Push entries onto the request queue
864-
if len(activeEntries) > 0 {
829+
// Push entries onto the request queue and signal network that new work is ready.
830+
if len(activeEntries) != 0 {
865831
e.peerRequestQueue.PushTasksTruncated(e.maxQueuedWantlistEntriesPerPeer, p, activeEntries...)
866832
e.updateMetrics()
833+
e.signalNewWork()
867834
}
868835
return false
869836
}
870837

838+
/*
839+
840+
// Ensure sufficient space for new wants.
841+
s := e.peerLedger.WantlistSizeForPeer(p)
842+
available := int(e.maxQueuedWantlistEntriesPerPeer) - s
843+
if len(wants) > available {
844+
needSpace := len(wants) - available
845+
log.Debugw("wantlist overflow", "local", e.self, "remote", p, "would be", s+len(wants), "canceling", needSpace)
846+
// Cancel any wants that are being requested again. This makes room
847+
// for new wants and minimizes that existing wants to cancel that
848+
// are not in the new request.
849+
for _, entry := range wants {
850+
if e.peerLedger.CancelWant(p, entry.Cid) {
851+
e.peerRequestQueue.Remove(entry.Cid, p)
852+
needSpace--
853+
if needSpace == 0 {
854+
break
855+
}
856+
}
857+
}
858+
// Cancel additional wants, that are not being replaced, to make
859+
// room for new wants.
860+
if needSpace != 0 {
861+
wl := e.peerLedger.WantlistForPeer(p)
862+
for i := range wl {
863+
entCid := wl[i].Cid
864+
if e.peerLedger.CancelWant(p, entCid) {
865+
e.peerRequestQueue.Remove(entCid, p)
866+
needSpace--
867+
if needSpace == 0 {
868+
break
869+
}
870+
}
871+
}
872+
}
873+
}
874+
875+
for _, entry := range wants {
876+
e.peerLedger.Wants(p, entry.Entry)
877+
}
878+
}
879+
880+
*/
881+
871882
// Split the want-havek entries from the cancel and deny entries.
872-
func (e *Engine) splitWantsCancelsDenials(p peer.ID, m bsmsg.BitSwapMessage) ([]bsmsg.Entry, []bsmsg.Entry, []bsmsg.Entry) {
883+
func (e *Engine) splitWantsCancelsDenials(p peer.ID, m bsmsg.BitSwapMessage) ([]bsmsg.Entry, []bsmsg.Entry, []bsmsg.Entry, error) {
873884
entries := m.Wantlist() // creates copy; safe to modify
874885
if len(entries) == 0 {
875-
return nil, nil, nil
886+
return nil, nil, nil, nil
876887
}
877888

878889
log.Debugw("Bitswap engine <- msg", "local", e.self, "from", p, "entryCount", len(entries))
@@ -881,18 +892,27 @@ func (e *Engine) splitWantsCancelsDenials(p peer.ID, m bsmsg.BitSwapMessage) ([]
881892
var cancels, denials []bsmsg.Entry
882893

883894
for _, et := range entries {
895+
c := et.Cid
896+
if e.maxCidSize != 0 && uint(c.ByteLen()) > e.maxCidSize {
897+
// Ignore requests about CIDs that big.
898+
continue
899+
}
900+
if c.Prefix().MhType == mh.IDENTITY {
901+
return nil, nil, nil, errors.New("peer canceled an identity CID")
902+
}
903+
884904
if et.Cancel {
885905
cancels = append(cancels, et)
886906
continue
887907
}
888908

889909
if et.WantType == pb.Message_Wantlist_Have {
890-
log.Debugw("Bitswap engine <- want-have", "local", e.self, "from", p, "cid", et.Cid)
910+
log.Debugw("Bitswap engine <- want-have", "local", e.self, "from", p, "cid", c)
891911
} else {
892-
log.Debugw("Bitswap engine <- want-block", "local", e.self, "from", p, "cid", et.Cid)
912+
log.Debugw("Bitswap engine <- want-block", "local", e.self, "from", p, "cid", c)
893913
}
894914

895-
if e.peerBlockRequestFilter != nil && !e.peerBlockRequestFilter(p, et.Cid) {
915+
if e.peerBlockRequestFilter != nil && !e.peerBlockRequestFilter(p, c) {
896916
denials = append(denials, et)
897917
continue
898918
}
@@ -904,10 +924,19 @@ func (e *Engine) splitWantsCancelsDenials(p peer.ID, m bsmsg.BitSwapMessage) ([]
904924
wants = nil
905925
}
906926

927+
// Do not take more wants that can be handled.
928+
if len(wants) > int(e.maxQueuedWantlistEntriesPerPeer) {
929+
// Keep the highest priority wants.
930+
slices.SortFunc(wants, func(a, b bsmsg.Entry) int {
931+
return cmp.Compare(b.Entry.Priority, a.Entry.Priority)
932+
})
933+
wants = wants[:int(e.maxQueuedWantlistEntriesPerPeer)]
934+
}
935+
907936
// Clear truncated entries.
908937
clear(entries[len(wants):])
909938

910-
return wants, cancels, denials
939+
return wants, cancels, denials, nil
911940
}
912941

913942
// ReceivedBlocks is called when new blocks are received from the network.

0 commit comments

Comments
 (0)