Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/nats-io/nats-server/v2

go 1.16
go 1.17

require (
github.com/golang/protobuf v1.4.2 // indirect
Expand All @@ -10,7 +10,7 @@ require (
github.com/nats-io/nats.go v1.13.1-0.20211122170419-d7c1d78a50fc
github.com/nats-io/nkeys v0.3.0
github.com/nats-io/nuid v1.0.1
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296 h1:vU9tpM3apjYlLL
github.com/nats-io/jwt/v2 v2.2.1-0.20220113022732-58e87895b296/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k=
github.com/nats-io/nats.go v1.13.1-0.20211122170419-d7c1d78a50fc h1:SHr4MUUZJ/fAC0uSm2OzWOJYsHpapmR86mpw7q1qPXU=
github.com/nats-io/nats.go v1.13.1-0.20211122170419-d7c1d78a50fc/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
github.com/nats-io/nats.go v1.13.1-0.20220106142636-ebcdff697d3f h1:WtlVcCLq7NOOskKidJ1rRZoXwOTs6RIJSl0R/gIPBMg=
github.com/nats-io/nats.go v1.13.1-0.20220106142636-ebcdff697d3f/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8=
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
91 changes: 55 additions & 36 deletions server/accounts.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2018-2021 The NATS Authors
// Copyright 2018-2022 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Expand Down Expand Up @@ -1242,9 +1242,7 @@ func (a *Account) sendReplyInterestLostTrackLatency(si *serviceImport) {
Error: "Request Timeout",
}
a.mu.RLock()
rc := si.rc
share := si.share
ts := si.ts
rc, share, ts := si.rc, si.share, si.ts
sl.RequestHeader = si.trackingHdr
a.mu.RUnlock()
if rc != nil {
Expand All @@ -1257,9 +1255,7 @@ func (a *Account) sendReplyInterestLostTrackLatency(si *serviceImport) {
func (a *Account) sendBackendErrorTrackingLatency(si *serviceImport, reason rsiReason) {
sl := &ServiceLatency{}
a.mu.RLock()
rc := si.rc
share := si.share
ts := si.ts
rc, share, ts := si.rc, si.share, si.ts
sl.RequestHeader = si.trackingHdr
a.mu.RUnlock()
if rc != nil {
Expand Down Expand Up @@ -1568,14 +1564,17 @@ func (a *Account) removeRespServiceImport(si *serviceImport, reason rsiReason) {
}

a.mu.Lock()
c := a.ic
delete(a.exports.responses, si.from)
dest := si.acc
to := si.to
tracking := si.tracking
rc := si.rc
dest, to, tracking, rc, didDeliver := si.acc, si.to, si.tracking, si.rc, si.didDeliver
a.mu.Unlock()

if tracking && rc != nil {
// If we have a sid make sure to unsub.
if len(si.sid) > 0 && c != nil {
c.processUnsub(si.sid)
}

if tracking && rc != nil && !didDeliver {
a.sendBackendErrorTrackingLatency(si, reason)
}

Expand Down Expand Up @@ -1714,12 +1713,17 @@ func (a *Account) checkForReverseEntry(reply string, si *serviceImport, checkInt
var trackingCleanup bool
var rsi *serviceImport
acc.mu.Lock()
c := acc.ic
if rsi = acc.exports.responses[sre.msub]; rsi != nil && !rsi.didDeliver {
delete(acc.exports.responses, rsi.from)
trackingCleanup = rsi.tracking && rsi.rc != nil
}
acc.mu.Unlock()

// If we are doing explicit subs for all responses (e.g. bound to leafnode)
// we will have a non-empty sid here.
if rsi != nil && len(rsi.sid) > 0 && c != nil {
c.processUnsub(rsi.sid)
}
if trackingCleanup {
acc.sendReplyInterestLostTrackLatency(rsi)
}
Expand Down Expand Up @@ -1842,18 +1846,26 @@ func (a *Account) internalClient() *client {

// Internal account scoped subscriptions.
func (a *Account) subscribeInternal(subject string, cb msgHandler) (*subscription, error) {
return a.subscribeInternalEx(subject, cb, false)
}

// Creates internal subscription for service import responses.
func (a *Account) subscribeServiceImportResponse(subject string) (*subscription, error) {
return a.subscribeInternalEx(subject, a.processServiceImportResponse, true)
}

func (a *Account) subscribeInternalEx(subject string, cb msgHandler, ri bool) (*subscription, error) {
a.mu.Lock()
c := a.internalClient()
a.isid++
sid := strconv.FormatUint(a.isid, 10)
c, sid := a.internalClient(), strconv.FormatUint(a.isid, 10)
a.mu.Unlock()

// This will happen in parsing when the account has not been properly setup.
if c == nil {
return nil, fmt.Errorf("no internal account client")
}

return c.processSub([]byte(subject), nil, []byte(sid), cb, false)
return c.processSubEx([]byte(subject), nil, []byte(sid), cb, false, false, ri)
}

// This will add an account subscription that matches the "from" from a service import entry.
Expand Down Expand Up @@ -2062,29 +2074,18 @@ func (a *Account) processServiceImportResponse(sub *subscription, c *client, _ *
c.processServiceImport(si, a, msg)
}

// Will create a wildcard subscription to handle interest graph propagation for all
// service replies.
// Lock should not be held.
func (a *Account) createRespWildcard() []byte {
a.mu.Lock()
// Will create the response prefix for fast generation of responses.
// A wildcard subscription may be used handle interest graph propagation
// for all service replies, unless we are bound to a leafnode.
// Lock should be held.
func (a *Account) createRespWildcard() {
var b = [baseServerLen]byte{'_', 'R', '_', '.'}
rn := a.prand.Uint64()
for i, l := replyPrefixLen, rn; i < len(b); i++ {
b[i] = digits[l%base]
l /= base
}
a.siReply = append(b[:], '.')
pre := a.siReply
wcsub := append(a.siReply, '>')
c := a.internalClient()
a.isid++
sid := strconv.FormatUint(a.isid, 10)
a.mu.Unlock()

// Create subscription and internal callback for all the wildcard response subjects.
c.processSubEx(wcsub, nil, []byte(sid), a.processServiceImportResponse, false, false, true)

return pre
}

// Test whether this is a tracked reply.
Expand All @@ -2097,17 +2098,27 @@ func isTrackedReply(reply []byte) bool {
// FIXME(dlc) - probably do not have to use rand here. about 25ns per.
func (a *Account) newServiceReply(tracking bool) []byte {
a.mu.Lock()
s, replyPre := a.srv, a.siReply
s := a.srv
if a.prand == nil {
var h maphash.Hash
h.WriteString(nuid.Next())
a.prand = rand.New(rand.NewSource(int64(h.Sum64())))
}
rn := a.prand.Uint64()

// Check if we need to create the reply here.
var createdSiReply bool
if a.siReply == nil {
a.createRespWildcard()
createdSiReply = true
}
replyPre, isBoundToLeafnode := a.siReply, a.lds != _EMPTY_
a.mu.Unlock()

if replyPre == nil {
replyPre = a.createRespWildcard()
// If we created the siReply and we are not bound to a leafnode
// we need to do the wildcard subscription.
if createdSiReply && !isBoundToLeafnode {
a.subscribeServiceImportResponse(string(append(replyPre, '>')))
}

var b [replyLen]byte
Expand All @@ -2127,6 +2138,7 @@ func (a *Account) newServiceReply(tracking bool) []byte {
reply = append(reply, s.sys.shash...)
reply = append(reply, '.', 'T')
}

return reply
}

Expand Down Expand Up @@ -2256,12 +2268,19 @@ func (a *Account) addRespServiceImport(dest *Account, to string, osi *serviceImp
si.tracking = true
si.trackingHdr = header
}
isBoundToLeafnode := a.lds != _EMPTY_
a.mu.Unlock()

// We do not do individual subscriptions here like we do on configured imports.
// We might not do individual subscriptions here like we do on configured imports.
// If we are bound to a leafnode we do explicit subscriptions for these.
// We have an internal callback for all responses inbound to this account and
// will process appropriately there. This does not pollute the sublist and the caches.

if isBoundToLeafnode {
sub, _ := a.subscribeServiceImportResponse(nrr)
si.sid = sub.sid
}

// We do add in the reverse map such that we can detect loss of interest and do proper
// cleanup of this si as interest goes away.
dest.addReverseRespMapEntry(a, to, nrr)
Expand Down
Loading