Skip to content

Commit 8949ff5

Browse files
committed
transfer: clean up contract creation to create fewer contracts in parallel
1 parent ae44895 commit 8949ff5

3 files changed

Lines changed: 74 additions & 56 deletions

File tree

transfer.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ func DefaultClientSettingsNoNetworkEvents() *ClientSettings {
9696
func DefaultSendBufferSettings() *SendBufferSettings {
9797
return &SendBufferSettings{
9898
CreateContractTimeout: 30 * time.Second,
99-
CreateContractRetryInterval: 5 * time.Second,
99+
CreateContractRetryInterval: 15 * time.Second,
100100
MinResendInterval: 1 * time.Second,
101101
MaxResendInterval: 5 * time.Second,
102102
// no backoff
@@ -1442,6 +1442,14 @@ func (self *SendSequence) Run() {
14421442
sendContract.ackedByteCount,
14431443
sendContract.unackedByteCount,
14441444
)
1445+
// flush queued contracts for already sent contracts
1446+
// contractKey = ContractKey{
1447+
// Destination: sendContract.path.DestinationMask(),
1448+
// IntermediaryIds: self.intermediaryIds,
1449+
// CompanionContract: self.companionContract,
1450+
// ForceStream: self.forceStream,
1451+
// }
1452+
// self.client.ContractManager().FlushContractQueue(contractKey, true)
14451453
}
14461454

14471455
// drain the buffer
@@ -1682,8 +1690,7 @@ func (self *SendSequence) Run() {
16821690
func (self *SendSequence) updateContract(messageByteCount ByteCount) bool {
16831691
// `sendNoContract` is a mutual configuration
16841692
// both sides must configure themselves to require no contract from each other
1685-
isStream := self.destination.IsStream() || 0 < self.intermediaryIds.Len()
1686-
if !isStream && self.client.ContractManager().SendNoContract(self.destination.DestinationId) {
1693+
if self.client.ContractManager().SendNoContract(self.destination.DestinationId) {
16871694
return true
16881695
}
16891696
if self.sendContract != nil && self.sendContract.update(messageByteCount) {
@@ -1774,11 +1781,15 @@ func (self *SendSequence) updateContract(messageByteCount ByteCount) bool {
17741781
}
17751782
}
17761783

1777-
if traceNextContract(0) {
1778-
return true
1784+
endTime := time.Now().Add(self.sendBufferSettings.CreateContractTimeout)
1785+
1786+
if self.sendContract != nil {
1787+
// there should be a queued up contract
1788+
if traceNextContract(min(self.sendBufferSettings.CreateContractTimeout, self.sendBufferSettings.CreateContractRetryInterval)) {
1789+
return true
1790+
}
17791791
}
17801792

1781-
endTime := time.Now().Add(self.sendBufferSettings.CreateContractTimeout)
17821793
for {
17831794
select {
17841795
case <-self.ctx.Done():
@@ -3193,7 +3204,7 @@ func (self *ReceiveSequence) updateContract(item *receiveItem) bool {
31933204
}
31943205
// `receiveNoContract` is a mutual configuration
31953206
// both sides must configure themselves to require no contract from each other
3196-
if !self.source.IsStream() && self.client.ContractManager().ReceiveNoContract(self.source.SourceId) {
3207+
if self.client.ContractManager().ReceiveNoContract(self.source.SourceId) {
31973208
return true
31983209
}
31993210
return false

transfer_contract_manager.go

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -321,15 +321,15 @@ func (self *ContractManager) contractStatus(contractStatus *ContractStatus) {
321321
func (self *ContractManager) Receive(source TransferPath, frames []*protocol.Frame, provideMode protocol.ProvideMode) {
322322
if source.IsControlSource() {
323323
for _, frame := range frames {
324-
self.handleControlFrame(frame)
324+
self.handleControlFrame(nil, frame)
325325
}
326326
}
327327
}
328328

329-
func (self *ContractManager) handleControlFrame(frame *protocol.Frame) error {
329+
func (self *ContractManager) handleControlFrame(createContractKey *ContractKey, frame *protocol.Frame) error {
330330
switch frame.MessageType {
331331
case protocol.MessageType_TransferCreateContractResult:
332-
contracts, contractErrors := self.parseControlFrame(frame)
332+
contracts, contractErrors := self.parseControlFrame(createContractKey, frame)
333333
for contractKey, contract := range contracts {
334334
c := func() error {
335335
err := self.addContract(contractKey, contract)
@@ -400,68 +400,71 @@ func (self *ContractManager) handleControlFrame(frame *protocol.Frame) error {
400400
}
401401

402402
// frames are verified before calling to be from source ControlId
403-
func (self *ContractManager) parseControlFrame(frame *protocol.Frame) (
403+
func (self *ContractManager) parseControlFrame(createContractKey *ContractKey, frame *protocol.Frame) (
404404
contracts map[ContractKey]*protocol.Contract,
405405
contractErrors map[ContractKey]protocol.ContractError,
406406
) {
407407
contracts = map[ContractKey]*protocol.Contract{}
408408
contractErrors = map[ContractKey]protocol.ContractError{}
409409

410410
addResult := func(v *protocol.CreateContractResult) {
411-
contractKey := ContractKey{}
412-
if v.CreateContract != nil {
413-
contractKey.CompanionContract = v.CreateContract.Companion
414-
if v.CreateContract.ForceStream != nil {
415-
contractKey.ForceStream = *v.CreateContract.ForceStream
411+
var contractKey *ContractKey
412+
if createContractKey != nil {
413+
contractKey = createContractKey
414+
} else if createContract := v.CreateContract; createContract != nil {
415+
contractKey = &ContractKey{}
416+
var err error
417+
contractKey.Destination, err = TransferPathFromBytes(
418+
nil,
419+
createContract.DestinationId,
420+
nil,
421+
)
422+
if err != nil {
423+
return
416424
}
417-
if v.CreateContract.IntermediaryIds != nil {
418-
if intermediaryIds, err := MultiHopIdFromBytes(v.CreateContract.IntermediaryIds); err == nil {
425+
contractKey.CompanionContract = createContract.Companion
426+
if createContract.ForceStream != nil {
427+
contractKey.ForceStream = *createContract.ForceStream
428+
}
429+
if createContract.IntermediaryIds != nil {
430+
if intermediaryIds, err := MultiHopIdFromBytes(createContract.IntermediaryIds); err == nil {
419431
contractKey.IntermediaryIds = intermediaryIds
420432
}
421433
}
422434
}
423435

424436
if contractError := v.Error; contractError != nil {
425-
if v.CreateContract != nil {
426-
var err error
427-
contractKey.Destination, err = TransferPathFromBytes(
428-
nil,
429-
v.CreateContract.DestinationId,
430-
v.CreateContract.StreamId,
431-
)
432-
if err != nil {
433-
return
434-
}
437+
if contractKey != nil {
438+
contractErrors[*contractKey] = *contractError
439+
} else {
440+
glog.Infof("[contract]error with unassociated contract = %s\n", contractError)
435441
}
436-
contractErrors[contractKey] = *contractError
437442
} else if contract := v.Contract; contract != nil {
438443
storedContract := &protocol.StoredContract{}
439444
err := ProtoUnmarshal(contract.StoredContractBytes, storedContract)
440445
if err != nil {
441446
return
442447
}
443448

444-
if v.CreateContract != nil {
445-
var err error
446-
contractKey.Destination, err = TransferPathFromBytes(
447-
nil,
448-
v.CreateContract.DestinationId,
449-
v.CreateContract.StreamId,
450-
)
451-
if err != nil {
452-
return
453-
}
454-
} else {
449+
if contractKey == nil && self.settings.LegacyCreateContract {
450+
// this only makes sense for legacy contracts
451+
contractKey = &ContractKey{}
455452
contractKey.Destination, err = TransferPathFromBytes(
456453
nil,
457454
storedContract.DestinationId,
458-
storedContract.StreamId,
455+
nil,
459456
)
460457
if err != nil {
461458
return
462459
}
463460
}
464-
contracts[contractKey] = contract
461+
462+
if contractKey != nil {
463+
contracts[*contractKey] = contract
464+
} else {
465+
// this contract can't be associated (TODO close it)
466+
glog.Errorf("[contract]unassociated contract %s\n", Id(storedContract.ContractId))
467+
}
465468
}
466469
}
467470

@@ -806,18 +809,11 @@ func (self *ContractManager) addContract(contractKey ContractKey, contract *prot
806809
return err
807810
}
808811

809-
path, err := TransferPathFromBytes(
810-
storedContract.SourceId,
811-
storedContract.DestinationId,
812-
storedContract.StreamId,
813-
)
814-
if err != nil {
815-
return err
812+
if Id(storedContract.SourceId) != self.client.ClientId() {
813+
return fmt.Errorf("Contract source must be this client: %s<>%s", Id(storedContract.SourceId), self.client.ClientId())
816814
}
817815

818-
if !path.IsStream() && path.SourceId != self.client.ClientId() {
819-
return fmt.Errorf("Contract source must be this client: %s<>%s", path.SourceId, self.client.ClientId())
820-
}
816+
glog.V(1).Infof("[contract]add %s %s\n", self.client.ClientId(), contractKey.Destination)
821817

822818
func() {
823819
contractQueue := self.openContractQueue(contractKey)
@@ -838,7 +834,6 @@ func (self *ContractManager) CreateContract(contractKey ContractKey, contractSeq
838834
createContract := &protocol.CreateContract{
839835
DestinationId: contractKey.Destination.DestinationId.Bytes(),
840836
IntermediaryIds: contractKey.IntermediaryIds.Bytes(),
841-
StreamId: contractKey.Destination.StreamId.Bytes(),
842837
TransferByteCount: uint64(self.contractByteCount(contractSeqIndex, minByteCount)),
843838
Companion: contractKey.CompanionContract,
844839
ForceStream: &contractKey.ForceStream,
@@ -852,11 +847,16 @@ func (self *ContractManager) CreateContract(contractKey ContractKey, contractSeq
852847
glog.Infof("[contract]could not create contract frame = %s", err)
853848
return
854849
}
850+
851+
glog.V(1).Infof("[contract]create %s %s\n", self.client.ClientId(), contractKey.Destination)
852+
855853
self.client.ClientOob().SendControl(
856854
[]*protocol.Frame{frame},
857855
func(resultFrames []*protocol.Frame, err error) {
858856
if err == nil {
859-
self.Receive(SourceId(ControlId), resultFrames, protocol.ProvideMode_Network)
857+
for _, resultFrame := range resultFrames {
858+
self.handleControlFrame(&contractKey, resultFrame)
859+
}
860860
} else {
861861
select {
862862
case <-self.client.Done():
@@ -978,11 +978,16 @@ func (self *ContractManager) Flush(resetUsedContractIds bool) []Id {
978978
self.mutex.Lock()
979979
defer self.mutex.Unlock()
980980

981+
glog.V(1).Infof("[contract]flush %s %s\n", self.client.ClientId(), maps.Keys(self.destinationContracts))
982+
981983
contracts := []*protocol.Contract{}
982-
for _, contractQueue := range self.destinationContracts {
984+
for contractKey, contractQueue := range self.destinationContracts {
983985
for _, contract := range contractQueue.Flush(resetUsedContractIds) {
984986
contracts = append(contracts, contract)
985987
}
988+
if contractQueue.IsDone() {
989+
delete(self.destinationContracts, contractKey)
990+
}
986991
}
987992
return contracts
988993
}()
@@ -1119,7 +1124,7 @@ func (self *contractQueue) Add(contract *protocol.Contract, storedContract *prot
11191124
glog.V(2).Infof("[contract]add update existing %s\n", contractId)
11201125
self.contracts[contractId] = contract
11211126
self.updateMonitor.NotifyAll()
1122-
} else if !self.usedContractIds[contractId] {
1127+
} else if !self.trackUsedContracts || !self.usedContractIds[contractId] {
11231128
glog.V(2).Infof("[contract]add %s\n", contractId)
11241129
if self.trackUsedContracts {
11251130
self.usedContractIds[contractId] = true

transfer_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ func TestSendReceiveSenderReset(t *testing.T) {
7373
// clientSettingsA.ReceiveBufferSettings.AckBufferSize = 0
7474
clientSettingsA.ForwardBufferSettings.SequenceBufferSize = 0
7575
clientSettingsA.ForwardBufferSettings.IdleTimeout = 180 * time.Second
76+
clientSettingsA.ContractManagerSettings.LegacyCreateContract = true
7677
a := NewClient(ctx, aClientId, NewNoContractClientOob(), clientSettingsA)
7778
aRouteManager := a.RouteManager()
7879
aContractManager := a.ContractManager()
@@ -98,6 +99,7 @@ func TestSendReceiveSenderReset(t *testing.T) {
9899
// clientSettingsB.ReceiveBufferSettings.AckBufferSize = 0
99100
clientSettingsB.ForwardBufferSettings.SequenceBufferSize = 0
100101
clientSettingsB.ForwardBufferSettings.IdleTimeout = 180 * time.Second
102+
clientSettingsB.ContractManagerSettings.LegacyCreateContract = true
101103
b := NewClient(ctx, bClientId, NewNoContractClientOob(), clientSettingsB)
102104
bRouteManager := b.RouteManager()
103105
bContractManager := b.ContractManager()

0 commit comments

Comments
 (0)