// Copyright 2018-2023 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 // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //go:build !race && !skip_no_race_tests // +build !race,!skip_no_race_tests package server import ( "bufio" "bytes" "compress/gzip" "context" "encoding/binary" "encoding/json" "errors" "fmt" "io" "math" "math/rand" "net" "net/http" "net/url" "path/filepath" "reflect" "runtime" "runtime/debug" "strconv" "strings" "sync" "sync/atomic" "testing" "time" "crypto/hmac" crand "crypto/rand" "crypto/sha256" "github.com/klauspost/compress/s2" "github.com/nats-io/jwt/v2" "github.com/nats-io/nats-server/v2/server/avl" "github.com/nats-io/nats.go" "github.com/nats-io/nkeys" "github.com/nats-io/nuid" ) // IMPORTANT: Tests in this file are not executed when running with the -race flag. // The test name should be prefixed with TestNoRace so we can run only // those tests: go test -run=TestNoRace ... func TestNoRaceAvoidSlowConsumerBigMessages(t *testing.T) { opts := DefaultOptions() // Use defaults to make sure they avoid pending slow consumer. opts.NoSystemAccount = true s := RunServer(opts) defer s.Shutdown() nc1, err := nats.Connect(fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port)) if err != nil { t.Fatalf("Error on connect: %v", err) } defer nc1.Close() nc2, err := nats.Connect(fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port)) if err != nil { t.Fatalf("Error on connect: %v", err) } defer nc2.Close() data := make([]byte, 1024*1024) // 1MB payload crand.Read(data) expected := int32(500) received := int32(0) done := make(chan bool) // Create Subscription. nc1.Subscribe("slow.consumer", func(m *nats.Msg) { // Just eat it so that we are not measuring // code time, just delivery. atomic.AddInt32(&received, 1) if received >= expected { done <- true } }) // Create Error handler nc1.SetErrorHandler(func(c *nats.Conn, s *nats.Subscription, err error) { t.Fatalf("Received an error on the subscription's connection: %v\n", err) }) nc1.Flush() for i := 0; i < int(expected); i++ { nc2.Publish("slow.consumer", data) } nc2.Flush() select { case <-done: return case <-time.After(10 * time.Second): r := atomic.LoadInt32(&received) if s.NumSlowConsumers() > 0 { t.Fatalf("Did not receive all large messages due to slow consumer status: %d of %d", r, expected) } t.Fatalf("Failed to receive all large messages: %d of %d\n", r, expected) } } func TestNoRaceRoutedQueueAutoUnsubscribe(t *testing.T) { optsA, err := ProcessConfigFile("./configs/seed.conf") require_NoError(t, err) optsA.NoSigs, optsA.NoLog = true, true optsA.NoSystemAccount = true srvA := RunServer(optsA) defer srvA.Shutdown() srvARouteURL := fmt.Sprintf("nats://%s:%d", optsA.Cluster.Host, srvA.ClusterAddr().Port) optsB := nextServerOpts(optsA) optsB.Routes = RoutesFromStr(srvARouteURL) srvB := RunServer(optsB) defer srvB.Shutdown() // Wait for these 2 to connect to each other checkClusterFormed(t, srvA, srvB) // Have a client connection to each server ncA, err := nats.Connect(fmt.Sprintf("nats://%s:%d", optsA.Host, optsA.Port)) if err != nil { t.Fatalf("Error on connect: %v", err) } defer ncA.Close() ncB, err := nats.Connect(fmt.Sprintf("nats://%s:%d", optsB.Host, optsB.Port)) if err != nil { t.Fatalf("Error on connect: %v", err) } defer ncB.Close() rbar := int32(0) barCb := func(m *nats.Msg) { atomic.AddInt32(&rbar, 1) } rbaz := int32(0) bazCb := func(m *nats.Msg) { atomic.AddInt32(&rbaz, 1) } // Create 125 queue subs with auto-unsubscribe to each server for // group bar and group baz. So 250 total per queue group. cons := []*nats.Conn{ncA, ncB} for _, c := range cons { for i := 0; i < 100; i++ { qsub, err := c.QueueSubscribe("foo", "bar", barCb) if err != nil { t.Fatalf("Error on subscribe: %v", err) } if err := qsub.AutoUnsubscribe(1); err != nil { t.Fatalf("Error on auto-unsubscribe: %v", err) } qsub, err = c.QueueSubscribe("foo", "baz", bazCb) if err != nil { t.Fatalf("Error on subscribe: %v", err) } if err := qsub.AutoUnsubscribe(1); err != nil { t.Fatalf("Error on auto-unsubscribe: %v", err) } } c.Subscribe("TEST.COMPLETE", func(m *nats.Msg) {}) } // We coelasce now so for each server we will have all local (200) plus // two from the remote side for each queue group. We also create one more // and will wait til each server has 204 subscriptions, that will make sure // that we have everything setup. checkFor(t, 10*time.Second, 100*time.Millisecond, func() error { subsA := srvA.NumSubscriptions() subsB := srvB.NumSubscriptions() if subsA != 204 || subsB != 204 { return fmt.Errorf("Not all subs processed yet: %d and %d", subsA, subsB) } return nil }) expected := int32(200) // Now send messages from each server for i := int32(0); i < expected; i++ { c := cons[i%2] c.Publish("foo", []byte("Don't Drop Me!")) } for _, c := range cons { c.Flush() } checkFor(t, 10*time.Second, 100*time.Millisecond, func() error { nbar := atomic.LoadInt32(&rbar) nbaz := atomic.LoadInt32(&rbaz) if nbar == expected && nbaz == expected { return nil } return fmt.Errorf("Did not receive all %d queue messages, received %d for 'bar' and %d for 'baz'", expected, atomic.LoadInt32(&rbar), atomic.LoadInt32(&rbaz)) }) } func TestNoRaceClosedSlowConsumerWriteDeadline(t *testing.T) { opts := DefaultOptions() opts.NoSystemAccount = true opts.WriteDeadline = 10 * time.Millisecond // Make very small to trip. opts.MaxPending = 500 * 1024 * 1024 // Set high so it will not trip here. s := RunServer(opts) defer s.Shutdown() c, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", opts.Host, opts.Port), 3*time.Second) if err != nil { t.Fatalf("Error on connect: %v", err) } defer c.Close() if _, err := c.Write([]byte("CONNECT {}\r\nPING\r\nSUB foo 1\r\n")); err != nil { t.Fatalf("Error sending protocols to server: %v", err) } // Reduce socket buffer to increase reliability of data backing up in the server destined // for our subscribed client. c.(*net.TCPConn).SetReadBuffer(128) url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) sender, err := nats.Connect(url) if err != nil { t.Fatalf("Error on connect: %v", err) } defer sender.Close() payload := make([]byte, 1024*1024) for i := 0; i < 100; i++ { if err := sender.Publish("foo", payload); err != nil { t.Fatalf("Error on publish: %v", err) } } // Flush sender connection to ensure that all data has been sent. if err := sender.Flush(); err != nil { t.Fatalf("Error on flush: %v", err) } // At this point server should have closed connection c. checkClosedConns(t, s, 1, 2*time.Second) conns := s.closedClients() if lc := len(conns); lc != 1 { t.Fatalf("len(conns) expected to be %d, got %d\n", 1, lc) } checkReason(t, conns[0].Reason, SlowConsumerWriteDeadline) } func TestNoRaceClosedSlowConsumerPendingBytes(t *testing.T) { opts := DefaultOptions() opts.NoSystemAccount = true opts.WriteDeadline = 30 * time.Second // Wait for long time so write deadline does not trigger slow consumer. opts.MaxPending = 1 * 1024 * 1024 // Set to low value (1MB) to allow SC to trip. s := RunServer(opts) defer s.Shutdown() c, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", opts.Host, opts.Port), 3*time.Second) if err != nil { t.Fatalf("Error on connect: %v", err) } defer c.Close() if _, err := c.Write([]byte("CONNECT {}\r\nPING\r\nSUB foo 1\r\n")); err != nil { t.Fatalf("Error sending protocols to server: %v", err) } // Reduce socket buffer to increase reliability of data backing up in the server destined // for our subscribed client. c.(*net.TCPConn).SetReadBuffer(128) url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) sender, err := nats.Connect(url) if err != nil { t.Fatalf("Error on connect: %v", err) } defer sender.Close() payload := make([]byte, 1024*1024) for i := 0; i < 100; i++ { if err := sender.Publish("foo", payload); err != nil { t.Fatalf("Error on publish: %v", err) } } // Flush sender connection to ensure that all data has been sent. if err := sender.Flush(); err != nil { t.Fatalf("Error on flush: %v", err) } // At this point server should have closed connection c. checkClosedConns(t, s, 1, 2*time.Second) conns := s.closedClients() if lc := len(conns); lc != 1 { t.Fatalf("len(conns) expected to be %d, got %d\n", 1, lc) } checkReason(t, conns[0].Reason, SlowConsumerPendingBytes) } func TestNoRaceSlowConsumerPendingBytes(t *testing.T) { opts := DefaultOptions() opts.NoSystemAccount = true opts.WriteDeadline = 30 * time.Second // Wait for long time so write deadline does not trigger slow consumer. opts.MaxPending = 1 * 1024 * 1024 // Set to low value (1MB) to allow SC to trip. s := RunServer(opts) defer s.Shutdown() c, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", opts.Host, opts.Port), 3*time.Second) if err != nil { t.Fatalf("Error on connect: %v", err) } defer c.Close() if _, err := c.Write([]byte("CONNECT {}\r\nPING\r\nSUB foo 1\r\n")); err != nil { t.Fatalf("Error sending protocols to server: %v", err) } // Reduce socket buffer to increase reliability of data backing up in the server destined // for our subscribed client. c.(*net.TCPConn).SetReadBuffer(128) url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) sender, err := nats.Connect(url) if err != nil { t.Fatalf("Error on connect: %v", err) } defer sender.Close() payload := make([]byte, 1024*1024) for i := 0; i < 100; i++ { if err := sender.Publish("foo", payload); err != nil { t.Fatalf("Error on publish: %v", err) } } // Flush sender connection to ensure that all data has been sent. if err := sender.Flush(); err != nil { t.Fatalf("Error on flush: %v", err) } // At this point server should have closed connection c. // On certain platforms, it may take more than one call before // getting the error. for i := 0; i < 100; i++ { if _, err := c.Write([]byte("PUB bar 5\r\nhello\r\n")); err != nil { // ok return } } t.Fatal("Connection should have been closed") } func TestNoRaceGatewayNoMissingReplies(t *testing.T) { // This test will have following setup: // // responder1 requestor // | | // v v // [A1]<-------gw------------[B1] // | \ | // | \______gw__________ | route // | _\| | // [ ]--------gw----------->[ ] // [A2]<-------gw------------[B2] // [ ] [ ] // ^ // | // responder2 // // There is a possible race that when the requestor creates // a subscription on the reply subject, the subject interest // being sent from the inbound gateway, and B1 having none, // the SUB first goes to B2 before being sent to A1 from // B2's inbound GW. But the request can go from B1 to A1 // right away and the responder1 connecting to A1 may send // back the reply before the interest on the reply makes it // to A1 (from B2). // This test will also verify that if the responder is instead // connected to A2, the reply is properly received by requestor // on B1. // For this test we want to be in interestOnly mode, so // make it happen quickly gatewayMaxRUnsubBeforeSwitch = 1 defer func() { gatewayMaxRUnsubBeforeSwitch = defaultGatewayMaxRUnsubBeforeSwitch }() // Start with setting up A2 and B2. ob2 := testDefaultOptionsForGateway("B") sb2 := runGatewayServer(ob2) defer sb2.Shutdown() oa2 := testGatewayOptionsFromToWithServers(t, "A", "B", sb2) sa2 := runGatewayServer(oa2) defer sa2.Shutdown() waitForOutboundGateways(t, sa2, 1, time.Second) waitForInboundGateways(t, sa2, 1, time.Second) waitForOutboundGateways(t, sb2, 1, time.Second) waitForInboundGateways(t, sb2, 1, time.Second) // Now start A1 which will connect to B2 oa1 := testGatewayOptionsFromToWithServers(t, "A", "B", sb2) oa1.Routes = RoutesFromStr(fmt.Sprintf("nats://%s:%d", oa2.Cluster.Host, oa2.Cluster.Port)) sa1 := runGatewayServer(oa1) defer sa1.Shutdown() waitForOutboundGateways(t, sa1, 1, time.Second) waitForInboundGateways(t, sb2, 2, time.Second) checkClusterFormed(t, sa1, sa2) // Finally, start B1 that will connect to A1. ob1 := testGatewayOptionsFromToWithServers(t, "B", "A", sa1) ob1.Routes = RoutesFromStr(fmt.Sprintf("nats://%s:%d", ob2.Cluster.Host, ob2.Cluster.Port)) sb1 := runGatewayServer(ob1) defer sb1.Shutdown() // Check that we have the outbound gateway from B1 to A1 checkFor(t, 3*time.Second, 15*time.Millisecond, func() error { c := sb1.getOutboundGatewayConnection("A") if c == nil { return fmt.Errorf("Outbound connection to A not created yet") } c.mu.Lock() name := c.opts.Name nc := c.nc c.mu.Unlock() if name != sa1.ID() { // Force a disconnect nc.Close() return fmt.Errorf("Was unable to have B1 connect to A1") } return nil }) waitForInboundGateways(t, sa1, 1, time.Second) checkClusterFormed(t, sb1, sb2) a1URL := fmt.Sprintf("nats://%s:%d", oa1.Host, oa1.Port) a2URL := fmt.Sprintf("nats://%s:%d", oa2.Host, oa2.Port) b1URL := fmt.Sprintf("nats://%s:%d", ob1.Host, ob1.Port) b2URL := fmt.Sprintf("nats://%s:%d", ob2.Host, ob2.Port) ncb1 := natsConnect(t, b1URL) defer ncb1.Close() ncb2 := natsConnect(t, b2URL) defer ncb2.Close() natsSubSync(t, ncb1, "just.a.sub") natsSubSync(t, ncb2, "just.a.sub") checkExpectedSubs(t, 2, sb1, sb2) // For this test, we want A to be checking B's interest in order // to send messages (which would cause replies to be dropped if // there is no interest registered on A). So from A servers, // send to various subjects and cause B's to switch to interestOnly // mode. nca1 := natsConnect(t, a1URL) defer nca1.Close() for i := 0; i < 10; i++ { natsPub(t, nca1, fmt.Sprintf("reject.%d", i), []byte("hello")) } nca2 := natsConnect(t, a2URL) defer nca2.Close() for i := 0; i < 10; i++ { natsPub(t, nca2, fmt.Sprintf("reject.%d", i), []byte("hello")) } checkSwitchedMode := func(t *testing.T, s *Server) { t.Helper() checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { var switchedMode bool c := s.getOutboundGatewayConnection("B") ei, _ := c.gw.outsim.Load(globalAccountName) if ei != nil { e := ei.(*outsie) e.RLock() switchedMode = e.ni == nil && e.mode == InterestOnly e.RUnlock() } if !switchedMode { return fmt.Errorf("Still not switched mode") } return nil }) } checkSwitchedMode(t, sa1) checkSwitchedMode(t, sa2) // Setup a subscriber on _INBOX.> on each of A's servers. total := 1000 expected := int32(total) rcvOnA := int32(0) qrcvOnA := int32(0) natsSub(t, nca1, "myreply.>", func(_ *nats.Msg) { atomic.AddInt32(&rcvOnA, 1) }) natsQueueSub(t, nca2, "myreply.>", "bar", func(_ *nats.Msg) { atomic.AddInt32(&qrcvOnA, 1) }) checkExpectedSubs(t, 2, sa1, sa2) // Ok.. so now we will run the actual test where we // create a responder on A1 and make sure that every // single request from B1 gets the reply. Will repeat // test with responder connected to A2. sendReqs := func(t *testing.T, subConn *nats.Conn) { t.Helper() responder := natsSub(t, subConn, "foo", func(m *nats.Msg) { m.Respond([]byte("reply")) }) natsFlush(t, subConn) checkExpectedSubs(t, 3, sa1, sa2) // We are not going to use Request() because this sets // a wildcard subscription on an INBOX and less likely // to produce the race. Instead we will explicitly set // the subscription on the reply subject and create one // per request. for i := 0; i < total/2; i++ { reply := fmt.Sprintf("myreply.%d", i) replySub := natsQueueSubSync(t, ncb1, reply, "bar") natsFlush(t, ncb1) // Let's make sure we have interest on B2. if r := sb2.globalAccount().sl.Match(reply); len(r.qsubs) == 0 { checkFor(t, time.Second, time.Millisecond, func() error { if r := sb2.globalAccount().sl.Match(reply); len(r.qsubs) == 0 { return fmt.Errorf("B still not registered interest on %s", reply) } return nil }) } natsPubReq(t, ncb1, "foo", reply, []byte("request")) if _, err := replySub.NextMsg(time.Second); err != nil { t.Fatalf("Did not receive reply: %v", err) } natsUnsub(t, replySub) } responder.Unsubscribe() natsFlush(t, subConn) checkExpectedSubs(t, 2, sa1, sa2) } sendReqs(t, nca1) sendReqs(t, nca2) checkFor(t, time.Second, 15*time.Millisecond, func() error { if n := atomic.LoadInt32(&rcvOnA); n != expected { return fmt.Errorf("Subs on A expected to get %v replies, got %v", expected, n) } return nil }) // We should not have received a single message on the queue sub // on cluster A because messages will have been delivered to // the member on cluster B. if n := atomic.LoadInt32(&qrcvOnA); n != 0 { t.Fatalf("Queue sub on A should not have received message, got %v", n) } } func TestNoRaceRouteMemUsage(t *testing.T) { oa := DefaultOptions() sa := RunServer(oa) defer sa.Shutdown() ob := DefaultOptions() ob.Routes = RoutesFromStr(fmt.Sprintf("nats://%s:%d", oa.Cluster.Host, oa.Cluster.Port)) sb := RunServer(ob) defer sb.Shutdown() checkClusterFormed(t, sa, sb) responder := natsConnect(t, fmt.Sprintf("nats://%s:%d", oa.Host, oa.Port)) defer responder.Close() for i := 0; i < 10; i++ { natsSub(t, responder, "foo", func(m *nats.Msg) { m.Respond(m.Data) }) } natsFlush(t, responder) payload := make([]byte, 50*1024) bURL := fmt.Sprintf("nats://%s:%d", ob.Host, ob.Port) // Capture mem usage mem := runtime.MemStats{} runtime.ReadMemStats(&mem) inUseBefore := mem.HeapInuse for i := 0; i < 100; i++ { requestor := natsConnect(t, bURL) // Don't use a defer here otherwise that will make the memory check fail! // We are closing the connection just after these few instructions that // are not calling t.Fatal() anyway. inbox := nats.NewInbox() sub := natsSubSync(t, requestor, inbox) natsPubReq(t, requestor, "foo", inbox, payload) for j := 0; j < 10; j++ { natsNexMsg(t, sub, time.Second) } requestor.Close() } runtime.GC() debug.FreeOSMemory() runtime.ReadMemStats(&mem) inUseNow := mem.HeapInuse if inUseNow > 3*inUseBefore { t.Fatalf("Heap in-use before was %v, now %v: too high", inUseBefore, inUseNow) } } func TestNoRaceRouteCache(t *testing.T) { maxPerAccountCacheSize = 20 prunePerAccountCacheSize = 5 closedSubsCheckInterval = 250 * time.Millisecond defer func() { maxPerAccountCacheSize = defaultMaxPerAccountCacheSize prunePerAccountCacheSize = defaultPrunePerAccountCacheSize closedSubsCheckInterval = defaultClosedSubsCheckInterval }() for _, test := range []struct { name string useQueue bool }{ {"plain_sub", false}, {"queue_sub", true}, } { t.Run(test.name, func(t *testing.T) { oa := DefaultOptions() oa.NoSystemAccount = true oa.Cluster.PoolSize = -1 sa := RunServer(oa) defer sa.Shutdown() ob := DefaultOptions() ob.NoSystemAccount = true ob.Cluster.PoolSize = -1 ob.Routes = RoutesFromStr(fmt.Sprintf("nats://%s:%d", oa.Cluster.Host, oa.Cluster.Port)) sb := RunServer(ob) defer sb.Shutdown() checkClusterFormed(t, sa, sb) responder := natsConnect(t, fmt.Sprintf("nats://%s:%d", oa.Host, oa.Port)) defer responder.Close() natsSub(t, responder, "foo", func(m *nats.Msg) { m.Respond(m.Data) }) natsFlush(t, responder) checkExpectedSubs(t, 1, sa) checkExpectedSubs(t, 1, sb) bURL := fmt.Sprintf("nats://%s:%d", ob.Host, ob.Port) requestor := natsConnect(t, bURL) defer requestor.Close() ch := make(chan struct{}, 1) cb := func(_ *nats.Msg) { select { case ch <- struct{}{}: default: } } sendReqs := func(t *testing.T, nc *nats.Conn, count int, unsub bool) { t.Helper() for i := 0; i < count; i++ { inbox := nats.NewInbox() var sub *nats.Subscription if test.useQueue { sub = natsQueueSub(t, nc, inbox, "queue", cb) } else { sub = natsSub(t, nc, inbox, cb) } natsPubReq(t, nc, "foo", inbox, []byte("hello")) select { case <-ch: case <-time.After(time.Second): t.Fatalf("Failed to get reply") } if unsub { natsUnsub(t, sub) } } } sendReqs(t, requestor, maxPerAccountCacheSize+1, true) var route *client sb.mu.Lock() route = getFirstRoute(sb) sb.mu.Unlock() checkExpected := func(t *testing.T, expected int) { t.Helper() checkFor(t, 2*time.Second, 15*time.Millisecond, func() error { route.mu.Lock() n := len(route.in.pacache) route.mu.Unlock() if n != expected { return fmt.Errorf("Expected %v subs in the cache, got %v", expected, n) } return nil }) } checkExpected(t, (maxPerAccountCacheSize+1)-(prunePerAccountCacheSize+1)) // Wait for more than the orphan check time.Sleep(2 * closedSubsCheckInterval) // Add a new subs up to point where new prune would occur sendReqs(t, requestor, prunePerAccountCacheSize+1, false) // Now closed subs should have been removed, so expected // subs in the cache should be the new ones. checkExpected(t, prunePerAccountCacheSize+1) // Now try wil implicit unsubscribe (due to connection close) sendReqs(t, requestor, maxPerAccountCacheSize+1, false) requestor.Close() checkExpected(t, maxPerAccountCacheSize-prunePerAccountCacheSize) // Wait for more than the orphan check time.Sleep(2 * closedSubsCheckInterval) // Now create new connection and send prunePerAccountCacheSize+1 // and that should cause all subs from previous connection to be // removed from cache requestor = natsConnect(t, bURL) defer requestor.Close() sendReqs(t, requestor, prunePerAccountCacheSize+1, false) checkExpected(t, prunePerAccountCacheSize+1) }) } } func TestNoRaceFetchAccountDoesNotRegisterAccountTwice(t *testing.T) { sa, oa, sb, ob, _ := runTrustedGateways(t) defer sa.Shutdown() defer sb.Shutdown() // Let's create a user account. okp, _ := nkeys.FromSeed(oSeed) akp, _ := nkeys.CreateAccount() pub, _ := akp.PublicKey() nac := jwt.NewAccountClaims(pub) jwt, _ := nac.Encode(okp) userAcc := pub // Replace B's account resolver with one that introduces // delay during the Fetch() sac := &slowAccResolver{AccountResolver: sb.AccountResolver()} sb.SetAccountResolver(sac) // Add the account in sa and sb addAccountToMemResolver(sa, userAcc, jwt) addAccountToMemResolver(sb, userAcc, jwt) // Tell the slow account resolver which account to slow down sac.Lock() sac.acc = userAcc sac.Unlock() urlA := fmt.Sprintf("nats://%s:%d", oa.Host, oa.Port) urlB := fmt.Sprintf("nats://%s:%d", ob.Host, ob.Port) nca, err := nats.Connect(urlA, createUserCreds(t, sa, akp)) if err != nil { t.Fatalf("Error connecting to A: %v", err) } defer nca.Close() // Since there is an optimistic send, this message will go to B // and on processing this message, B will lookup/fetch this // account, which can produce race with the fetch of this // account from A's system account that sent a notification // about this account, or with the client connect just after // that. nca.Publish("foo", []byte("hello")) // Now connect and create a subscription on B ncb, err := nats.Connect(urlB, createUserCreds(t, sb, akp)) if err != nil { t.Fatalf("Error connecting to A: %v", err) } defer ncb.Close() sub, err := ncb.SubscribeSync("foo") if err != nil { t.Fatalf("Error on subscribe: %v", err) } ncb.Flush() // Now send messages from A and B should ultimately start to receive // them (once the subscription has been correctly registered) ok := false for i := 0; i < 10; i++ { nca.Publish("foo", []byte("hello")) if _, err := sub.NextMsg(100 * time.Millisecond); err != nil { continue } ok = true break } if !ok { t.Fatalf("B should be able to receive messages") } checkTmpAccounts := func(t *testing.T, s *Server) { t.Helper() empty := true s.tmpAccounts.Range(func(_, _ interface{}) bool { empty = false return false }) if !empty { t.Fatalf("tmpAccounts is not empty") } } checkTmpAccounts(t, sa) checkTmpAccounts(t, sb) } func TestNoRaceWriteDeadline(t *testing.T) { opts := DefaultOptions() opts.NoSystemAccount = true opts.WriteDeadline = 30 * time.Millisecond s := RunServer(opts) defer s.Shutdown() c, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", opts.Host, opts.Port), 3*time.Second) if err != nil { t.Fatalf("Error on connect: %v", err) } defer c.Close() if _, err := c.Write([]byte("CONNECT {}\r\nPING\r\nSUB foo 1\r\n")); err != nil { t.Fatalf("Error sending protocols to server: %v", err) } // Reduce socket buffer to increase reliability of getting // write deadline errors. c.(*net.TCPConn).SetReadBuffer(4) url := fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port) sender, err := nats.Connect(url) if err != nil { t.Fatalf("Error on connect: %v", err) } defer sender.Close() payload := make([]byte, 1000000) total := 1000 for i := 0; i < total; i++ { if err := sender.Publish("foo", payload); err != nil { t.Fatalf("Error on publish: %v", err) } } // Flush sender connection to ensure that all data has been sent. if err := sender.Flush(); err != nil { t.Fatalf("Error on flush: %v", err) } // At this point server should have closed connection c. // On certain platforms, it may take more than one call before // getting the error. for i := 0; i < 100; i++ { if _, err := c.Write([]byte("PUB bar 5\r\nhello\r\n")); err != nil { // ok return } } t.Fatal("Connection should have been closed") } func TestNoRaceLeafNodeClusterNameConflictDeadlock(t *testing.T) { o := DefaultOptions() o.LeafNode.Port = -1 s := RunServer(o) defer s.Shutdown() u, err := url.Parse(fmt.Sprintf("nats://127.0.0.1:%d", o.LeafNode.Port)) if err != nil { t.Fatalf("Error parsing url: %v", err) } o1 := DefaultOptions() o1.ServerName = "A1" o1.Cluster.Name = "clusterA" o1.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{u}}} s1 := RunServer(o1) defer s1.Shutdown() checkLeafNodeConnected(t, s1) o2 := DefaultOptions() o2.ServerName = "A2" o2.Cluster.Name = "clusterA" o2.Routes = RoutesFromStr(fmt.Sprintf("nats://127.0.0.1:%d", o1.Cluster.Port)) o2.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{u}}} s2 := RunServer(o2) defer s2.Shutdown() checkLeafNodeConnected(t, s2) checkClusterFormed(t, s1, s2) o3 := DefaultOptions() o3.ServerName = "A3" o3.Cluster.Name = "" // intentionally not set o3.Routes = RoutesFromStr(fmt.Sprintf("nats://127.0.0.1:%d", o1.Cluster.Port)) o3.LeafNode.Remotes = []*RemoteLeafOpts{{URLs: []*url.URL{u}}} s3 := RunServer(o3) defer s3.Shutdown() checkLeafNodeConnected(t, s3) checkClusterFormed(t, s1, s2, s3) } // This test is same than TestAccountAddServiceImportRace but running // without the -race flag, it would capture more easily the possible // duplicate sid, resulting in less than expected number of subscriptions // in the account's internal subscriptions map. func TestNoRaceAccountAddServiceImportRace(t *testing.T) { TestAccountAddServiceImportRace(t) } // Similar to the routed version. Make sure we receive all of the // messages with auto-unsubscribe enabled. func TestNoRaceQueueAutoUnsubscribe(t *testing.T) { opts := DefaultOptions() s := RunServer(opts) defer s.Shutdown() nc, err := nats.Connect(fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port)) if err != nil { t.Fatalf("Error on connect: %v", err) } defer nc.Close() rbar := int32(0) barCb := func(m *nats.Msg) { atomic.AddInt32(&rbar, 1) } rbaz := int32(0) bazCb := func(m *nats.Msg) { atomic.AddInt32(&rbaz, 1) } // Create 1000 subscriptions with auto-unsubscribe of 1. // Do two groups, one bar and one baz. total := 1000 for i := 0; i < total; i++ { qsub, err := nc.QueueSubscribe("foo", "bar", barCb) if err != nil { t.Fatalf("Error on subscribe: %v", err) } if err := qsub.AutoUnsubscribe(1); err != nil { t.Fatalf("Error on auto-unsubscribe: %v", err) } qsub, err = nc.QueueSubscribe("foo", "baz", bazCb) if err != nil { t.Fatalf("Error on subscribe: %v", err) } if err := qsub.AutoUnsubscribe(1); err != nil { t.Fatalf("Error on auto-unsubscribe: %v", err) } } nc.Flush() expected := int32(total) for i := int32(0); i < expected; i++ { nc.Publish("foo", []byte("Don't Drop Me!")) } nc.Flush() checkFor(t, 5*time.Second, 10*time.Millisecond, func() error { nbar := atomic.LoadInt32(&rbar) nbaz := atomic.LoadInt32(&rbaz) if nbar == expected && nbaz == expected { return nil } return fmt.Errorf("Did not receive all %d queue messages, received %d for 'bar' and %d for 'baz'", expected, atomic.LoadInt32(&rbar), atomic.LoadInt32(&rbaz)) }) } func TestNoRaceAcceptLoopsDoNotLeaveOpenedConn(t *testing.T) { for _, test := range []struct { name string url func(o *Options) (string, int) }{ {"client", func(o *Options) (string, int) { return o.Host, o.Port }}, {"route", func(o *Options) (string, int) { return o.Cluster.Host, o.Cluster.Port }}, {"gateway", func(o *Options) (string, int) { return o.Gateway.Host, o.Gateway.Port }}, {"leafnode", func(o *Options) (string, int) { return o.LeafNode.Host, o.LeafNode.Port }}, {"websocket", func(o *Options) (string, int) { return o.Websocket.Host, o.Websocket.Port }}, } { t.Run(test.name, func(t *testing.T) { o := DefaultOptions() o.DisableShortFirstPing = true o.Accounts = []*Account{NewAccount("$SYS")} o.SystemAccount = "$SYS" o.Cluster.Name = "abc" o.Cluster.Host = "127.0.0.1" o.Cluster.Port = -1 o.Gateway.Name = "abc" o.Gateway.Host = "127.0.0.1" o.Gateway.Port = -1 o.LeafNode.Host = "127.0.0.1" o.LeafNode.Port = -1 o.Websocket.Host = "127.0.0.1" o.Websocket.Port = -1 o.Websocket.HandshakeTimeout = 1 o.Websocket.NoTLS = true s := RunServer(o) defer s.Shutdown() host, port := test.url(o) url := fmt.Sprintf("%s:%d", host, port) var conns []net.Conn wg := sync.WaitGroup{} wg.Add(1) done := make(chan struct{}, 1) go func() { defer wg.Done() // Have an upper limit for i := 0; i < 200; i++ { c, err := net.Dial("tcp", url) if err != nil { return } conns = append(conns, c) select { case <-done: return default: } } }() time.Sleep(15 * time.Millisecond) s.Shutdown() close(done) wg.Wait() for _, c := range conns { c.SetReadDeadline(time.Now().Add(2 * time.Second)) br := bufio.NewReader(c) // Read INFO for connections that were accepted _, _, err := br.ReadLine() if err == nil { // After that, the connection should be closed, // so we should get an error here. _, _, err = br.ReadLine() } // We expect an io.EOF or any other error indicating the use of a closed // connection, but we should not get the timeout error. if ne, ok := err.(net.Error); ok && ne.Timeout() { err = nil } if err == nil { var buf [10]byte c.SetDeadline(time.Now().Add(2 * time.Second)) c.Write([]byte("C")) _, err = c.Read(buf[:]) if ne, ok := err.(net.Error); ok && ne.Timeout() { err = nil } } if err == nil { t.Fatalf("Connection should have been closed") } c.Close() } }) } } func TestNoRaceJetStreamDeleteStreamManyConsumers(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() mname := "MYS" mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: mname, Storage: FileStorage}) if err != nil { t.Fatalf("Unexpected error adding stream: %v", err) } // This number needs to be higher than the internal sendq size to trigger what this test is testing. for i := 0; i < 2000; i++ { _, err := mset.addConsumer(&ConsumerConfig{ Durable: fmt.Sprintf("D-%d", i), DeliverSubject: fmt.Sprintf("deliver.%d", i), }) if err != nil { t.Fatalf("Error creating consumer: %v", err) } } // With bug this would not return and would hang. mset.delete() } // We used to swap accounts on an inbound message when processing service imports. // Until JetStream this was kinda ok, but with JetStream we can have pull consumers // trying to access the clients account in another Go routine now which causes issues. // This is not limited to the case above, its just the one that exposed it. // This test is to show that issue and that the fix works, meaning we no longer swap c.acc. func TestNoRaceJetStreamServiceImportAccountSwapIssue(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() // Client based API nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo", "bar"}, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } sub, err := js.PullSubscribe("foo", "dlc") if err != nil { t.Fatalf("Unexpected error: %v", err) } beforeSubs := s.NumSubscriptions() // How long we want both sides to run. timeout := time.Now().Add(3 * time.Second) errs := make(chan error, 1) // Publishing side, which will signal the consumer that is waiting and which will access c.acc. If publish // operation runs concurrently we will catch c.acc being $SYS some of the time. go func() { time.Sleep(100 * time.Millisecond) for time.Now().Before(timeout) { // This will signal the delivery of the pull messages. js.Publish("foo", []byte("Hello")) // This will swap the account because of JetStream service import. // We can get an error here with the bug or not. if _, err := js.StreamInfo("TEST"); err != nil { errs <- err return } } errs <- nil }() // Pull messages flow. var received int for time.Now().Before(timeout.Add(2 * time.Second)) { if msgs, err := sub.Fetch(1, nats.MaxWait(200*time.Millisecond)); err == nil { for _, m := range msgs { received++ m.AckSync() } } else { break } } // Wait on publisher Go routine and check for errors. if err := <-errs; err != nil { t.Fatalf("Unexpected error: %v", err) } // Double check all received. si, err := js.StreamInfo("TEST") if err != nil { t.Fatalf("Unexpected error: %v", err) } if int(si.State.Msgs) != received { t.Fatalf("Expected to receive %d msgs, only got %d", si.State.Msgs, received) } // Now check for leaked subs from the fetch call above. That is what we first saw from the bug. if afterSubs := s.NumSubscriptions(); afterSubs != beforeSubs { t.Fatalf("Leaked subscriptions: %d before, %d after", beforeSubs, afterSubs) } } func TestNoRaceJetStreamAPIStreamListPaging(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() // Create 2X limit streamsNum := 2 * JSApiNamesLimit for i := 1; i <= streamsNum; i++ { name := fmt.Sprintf("STREAM-%06d", i) cfg := StreamConfig{Name: name, Storage: MemoryStorage} _, err := s.GlobalAccount().addStream(&cfg) if err != nil { t.Fatalf("Unexpected error adding stream: %v", err) } } // Client for API requests. nc := clientConnectToServer(t, s) defer nc.Close() reqList := func(offset int) []byte { t.Helper() var req []byte if offset > 0 { req, _ = json.Marshal(&ApiPagedRequest{Offset: offset}) } resp, err := nc.Request(JSApiStreams, req, time.Second) if err != nil { t.Fatalf("Unexpected error getting stream list: %v", err) } return resp.Data } checkResp := func(resp []byte, expectedLen, expectedOffset int) { t.Helper() var listResponse JSApiStreamNamesResponse if err := json.Unmarshal(resp, &listResponse); err != nil { t.Fatalf("Unexpected error: %v", err) } if len(listResponse.Streams) != expectedLen { t.Fatalf("Expected only %d streams but got %d", expectedLen, len(listResponse.Streams)) } if listResponse.Total != streamsNum { t.Fatalf("Expected total to be %d but got %d", streamsNum, listResponse.Total) } if listResponse.Offset != expectedOffset { t.Fatalf("Expected offset to be %d but got %d", expectedOffset, listResponse.Offset) } if expectedLen < 1 { return } // Make sure we get the right stream. sname := fmt.Sprintf("STREAM-%06d", expectedOffset+1) if listResponse.Streams[0] != sname { t.Fatalf("Expected stream %q to be first, got %q", sname, listResponse.Streams[0]) } } checkResp(reqList(0), JSApiNamesLimit, 0) checkResp(reqList(JSApiNamesLimit), JSApiNamesLimit, JSApiNamesLimit) checkResp(reqList(streamsNum), 0, streamsNum) checkResp(reqList(streamsNum-22), 22, streamsNum-22) checkResp(reqList(streamsNum+22), 0, streamsNum) } func TestNoRaceJetStreamAPIConsumerListPaging(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() sname := "MYSTREAM" mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: sname}) if err != nil { t.Fatalf("Unexpected error adding stream: %v", err) } // Client for API requests. nc := clientConnectToServer(t, s) defer nc.Close() consumersNum := JSApiNamesLimit for i := 1; i <= consumersNum; i++ { dsubj := fmt.Sprintf("d.%d", i) sub, _ := nc.SubscribeSync(dsubj) defer sub.Unsubscribe() nc.Flush() _, err := mset.addConsumer(&ConsumerConfig{DeliverSubject: dsubj}) if err != nil { t.Fatalf("Unexpected error: %v", err) } } reqListSubject := fmt.Sprintf(JSApiConsumersT, sname) reqList := func(offset int) []byte { t.Helper() var req []byte if offset > 0 { req, _ = json.Marshal(&JSApiConsumersRequest{ApiPagedRequest: ApiPagedRequest{Offset: offset}}) } resp, err := nc.Request(reqListSubject, req, time.Second) if err != nil { t.Fatalf("Unexpected error getting stream list: %v", err) } return resp.Data } checkResp := func(resp []byte, expectedLen, expectedOffset int) { t.Helper() var listResponse JSApiConsumerNamesResponse if err := json.Unmarshal(resp, &listResponse); err != nil { t.Fatalf("Unexpected error: %v", err) } if len(listResponse.Consumers) != expectedLen { t.Fatalf("Expected only %d streams but got %d", expectedLen, len(listResponse.Consumers)) } if listResponse.Total != consumersNum { t.Fatalf("Expected total to be %d but got %d", consumersNum, listResponse.Total) } if listResponse.Offset != expectedOffset { t.Fatalf("Expected offset to be %d but got %d", expectedOffset, listResponse.Offset) } } checkResp(reqList(0), JSApiNamesLimit, 0) checkResp(reqList(consumersNum-22), 22, consumersNum-22) checkResp(reqList(consumersNum+22), 0, consumersNum) } func TestNoRaceJetStreamWorkQueueLoadBalance(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() mname := "MY_MSG_SET" mset, err := s.GlobalAccount().addStream(&StreamConfig{Name: mname, Subjects: []string{"foo", "bar"}}) if err != nil { t.Fatalf("Unexpected error adding message set: %v", err) } defer mset.delete() // Create basic work queue mode consumer. oname := "WQ" o, err := mset.addConsumer(&ConsumerConfig{Durable: oname, AckPolicy: AckExplicit}) if err != nil { t.Fatalf("Expected no error with durable, got %v", err) } defer o.delete() // To send messages. nc := clientConnectToServer(t, s) defer nc.Close() // For normal work queue semantics, you send requests to the subject with stream and consumer name. reqMsgSubj := o.requestNextMsgSubject() numWorkers := 25 counts := make([]int32, numWorkers) var received int32 rwg := &sync.WaitGroup{} rwg.Add(numWorkers) wg := &sync.WaitGroup{} wg.Add(numWorkers) ch := make(chan bool) toSend := 1000 for i := 0; i < numWorkers; i++ { nc := clientConnectToServer(t, s) defer nc.Close() go func(index int32) { rwg.Done() defer wg.Done() <-ch for counter := &counts[index]; ; { m, err := nc.Request(reqMsgSubj, nil, 100*time.Millisecond) if err != nil { return } m.Respond(nil) atomic.AddInt32(counter, 1) if total := atomic.AddInt32(&received, 1); total >= int32(toSend) { return } } }(int32(i)) } // Wait for requestors to be ready rwg.Wait() close(ch) sendSubj := "bar" for i := 0; i < toSend; i++ { sendStreamMsg(t, nc, sendSubj, "Hello World!") } // Wait for test to complete. wg.Wait() target := toSend / numWorkers delta := target/2 + 5 low, high := int32(target-delta), int32(target+delta) for i := 0; i < numWorkers; i++ { if msgs := atomic.LoadInt32(&counts[i]); msgs < low || msgs > high { t.Fatalf("Messages received for worker [%d] too far off from target of %d, got %d", i, target, msgs) } } } func TestNoRaceJetStreamClusterLargeStreamInlineCatchup(t *testing.T) { c := createJetStreamClusterExplicit(t, "LSS", 3) defer c.shutdown() // Client based API s := c.randomServer() nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo"}, Replicas: 3, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } sr := c.randomNonStreamLeader("$G", "TEST") sr.Shutdown() // In case sr was meta leader. c.waitOnLeader() msg, toSend := []byte("Hello JS Clustering"), 5000 // Now fill up stream. for i := 0; i < toSend; i++ { if _, err = js.Publish("foo", msg); err != nil { t.Fatalf("Unexpected publish error: %v", err) } } si, err := js.StreamInfo("TEST") if err != nil { t.Fatalf("Unexpected error: %v", err) } // Check active state as well, shows that the owner answered. if si.State.Msgs != uint64(toSend) { t.Fatalf("Expected %d msgs, got bad state: %+v", toSend, si.State) } // Kill our current leader to make just 2. c.streamLeader("$G", "TEST").Shutdown() // Now restart the shutdown peer and wait for it to be current. sr = c.restartServer(sr) c.waitOnStreamCurrent(sr, "$G", "TEST") // Ask other servers to stepdown as leader so that sr becomes the leader. checkFor(t, 20*time.Second, 200*time.Millisecond, func() error { c.waitOnStreamLeader("$G", "TEST") if sl := c.streamLeader("$G", "TEST"); sl != sr { sl.JetStreamStepdownStream("$G", "TEST") return fmt.Errorf("Server %s is not leader yet", sr) } return nil }) si, err = js.StreamInfo("TEST") if err != nil { t.Fatalf("Unexpected error: %v", err) } // Check that we have all of our messsages stored. // Wait for a bit for upper layers to process. checkFor(t, 2*time.Second, 100*time.Millisecond, func() error { if si.State.Msgs != uint64(toSend) { return fmt.Errorf("Expected %d msgs, got %d", toSend, si.State.Msgs) } return nil }) } func TestNoRaceJetStreamClusterStreamCreateAndLostQuorum(t *testing.T) { c := createJetStreamClusterExplicit(t, "R5S", 3) defer c.shutdown() // Client based API s := c.randomServer() nc, js := jsClientConnect(t, s) defer nc.Close() sub, err := nc.SubscribeSync(JSAdvisoryStreamQuorumLostPre + ".*") if err != nil { t.Fatalf("Unexpected error: %v", err) } if _, err := js.AddStream(&nats.StreamConfig{Name: "NO-LQ-START", Replicas: 3}); err != nil { t.Fatalf("Unexpected error: %v", err) } c.waitOnStreamLeader("$G", "NO-LQ-START") checkSubsPending(t, sub, 0) c.stopAll() // Start up the one we were connected to first and wait for it to be connected. s = c.restartServer(s) nc, err = nats.Connect(s.ClientURL()) if err != nil { t.Fatalf("Failed to create client: %v", err) } defer nc.Close() sub, err = nc.SubscribeSync(JSAdvisoryStreamQuorumLostPre + ".*") if err != nil { t.Fatalf("Unexpected error: %v", err) } nc.Flush() c.restartAll() c.waitOnStreamLeader("$G", "NO-LQ-START") checkSubsPending(t, sub, 0) } func TestNoRaceJetStreamSuperClusterMirrors(t *testing.T) { sc := createJetStreamSuperCluster(t, 3, 3) defer sc.shutdown() // Client based API s := sc.clusterForName("C2").randomServer() nc, js := jsClientConnect(t, s) defer nc.Close() // Create source stream. _, err := js.AddStream(&nats.StreamConfig{Name: "S1", Subjects: []string{"foo", "bar"}, Replicas: 3, Placement: &nats.Placement{Cluster: "C2"}}) if err != nil { t.Fatalf("Unexpected error: %v", err) } // Needed while Go client does not have mirror support. createStream := func(cfg *nats.StreamConfig) { t.Helper() if _, err := js.AddStream(cfg); err != nil { t.Fatalf("Unexpected error: %+v", err) } } // Send 100 messages. for i := 0; i < 100; i++ { if _, err := js.Publish("foo", []byte("MIRRORS!")); err != nil { t.Fatalf("Unexpected publish error: %v", err) } } createStream(&nats.StreamConfig{ Name: "M1", Mirror: &nats.StreamSource{Name: "S1"}, Placement: &nats.Placement{Cluster: "C1"}, }) checkFor(t, 2*time.Second, 100*time.Millisecond, func() error { si, err := js.StreamInfo("M1") if err != nil { t.Fatalf("Unexpected error: %v", err) } if si.State.Msgs != 100 { return fmt.Errorf("Expected 100 msgs, got state: %+v", si.State) } return nil }) // Purge the source stream. if err := js.PurgeStream("S1"); err != nil { t.Fatalf("Unexpected purge error: %v", err) } // Send 50 more msgs now. for i := 0; i < 50; i++ { if _, err := js.Publish("bar", []byte("OK")); err != nil { t.Fatalf("Unexpected publish error: %v", err) } } createStream(&nats.StreamConfig{ Name: "M2", Mirror: &nats.StreamSource{Name: "S1"}, Replicas: 3, Placement: &nats.Placement{Cluster: "C3"}, }) checkFor(t, 10*time.Second, 100*time.Millisecond, func() error { si, err := js.StreamInfo("M2") if err != nil { t.Fatalf("Unexpected error: %v", err) } if si.State.Msgs != 50 { return fmt.Errorf("Expected 50 msgs, got state: %+v", si.State) } if si.State.FirstSeq != 101 { return fmt.Errorf("Expected start seq of 101, got state: %+v", si.State) } return nil }) sl := sc.clusterForName("C3").streamLeader("$G", "M2") doneCh := make(chan bool) // Now test that if the mirror get's interrupted that it picks up where it left off etc. go func() { // Send 100 more messages. for i := 0; i < 100; i++ { if _, err := js.Publish("foo", []byte("MIRRORS!")); err != nil { t.Errorf("Unexpected publish on %d error: %v", i, err) } time.Sleep(2 * time.Millisecond) } doneCh <- true }() time.Sleep(20 * time.Millisecond) sl.Shutdown() <-doneCh sc.clusterForName("C3").waitOnStreamLeader("$G", "M2") checkFor(t, 10*time.Second, 100*time.Millisecond, func() error { si, err := js.StreamInfo("M2") if err != nil { t.Fatalf("Unexpected error: %v", err) } if si.State.Msgs != 150 { return fmt.Errorf("Expected 150 msgs, got state: %+v", si.State) } if si.State.FirstSeq != 101 { return fmt.Errorf("Expected start seq of 101, got state: %+v", si.State) } return nil }) } func TestNoRaceJetStreamSuperClusterMixedModeMirrors(t *testing.T) { // Unlike the similar sources test, this test is not reliably catching the bug // that would cause mirrors to not have the expected messages count. // Still, adding this test in case we have a regression and we are lucky in // getting the failure while running this. tmpl := ` listen: 127.0.0.1:-1 server_name: %s jetstream: { domain: ngs, max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} leaf: { listen: 127.0.0.1:-1 } cluster { name: %s listen: 127.0.0.1:%d routes = [%s] } accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } ` sc := createJetStreamSuperClusterWithTemplateAndModHook(t, tmpl, 7, 4, func(serverName, clusterName, storeDir, conf string) string { sname := serverName[strings.Index(serverName, "-")+1:] switch sname { case "S5", "S6", "S7": conf = strings.ReplaceAll(conf, "jetstream: { ", "#jetstream: { ") default: conf = strings.ReplaceAll(conf, "leaf: { ", "#leaf: { ") } return conf }, nil) defer sc.shutdown() // Connect our client to a non JS server c := sc.randomCluster() var s *Server for s == nil { if as := c.randomServer(); !as.JetStreamEnabled() { s = as break } } nc, js := jsClientConnect(t, s) defer nc.Close() toSend := 1000 // Create 10 origin streams for i := 0; i < 10; i++ { name := fmt.Sprintf("S%d", i+1) if _, err := js.AddStream(&nats.StreamConfig{Name: name}); err != nil { t.Fatalf("Unexpected error: %v", err) } c.waitOnStreamLeader(globalAccountName, name) // Load them up with a bunch of messages. for n := 0; n < toSend; n++ { m := nats.NewMsg(name) m.Header.Set("stream", name) m.Header.Set("idx", strconv.FormatInt(int64(n+1), 10)) if err := nc.PublishMsg(m); err != nil { t.Fatalf("Unexpected publish error: %v", err) } } } for i := 0; i < 3; i++ { // Now create our mirrors wg := sync.WaitGroup{} mirrorsCount := 10 wg.Add(mirrorsCount) errCh := make(chan error, 1) for m := 0; m < mirrorsCount; m++ { sname := fmt.Sprintf("S%d", rand.Intn(10)+1) go func(sname string, mirrorIdx int) { defer wg.Done() if _, err := js.AddStream(&nats.StreamConfig{ Name: fmt.Sprintf("M%d", mirrorIdx), Mirror: &nats.StreamSource{Name: sname}, Replicas: 3, }); err != nil { select { case errCh <- err: default: } } }(sname, m+1) } wg.Wait() select { case err := <-errCh: t.Fatalf("Error creating mirrors: %v", err) default: } // Now check the mirrors have all expected messages for m := 0; m < mirrorsCount; m++ { name := fmt.Sprintf("M%d", m+1) checkFor(t, 15*time.Second, 500*time.Millisecond, func() error { si, err := js.StreamInfo(name) if err != nil { t.Fatalf("Could not retrieve stream info") } if si.State.Msgs != uint64(toSend) { return fmt.Errorf("Expected %d msgs, got state: %+v", toSend, si.State) } return nil }) err := js.DeleteStream(name) require_NoError(t, err) } } } func TestNoRaceJetStreamSuperClusterSources(t *testing.T) { sc := createJetStreamSuperCluster(t, 3, 3) defer sc.shutdown() // Client based API s := sc.clusterForName("C1").randomServer() nc, js := jsClientConnect(t, s) defer nc.Close() // Create our source streams. for _, sname := range []string{"foo", "bar", "baz"} { if _, err := js.AddStream(&nats.StreamConfig{Name: sname, Replicas: 1}); err != nil { t.Fatalf("Unexpected error: %v", err) } } sendBatch := func(subject string, n int) { for i := 0; i < n; i++ { msg := fmt.Sprintf("MSG-%d", i+1) if _, err := js.Publish(subject, []byte(msg)); err != nil { t.Fatalf("Unexpected publish error: %v", err) } } } // Populate each one. sendBatch("foo", 10) sendBatch("bar", 15) sendBatch("baz", 25) // Needed while Go client does not have mirror support for creating mirror or source streams. createStream := func(cfg *nats.StreamConfig) { t.Helper() if _, err := js.AddStream(cfg); err != nil { t.Fatalf("Unexpected error: %+v", err) } } cfg := &nats.StreamConfig{ Name: "MS", Sources: []*nats.StreamSource{ {Name: "foo"}, {Name: "bar"}, {Name: "baz"}, }, } createStream(cfg) time.Sleep(time.Second) // Faster timeout since we loop below checking for condition. js2, err := nc.JetStream(nats.MaxWait(50 * time.Millisecond)) if err != nil { t.Fatalf("Unexpected error: %v", err) } checkFor(t, 10*time.Second, 100*time.Millisecond, func() error { si, err := js2.StreamInfo("MS") if err != nil { return err } if si.State.Msgs != 50 { return fmt.Errorf("Expected 50 msgs, got state: %+v", si.State) } return nil }) // Purge the source streams. for _, sname := range []string{"foo", "bar", "baz"} { if err := js.PurgeStream(sname); err != nil { t.Fatalf("Unexpected purge error: %v", err) } } if err := js.DeleteStream("MS"); err != nil { t.Fatalf("Unexpected delete error: %v", err) } // Send more msgs now. sendBatch("foo", 10) sendBatch("bar", 15) sendBatch("baz", 25) cfg = &nats.StreamConfig{ Name: "MS2", Sources: []*nats.StreamSource{ {Name: "foo"}, {Name: "bar"}, {Name: "baz"}, }, Replicas: 3, Placement: &nats.Placement{Cluster: "C3"}, } createStream(cfg) checkFor(t, 5*time.Second, 100*time.Millisecond, func() error { si, err := js2.StreamInfo("MS2") if err != nil { t.Fatalf("Unexpected error: %v", err) } if si.State.Msgs != 50 { return fmt.Errorf("Expected 50 msgs, got state: %+v", si.State) } if si.State.FirstSeq != 1 { return fmt.Errorf("Expected start seq of 1, got state: %+v", si.State) } return nil }) sl := sc.clusterForName("C3").streamLeader("$G", "MS2") doneCh := make(chan bool) if sl == sc.leader() { nc.Request(JSApiLeaderStepDown, nil, time.Second) sc.waitOnLeader() } // Now test that if the mirror get's interrupted that it picks up where it left off etc. go func() { // Send 50 more messages each. for i := 0; i < 50; i++ { msg := fmt.Sprintf("R-MSG-%d", i+1) for _, sname := range []string{"foo", "bar", "baz"} { m := nats.NewMsg(sname) m.Data = []byte(msg) if _, err := js.PublishMsg(m); err != nil { t.Errorf("Unexpected publish error: %v", err) } } time.Sleep(2 * time.Millisecond) } doneCh <- true }() time.Sleep(20 * time.Millisecond) sl.Shutdown() sc.clusterForName("C3").waitOnStreamLeader("$G", "MS2") <-doneCh checkFor(t, 15*time.Second, time.Second, func() error { si, err := js2.StreamInfo("MS2") if err != nil { return err } if si.State.Msgs != 200 { return fmt.Errorf("Expected 200 msgs, got state: %+v", si.State) } return nil }) } func TestNoRaceJetStreamClusterSourcesMuxd(t *testing.T) { c := createJetStreamClusterExplicit(t, "SMUX", 3) defer c.shutdown() // Client for API requests. nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() // Send in 10000 messages. msg, toSend := make([]byte, 1024), 10000 crand.Read(msg) var sources []*nats.StreamSource // Create 10 origin streams. for i := 1; i <= 10; i++ { name := fmt.Sprintf("O-%d", i) if _, err := js.AddStream(&nats.StreamConfig{Name: name}); err != nil { t.Fatalf("Unexpected error: %v", err) } // Make sure we have a leader before publishing, especially since we use // non JS publisher, we would not know if the messages made it to those // streams or not. c.waitOnStreamLeader(globalAccountName, name) // Load them up with a bunch of messages. for n := 0; n < toSend; n++ { if err := nc.Publish(name, msg); err != nil { t.Fatalf("Unexpected publish error: %v", err) } } sources = append(sources, &nats.StreamSource{Name: name}) } // Now create our downstream stream that sources from all of them. if _, err := js.AddStream(&nats.StreamConfig{Name: "S", Replicas: 2, Sources: sources}); err != nil { t.Fatalf("Unexpected error: %v", err) } checkFor(t, 20*time.Second, 500*time.Millisecond, func() error { si, err := js.StreamInfo("S") if err != nil { t.Fatalf("Could not retrieve stream info") } if si.State.Msgs != uint64(10*toSend) { return fmt.Errorf("Expected %d msgs, got state: %+v", toSend*10, si.State) } return nil }) } func TestNoRaceJetStreamSuperClusterMixedModeSources(t *testing.T) { tmpl := ` listen: 127.0.0.1:-1 server_name: %s jetstream: { domain: ngs, max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} leaf: { listen: 127.0.0.1:-1 } cluster { name: %s listen: 127.0.0.1:%d routes = [%s] } accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } ` sc := createJetStreamSuperClusterWithTemplateAndModHook(t, tmpl, 7, 2, func(serverName, clusterName, storeDir, conf string) string { sname := serverName[strings.Index(serverName, "-")+1:] switch sname { case "S5", "S6", "S7": conf = strings.ReplaceAll(conf, "jetstream: { ", "#jetstream: { ") default: conf = strings.ReplaceAll(conf, "leaf: { ", "#leaf: { ") } return conf }, nil) defer sc.shutdown() // Connect our client to a non JS server c := sc.randomCluster() var s *Server for s == nil { if as := c.randomServer(); !as.JetStreamEnabled() { s = as break } } nc, js := jsClientConnect(t, s) defer nc.Close() toSend := 1000 var sources []*nats.StreamSource // Create 100 origin streams. for i := 1; i <= 100; i++ { name := fmt.Sprintf("O-%d", i) if _, err := js.AddStream(&nats.StreamConfig{Name: name}); err != nil { t.Fatalf("Unexpected error: %v", err) } c.waitOnStreamLeader(globalAccountName, name) // Load them up with a bunch of messages. for n := 0; n < toSend; n++ { m := nats.NewMsg(name) m.Header.Set("stream", name) m.Header.Set("idx", strconv.FormatInt(int64(n+1), 10)) if err := nc.PublishMsg(m); err != nil { t.Fatalf("Unexpected publish error: %v", err) } } sources = append(sources, &nats.StreamSource{Name: name}) } for i := 0; i < 3; i++ { // Now create our downstream stream that sources from all of them. if _, err := js.AddStream(&nats.StreamConfig{Name: "S", Replicas: 3, Sources: sources}); err != nil { t.Fatalf("Unexpected error: %v", err) } checkFor(t, 15*time.Second, 1000*time.Millisecond, func() error { si, err := js.StreamInfo("S") if err != nil { t.Fatalf("Could not retrieve stream info") } if si.State.Msgs != uint64(100*toSend) { return fmt.Errorf("Expected %d msgs, got state: %+v", toSend*100, si.State) } return nil }) err := js.DeleteStream("S") require_NoError(t, err) } } func TestNoRaceJetStreamClusterExtendedStreamPurgeStall(t *testing.T) { // Uncomment to run. Needs to be on a big machine. Do not want as part of Travis tests atm. skip(t) cerr := func(t *testing.T, err error) { t.Helper() if err != nil { t.Fatalf("unexepected err: %s", err) } } s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, js := jsClientConnect(t, s) defer nc.Close() si, err := js.AddStream(&nats.StreamConfig{ Name: "KV", Subjects: []string{"kv.>"}, Storage: nats.FileStorage, }) cerr(t, err) // 100kb messages spread over 1000 different subjects body := make([]byte, 100*1024) for i := 0; i < 50000; i++ { if _, err := js.PublishAsync(fmt.Sprintf("kv.%d", i%1000), body); err != nil { cerr(t, err) } } checkFor(t, 5*time.Second, 200*time.Millisecond, func() error { if si, err = js.StreamInfo("KV"); err != nil { return err } if si.State.Msgs == 50000 { return nil } return fmt.Errorf("waiting for more") }) jp, _ := json.Marshal(&JSApiStreamPurgeRequest{Subject: "kv.20"}) start := time.Now() res, err := nc.Request(fmt.Sprintf(JSApiStreamPurgeT, "KV"), jp, time.Minute) elapsed := time.Since(start) cerr(t, err) pres := JSApiStreamPurgeResponse{} err = json.Unmarshal(res.Data, &pres) cerr(t, err) if !pres.Success { t.Fatalf("purge failed: %#v", pres) } if elapsed > time.Second { t.Fatalf("Purge took too long %s", elapsed) } v, _ := s.Varz(nil) if v.Mem > 100*1024*1024 { // 100MB limit but in practice < 100MB -> Was ~7GB when failing. t.Fatalf("Used too much memory: %v", friendlyBytes(v.Mem)) } } func TestNoRaceJetStreamClusterMirrorExpirationAndMissingSequences(t *testing.T) { c := createJetStreamClusterExplicit(t, "MMS", 9) defer c.shutdown() // Client for API requests. nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() sendBatch := func(n int) { t.Helper() // Send a batch to a given subject. for i := 0; i < n; i++ { if _, err := js.Publish("TEST", []byte("OK")); err != nil { t.Fatalf("Unexpected publish error: %v", err) } } } checkStream := func(stream string, num uint64) { t.Helper() checkFor(t, 10*time.Second, 50*time.Millisecond, func() error { si, err := js.StreamInfo(stream) if err != nil { return err } if si.State.Msgs != num { return fmt.Errorf("Expected %d msgs, got %d", num, si.State.Msgs) } return nil }) } checkMirror := func(num uint64) { t.Helper(); checkStream("M", num) } checkTest := func(num uint64) { t.Helper(); checkStream("TEST", num) } // Origin _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", MaxAge: 100 * time.Millisecond, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } ts := c.streamLeader("$G", "TEST") ml := c.leader() // Create mirror now. for ms := ts; ms == ts || ms == ml; { _, err = js.AddStream(&nats.StreamConfig{ Name: "M", Mirror: &nats.StreamSource{Name: "TEST"}, Replicas: 2, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } ms = c.streamLeader("$G", "M") if ts == ms || ms == ml { // Delete and retry. js.DeleteStream("M") } } sendBatch(10) checkMirror(10) // Now shutdown the server with the mirror. ms := c.streamLeader("$G", "M") ms.Shutdown() c.waitOnLeader() // Send more messages but let them expire. sendBatch(10) checkTest(0) c.restartServer(ms) c.checkClusterFormed() c.waitOnStreamLeader("$G", "M") sendBatch(10) checkMirror(20) } func TestNoRaceJetStreamClusterLargeActiveOnReplica(t *testing.T) { // Uncomment to run. skip(t) c := createJetStreamClusterExplicit(t, "LAG", 3) defer c.shutdown() // Client for API requests. nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() timeout := time.Now().Add(60 * time.Second) for time.Now().Before(timeout) { si, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo", "bar"}, Replicas: 3, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } for _, r := range si.Cluster.Replicas { if r.Active > 5*time.Second { t.Fatalf("Bad Active value: %+v", r) } } if err := js.DeleteStream("TEST"); err != nil { t.Fatalf("Unexpected delete error: %v", err) } } } func TestNoRaceJetStreamSuperClusterRIPStress(t *testing.T) { // Uncomment to run. Needs to be on a big machine. skip(t) sc := createJetStreamSuperCluster(t, 3, 3) defer sc.shutdown() // Client based API s := sc.clusterForName("C2").randomServer() nc, js := jsClientConnect(t, s) defer nc.Close() scm := make(map[string][]string) // Create 50 streams per cluster. for _, cn := range []string{"C1", "C2", "C3"} { var streams []string for i := 0; i < 50; i++ { sn := fmt.Sprintf("%s-S%d", cn, i+1) streams = append(streams, sn) _, err := js.AddStream(&nats.StreamConfig{ Name: sn, Replicas: 3, Placement: &nats.Placement{Cluster: cn}, MaxAge: 2 * time.Minute, MaxMsgs: 50_000, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } } scm[cn] = streams } sourceForCluster := func(cn string) []*nats.StreamSource { var sns []string switch cn { case "C1": sns = scm["C2"] case "C2": sns = scm["C3"] case "C3": sns = scm["C1"] default: t.Fatalf("Unknown cluster %q", cn) } var ss []*nats.StreamSource for _, sn := range sns { ss = append(ss, &nats.StreamSource{Name: sn}) } return ss } // Mux all 50 streams from one cluster to a single stream across a GW connection to another cluster. _, err := js.AddStream(&nats.StreamConfig{ Name: "C1-S-MUX", Replicas: 2, Placement: &nats.Placement{Cluster: "C1"}, Sources: sourceForCluster("C2"), MaxAge: time.Minute, MaxMsgs: 20_000, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } _, err = js.AddStream(&nats.StreamConfig{ Name: "C2-S-MUX", Replicas: 2, Placement: &nats.Placement{Cluster: "C2"}, Sources: sourceForCluster("C3"), MaxAge: time.Minute, MaxMsgs: 20_000, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } _, err = js.AddStream(&nats.StreamConfig{ Name: "C3-S-MUX", Replicas: 2, Placement: &nats.Placement{Cluster: "C3"}, Sources: sourceForCluster("C1"), MaxAge: time.Minute, MaxMsgs: 20_000, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } // Now create mirrors for our mux'd streams. _, err = js.AddStream(&nats.StreamConfig{ Name: "C1-MIRROR", Replicas: 3, Placement: &nats.Placement{Cluster: "C1"}, Mirror: &nats.StreamSource{Name: "C3-S-MUX"}, MaxAge: 5 * time.Minute, MaxMsgs: 10_000, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } _, err = js.AddStream(&nats.StreamConfig{ Name: "C2-MIRROR", Replicas: 3, Placement: &nats.Placement{Cluster: "C2"}, Mirror: &nats.StreamSource{Name: "C2-S-MUX"}, MaxAge: 5 * time.Minute, MaxMsgs: 10_000, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } _, err = js.AddStream(&nats.StreamConfig{ Name: "C3-MIRROR", Replicas: 3, Placement: &nats.Placement{Cluster: "C3"}, Mirror: &nats.StreamSource{Name: "C1-S-MUX"}, MaxAge: 5 * time.Minute, MaxMsgs: 10_000, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } var jsc []nats.JetStream // Create 64 clients. for i := 0; i < 64; i++ { s := sc.randomCluster().randomServer() nc, _ := jsClientConnect(t, s) defer nc.Close() js, err := nc.JetStream(nats.PublishAsyncMaxPending(8 * 1024)) if err != nil { t.Fatalf("Unexpected error: %v", err) } jsc = append(jsc, js) } msg := make([]byte, 1024) crand.Read(msg) // 10 minutes expires := time.Now().Add(480 * time.Second) for time.Now().Before(expires) { for _, sns := range scm { rand.Shuffle(len(sns), func(i, j int) { sns[i], sns[j] = sns[j], sns[i] }) for _, sn := range sns { js := jsc[rand.Intn(len(jsc))] if _, err = js.PublishAsync(sn, msg); err != nil { t.Fatalf("Unexpected publish error: %v", err) } } } time.Sleep(10 * time.Millisecond) } } func TestNoRaceJetStreamSlowFilteredInititalPendingAndFirstMsg(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() // Create directly here to force multiple blocks, etc. a, err := s.LookupAccount("$G") if err != nil { t.Fatalf("Unexpected error: %v", err) } mset, err := a.addStreamWithStore( &StreamConfig{ Name: "S", Subjects: []string{"foo", "bar", "baz", "foo.bar.baz", "foo.*"}, }, &FileStoreConfig{ BlockSize: 4 * 1024 * 1024, AsyncFlush: true, }, ) if err != nil { t.Fatalf("Unexpected error: %v", err) } nc, js := jsClientConnect(t, s) defer nc.Close() toSend := 100_000 // 500k total though. // Messages will be 'foo' 'bar' 'baz' repeated 100k times. // Then 'foo.bar.baz' all contigous for 100k. // Then foo.N for 1-100000 for i := 0; i < toSend; i++ { js.PublishAsync("foo", []byte("HELLO")) js.PublishAsync("bar", []byte("WORLD")) js.PublishAsync("baz", []byte("AGAIN")) } // Make contiguous block of same subject. for i := 0; i < toSend; i++ { js.PublishAsync("foo.bar.baz", []byte("ALL-TOGETHER")) } // Now add some more at the end. for i := 0; i < toSend; i++ { js.PublishAsync(fmt.Sprintf("foo.%d", i+1), []byte("LATER")) } checkFor(t, 10*time.Second, 250*time.Millisecond, func() error { si, err := js.StreamInfo("S") if err != nil { return err } if si.State.Msgs != uint64(5*toSend) { return fmt.Errorf("Expected %d msgs, got %d", 5*toSend, si.State.Msgs) } return nil }) // Threshold for taking too long. const thresh = 150 * time.Millisecond var dindex int testConsumerCreate := func(subj string, startSeq, expectedNumPending uint64) { t.Helper() dindex++ dname := fmt.Sprintf("dur-%d", dindex) cfg := ConsumerConfig{FilterSubject: subj, Durable: dname, AckPolicy: AckExplicit} if startSeq > 1 { cfg.OptStartSeq, cfg.DeliverPolicy = startSeq, DeliverByStartSequence } start := time.Now() o, err := mset.addConsumer(&cfg) if err != nil { t.Fatalf("Unexpected error: %v", err) } if delta := time.Since(start); delta > thresh { t.Fatalf("Creating consumer for %q and start: %d took too long: %v", subj, startSeq, delta) } if ci := o.info(); ci.NumPending != expectedNumPending { t.Fatalf("Expected NumPending of %d, got %d", expectedNumPending, ci.NumPending) } } testConsumerCreate("foo.100000", 1, 1) testConsumerCreate("foo.100000", 222_000, 1) testConsumerCreate("foo", 1, 100_000) testConsumerCreate("foo", 4, 100_000-1) testConsumerCreate("foo.bar.baz", 1, 100_000) testConsumerCreate("foo.bar.baz", 350_001, 50_000) testConsumerCreate("*", 1, 300_000) testConsumerCreate("*", 4, 300_000-3) testConsumerCreate(">", 1, 500_000) testConsumerCreate(">", 50_000, 500_000-50_000+1) testConsumerCreate("foo.10", 1, 1) // Also test that we do not take long if the start sequence is later in the stream. sub, err := js.PullSubscribe("foo.100000", "dlc") if err != nil { t.Fatalf("Unexpected error: %v", err) } start := time.Now() fetchMsgs(t, sub, 1, time.Second) if delta := time.Since(start); delta > thresh { t.Fatalf("Took too long for pull subscriber to fetch the message: %v", delta) } // Now do some deletes and make sure these are handled correctly. // Delete 3 foo messages. mset.removeMsg(1) mset.removeMsg(4) mset.removeMsg(7) testConsumerCreate("foo", 1, 100_000-3) // Make sure wider scoped subjects do the right thing from a pending perspective. o, err := mset.addConsumer(&ConsumerConfig{FilterSubject: ">", Durable: "cat", AckPolicy: AckExplicit}) if err != nil { t.Fatalf("Unexpected error: %v", err) } ci, expected := o.info(), uint64(500_000-3) if ci.NumPending != expected { t.Fatalf("Expected NumPending of %d, got %d", expected, ci.NumPending) } // Send another and make sure its captured by our wide scope consumer. js.Publish("foo", []byte("HELLO AGAIN")) if ci = o.info(); ci.NumPending != expected+1 { t.Fatalf("Expected the consumer to recognize the wide scoped consumer, wanted pending of %d, got %d", expected+1, ci.NumPending) } // Stop current server and test restart.. sd := s.JetStreamConfig().StoreDir s.Shutdown() // Restart. s = RunJetStreamServerOnPort(-1, sd) defer s.Shutdown() a, err = s.LookupAccount("$G") if err != nil { t.Fatalf("Unexpected error: %v", err) } mset, err = a.lookupStream("S") if err != nil { t.Fatalf("Unexpected error: %v", err) } // Make sure we recovered our per subject state on restart. testConsumerCreate("foo.100000", 1, 1) testConsumerCreate("foo", 1, 100_000-2) } func TestNoRaceJetStreamFileStoreBufferReuse(t *testing.T) { // Uncomment to run. Needs to be on a big machine. skip(t) s := RunBasicJetStreamServer(t) defer s.Shutdown() cfg := &StreamConfig{Name: "TEST", Subjects: []string{"foo", "bar", "baz"}, Storage: FileStorage} if _, err := s.GlobalAccount().addStreamWithStore(cfg, nil); err != nil { t.Fatalf("Unexpected error adding stream: %v", err) } // Client for API requests. nc, js := jsClientConnect(t, s) defer nc.Close() toSend := 200_000 m := nats.NewMsg("foo") m.Data = make([]byte, 8*1024) crand.Read(m.Data) start := time.Now() for i := 0; i < toSend; i++ { m.Reply = _EMPTY_ switch i % 3 { case 0: m.Subject = "foo" case 1: m.Subject = "bar" case 2: m.Subject = "baz" } m.Header.Set("X-ID2", fmt.Sprintf("XXXXX-%d", i)) if _, err := js.PublishMsgAsync(m); err != nil { t.Fatalf("Err on publish: %v", err) } } <-js.PublishAsyncComplete() fmt.Printf("TOOK %v to publish\n", time.Since(start)) v, err := s.Varz(nil) if err != nil { t.Fatalf("Unexpected error: %v", err) } fmt.Printf("MEM AFTER PUBLISH is %v\n", friendlyBytes(v.Mem)) si, _ := js.StreamInfo("TEST") fmt.Printf("si is %+v\n", si.State) received := 0 done := make(chan bool) cb := func(m *nats.Msg) { received++ if received >= toSend { done <- true } } start = time.Now() sub, err := js.Subscribe("*", cb, nats.EnableFlowControl(), nats.IdleHeartbeat(time.Second), nats.AckNone()) if err != nil { t.Fatalf("Unexpected error: %v", err) } defer sub.Unsubscribe() <-done fmt.Printf("TOOK %v to consume\n", time.Since(start)) v, err = s.Varz(nil) if err != nil { t.Fatalf("Unexpected error: %v", err) } fmt.Printf("MEM AFTER SUBSCRIBE is %v\n", friendlyBytes(v.Mem)) } // Report of slow restart for a server that has many messages that have expired while it was not running. func TestNoRaceJetStreamSlowRestartWithManyExpiredMsgs(t *testing.T) { opts := DefaultTestOptions opts.Port = -1 opts.JetStream = true s := RunServer(&opts) if config := s.JetStreamConfig(); config != nil { defer removeDir(t, config.StoreDir) } defer s.Shutdown() // Client for API requests. nc, js := jsClientConnect(t, s) defer nc.Close() ttl := 2 * time.Second _, err := js.AddStream(&nats.StreamConfig{ Name: "ORDERS", Subjects: []string{"orders.*"}, MaxAge: ttl, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } // Attach a consumer who is filtering on a wildcard subject as well. // This does not affect it like I thought originally but will keep it here. _, err = js.AddConsumer("ORDERS", &nats.ConsumerConfig{ Durable: "c22", FilterSubject: "orders.*", AckPolicy: nats.AckExplicitPolicy, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } // Now fill up with messages. toSend := 100_000 for i := 1; i <= toSend; i++ { js.PublishAsync(fmt.Sprintf("orders.%d", i), []byte("OK")) } <-js.PublishAsyncComplete() sdir := strings.TrimSuffix(s.JetStreamConfig().StoreDir, JetStreamStoreDir) s.Shutdown() // Let them expire while not running. time.Sleep(ttl + 500*time.Millisecond) start := time.Now() opts.Port = -1 opts.StoreDir = sdir s = RunServer(&opts) elapsed := time.Since(start) defer s.Shutdown() if elapsed > 2*time.Second { t.Fatalf("Took %v for restart which is too long", elapsed) } // Check everything is correct. nc, js = jsClientConnect(t, s) defer nc.Close() si, err := js.StreamInfo("ORDERS") if err != nil { t.Fatalf("Unexpected error: %v", err) } if si.State.Msgs != 0 { t.Fatalf("Expected no msgs after restart, got %d", si.State.Msgs) } } func TestNoRaceJetStreamStalledMirrorsAfterExpire(t *testing.T) { c := createJetStreamClusterExplicit(t, "JSC", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() cfg := &nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo.*"}, Replicas: 1, MaxAge: 100 * time.Millisecond, } if _, err := js.AddStream(cfg); err != nil { t.Fatalf("Error creating stream: %v", err) } if _, err := js.AddStream(&nats.StreamConfig{ Name: "M", Replicas: 2, Mirror: &nats.StreamSource{Name: "TEST"}, }); err != nil { t.Fatalf("Unexpected error: %v", err) } sendBatch := func(batch int) { t.Helper() for i := 0; i < batch; i++ { js.PublishAsync("foo.bar", []byte("Hello")) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } } numMsgs := 10_000 sendBatch(numMsgs) // Turn off expiration so we can test we did not stall. cfg.MaxAge = 0 if _, err := js.UpdateStream(cfg); err != nil { t.Fatalf("Unexpected error: %v", err) } sendBatch(numMsgs) // Wait for mirror to be caught up. checkFor(t, 10*time.Second, 500*time.Millisecond, func() error { si, err := js.StreamInfo("M") if err != nil { t.Fatalf("Unexpected error: %v", err) } if si.State.LastSeq != uint64(2*numMsgs) { return fmt.Errorf("Expected %d as last sequence, got state: %+v", 2*numMsgs, si.State) } return nil }) } // We will use JetStream helpers to create supercluster but this test is about exposing the ability to access // account scoped connz with subject interest filtering. func TestNoRaceJetStreamSuperClusterAccountConnz(t *testing.T) { // This has 4 different account, 3 general and system. sc := createJetStreamSuperClusterWithTemplate(t, jsClusterAccountsTempl, 3, 3) defer sc.shutdown() // Create 20 connections on account one and two // Create JetStream assets for each as well to make sure by default we do not report them. num := 20 for i := 0; i < num; i++ { nc, _ := jsClientConnect(t, sc.randomServer(), nats.UserInfo("one", "p"), nats.Name("one")) defer nc.Close() if i%2 == 0 { nc.SubscribeSync("foo") } else { nc.SubscribeSync("bar") } nc, js := jsClientConnect(t, sc.randomServer(), nats.UserInfo("two", "p"), nats.Name("two")) defer nc.Close() nc.SubscribeSync("baz") nc.SubscribeSync("foo.bar.*") nc.SubscribeSync(fmt.Sprintf("id.%d", i+1)) js.AddStream(&nats.StreamConfig{Name: fmt.Sprintf("TEST:%d", i+1)}) } type czapi struct { Server *ServerInfo Data *Connz Error *ApiError } parseConnz := func(buf []byte) *Connz { t.Helper() var cz czapi if err := json.Unmarshal(buf, &cz); err != nil { t.Fatalf("Unexpected error: %v", err) } if cz.Error != nil { t.Fatalf("Unexpected error: %+v", cz.Error) } return cz.Data } doRequest := func(reqSubj, acc, filter string, expected int) { t.Helper() nc, _ := jsClientConnect(t, sc.randomServer(), nats.UserInfo(acc, "p"), nats.Name(acc)) defer nc.Close() mch := make(chan *nats.Msg, 9) sub, _ := nc.ChanSubscribe(nats.NewInbox(), mch) var req []byte if filter != _EMPTY_ { req, _ = json.Marshal(&ConnzOptions{FilterSubject: filter}) } if err := nc.PublishRequest(reqSubj, sub.Subject, req); err != nil { t.Fatalf("Unexpected error: %v", err) } // So we can igniore ourtselves. cid, _ := nc.GetClientID() sid := nc.ConnectedServerId() wt := time.NewTimer(200 * time.Millisecond) var conns []*ConnInfo LOOP: for { select { case m := <-mch: if len(m.Data) == 0 { t.Fatalf("No responders") } cr := parseConnz(m.Data) // For account scoped, NumConns and Total should be the same (sans limits and offsets). // It Total should not include other accounts since that would leak information about the system. if filter == _EMPTY_ && cr.NumConns != cr.Total { t.Fatalf("NumConns and Total should be same with account scoped connz, got %+v", cr) } for _, c := range cr.Conns { if c.Name != acc { t.Fatalf("Got wrong account: %q vs %q for %+v", acc, c.Account, c) } if !(c.Cid == cid && cr.ID == sid) { conns = append(conns, c) } } wt.Reset(200 * time.Millisecond) case <-wt.C: break LOOP } } if len(conns) != expected { t.Fatalf("Expected to see %d conns but got %d", expected, len(conns)) } } doSysRequest := func(acc string, expected int) { t.Helper() doRequest("$SYS.REQ.SERVER.PING.CONNZ", acc, _EMPTY_, expected) } doAccRequest := func(acc string, expected int) { t.Helper() doRequest("$SYS.REQ.ACCOUNT.PING.CONNZ", acc, _EMPTY_, expected) } doFiltered := func(acc, filter string, expected int) { t.Helper() doRequest("$SYS.REQ.SERVER.PING.CONNZ", acc, filter, expected) } doSysRequest("one", 20) doAccRequest("one", 20) doSysRequest("two", 20) doAccRequest("two", 20) // Now check filtering. doFiltered("one", _EMPTY_, 20) doFiltered("one", ">", 20) doFiltered("one", "bar", 10) doFiltered("two", "bar", 0) doFiltered("two", "id.1", 1) doFiltered("two", "id.*", 20) doFiltered("two", "foo.bar.*", 20) doFiltered("two", "foo.>", 20) } func TestNoRaceCompressedConnz(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, _ := jsClientConnect(t, s) defer nc.Close() doRequest := func(compress string) { t.Helper() m := nats.NewMsg("$SYS.REQ.ACCOUNT.PING.CONNZ") m.Header.Add("Accept-Encoding", compress) resp, err := nc.RequestMsg(m, time.Second) if err != nil { t.Fatalf("Unexpected error: %v", err) } buf := resp.Data // Make sure we have an encoding header. ce := resp.Header.Get("Content-Encoding") switch strings.ToLower(ce) { case "gzip": zr, err := gzip.NewReader(bytes.NewReader(buf)) if err != nil { t.Fatalf("Unexpected error: %v", err) } defer zr.Close() buf, err = io.ReadAll(zr) if err != nil && err != io.ErrUnexpectedEOF { t.Fatalf("Unexpected error: %v", err) } case "snappy", "s2": sr := s2.NewReader(bytes.NewReader(buf)) buf, err = io.ReadAll(sr) if err != nil && err != io.ErrUnexpectedEOF { t.Fatalf("Unexpected error: %v", err) } default: t.Fatalf("Unknown content-encoding of %q", ce) } var cz ServerAPIConnzResponse if err := json.Unmarshal(buf, &cz); err != nil { t.Fatalf("Unexpected error: %v", err) } if cz.Error != nil { t.Fatalf("Unexpected error: %+v", cz.Error) } } doRequest("gzip") doRequest("snappy") doRequest("s2") } func TestNoRaceJetStreamClusterExtendedStreamPurge(t *testing.T) { for _, st := range []StorageType{FileStorage, MemoryStorage} { t.Run(st.String(), func(t *testing.T) { c := createJetStreamClusterExplicit(t, "JSC", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() cfg := StreamConfig{ Name: "KV", Subjects: []string{"kv.>"}, Storage: st, Replicas: 2, MaxMsgsPer: 100, } req, err := json.Marshal(cfg) if err != nil { t.Fatalf("Unexpected error: %v", err) } // Do manually for now. nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second) c.waitOnStreamLeader("$G", "KV") si, err := js.StreamInfo("KV") if err != nil { t.Fatalf("Unexpected error: %v", err) } if si == nil || si.Config.Name != "KV" { t.Fatalf("StreamInfo is not correct %+v", si) } for i := 0; i < 1000; i++ { js.PublishAsync("kv.foo", []byte("OK")) // 1 * i js.PublishAsync("kv.bar", []byte("OK")) // 2 * i js.PublishAsync("kv.baz", []byte("OK")) // 3 * i } // First is 2700, last is 3000 for i := 0; i < 700; i++ { js.PublishAsync(fmt.Sprintf("kv.%d", i+1), []byte("OK")) } // Now first is 2700, last is 3700 select { case <-js.PublishAsyncComplete(): case <-time.After(10 * time.Second): t.Fatalf("Did not receive completion signal") } si, err = js.StreamInfo("KV") if err != nil { t.Fatalf("Unexpected error: %v", err) } if si.State.Msgs != 1000 { t.Fatalf("Expected %d msgs, got %d", 1000, si.State.Msgs) } shouldFail := func(preq *JSApiStreamPurgeRequest) { req, _ := json.Marshal(preq) resp, err := nc.Request(fmt.Sprintf(JSApiStreamPurgeT, "KV"), req, time.Second) if err != nil { t.Fatalf("Unexpected error: %v", err) } var pResp JSApiStreamPurgeResponse if err = json.Unmarshal(resp.Data, &pResp); err != nil { t.Fatalf("Unexpected error: %v", err) } if pResp.Success || pResp.Error == nil { t.Fatalf("Expected an error response but got none") } } // Sequence and Keep should be mutually exclusive. shouldFail(&JSApiStreamPurgeRequest{Sequence: 10, Keep: 10}) purge := func(preq *JSApiStreamPurgeRequest, newTotal uint64) { t.Helper() req, _ := json.Marshal(preq) resp, err := nc.Request(fmt.Sprintf(JSApiStreamPurgeT, "KV"), req, time.Second) if err != nil { t.Fatalf("Unexpected error: %v", err) } var pResp JSApiStreamPurgeResponse if err = json.Unmarshal(resp.Data, &pResp); err != nil { t.Fatalf("Unexpected error: %v", err) } if !pResp.Success || pResp.Error != nil { t.Fatalf("Got a bad response %+v", pResp) } si, err = js.StreamInfo("KV") if err != nil { t.Fatalf("Unexpected error: %v", err) } if si.State.Msgs != newTotal { t.Fatalf("Expected total after purge to be %d but got %d", newTotal, si.State.Msgs) } } expectLeft := func(subject string, expected uint64) { t.Helper() ci, err := js.AddConsumer("KV", &nats.ConsumerConfig{Durable: "dlc", FilterSubject: subject, AckPolicy: nats.AckExplicitPolicy}) if err != nil { t.Fatalf("Unexpected error: %v", err) } defer js.DeleteConsumer("KV", "dlc") if ci.NumPending != expected { t.Fatalf("Expected %d remaining but got %d", expected, ci.NumPending) } } purge(&JSApiStreamPurgeRequest{Subject: "kv.foo"}, 900) expectLeft("kv.foo", 0) purge(&JSApiStreamPurgeRequest{Subject: "kv.bar", Keep: 1}, 801) expectLeft("kv.bar", 1) purge(&JSApiStreamPurgeRequest{Subject: "kv.baz", Sequence: 2851}, 751) expectLeft("kv.baz", 50) purge(&JSApiStreamPurgeRequest{Subject: "kv.*"}, 0) // RESET js.DeleteStream("KV") // Do manually for now. nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second) c.waitOnStreamLeader("$G", "KV") if _, err := js.StreamInfo("KV"); err != nil { t.Fatalf("Unexpected error: %v", err) } // Put in 100. for i := 0; i < 100; i++ { js.PublishAsync("kv.foo", []byte("OK")) } select { case <-js.PublishAsyncComplete(): case <-time.After(time.Second): t.Fatalf("Did not receive completion signal") } purge(&JSApiStreamPurgeRequest{Subject: "kv.foo", Keep: 10}, 10) purge(&JSApiStreamPurgeRequest{Subject: "kv.foo", Keep: 10}, 10) expectLeft("kv.foo", 10) // RESET AGAIN js.DeleteStream("KV") // Do manually for now. nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second) c.waitOnStreamLeader("$G", "KV") if _, err := js.StreamInfo("KV"); err != nil { t.Fatalf("Unexpected error: %v", err) } // Put in 100. for i := 0; i < 100; i++ { js.Publish("kv.foo", []byte("OK")) } purge(&JSApiStreamPurgeRequest{Keep: 10}, 10) expectLeft(">", 10) // RESET AGAIN js.DeleteStream("KV") // Do manually for now. nc.Request(fmt.Sprintf(JSApiStreamCreateT, cfg.Name), req, time.Second) if _, err := js.StreamInfo("KV"); err != nil { t.Fatalf("Unexpected error: %v", err) } // Put in 100. for i := 0; i < 100; i++ { js.Publish("kv.foo", []byte("OK")) } purge(&JSApiStreamPurgeRequest{Sequence: 90}, 11) // Up to 90 so we keep that, hence the 11. expectLeft(">", 11) }) } } func TestNoRaceJetStreamFileStoreCompaction(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, js := jsClientConnect(t, s) defer nc.Close() cfg := &nats.StreamConfig{ Name: "KV", Subjects: []string{"KV.>"}, MaxMsgsPerSubject: 1, } if _, err := js.AddStream(cfg); err != nil { t.Fatalf("Unexpected error: %v", err) } toSend := 10_000 data := make([]byte, 4*1024) crand.Read(data) // First one. js.PublishAsync("KV.FM", data) for i := 0; i < toSend; i++ { js.PublishAsync(fmt.Sprintf("KV.%d", i+1), data) } // Do again and overwrite the previous batch. for i := 0; i < toSend; i++ { js.PublishAsync(fmt.Sprintf("KV.%d", i+1), data) } select { case <-js.PublishAsyncComplete(): case <-time.After(10 * time.Second): t.Fatalf("Did not receive completion signal") } // Now check by hand the utilization level. mset, err := s.GlobalAccount().lookupStream("KV") if err != nil { t.Fatalf("Unexpected error: %v", err) } total, used, _ := mset.Store().Utilization() if pu := 100.0 * float32(used) / float32(total); pu < 80.0 { t.Fatalf("Utilization is less than 80%%, got %.2f", pu) } } func TestNoRaceJetStreamEncryptionEnabledOnRestartWithExpire(t *testing.T) { conf := createConfFile(t, []byte(fmt.Sprintf(` listen: 127.0.0.1:-1 jetstream { store_dir = %q } `, t.TempDir()))) s, _ := RunServerWithConfig(conf) defer s.Shutdown() config := s.JetStreamConfig() if config == nil { t.Fatalf("Expected config but got none") } defer removeDir(t, config.StoreDir) nc, js := jsClientConnect(t, s) defer nc.Close() toSend := 10_000 cfg := &nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo", "bar"}, MaxMsgs: int64(toSend), } if _, err := js.AddStream(cfg); err != nil { t.Fatalf("Unexpected error: %v", err) } data := make([]byte, 4*1024) // 4K payload crand.Read(data) for i := 0; i < toSend; i++ { js.PublishAsync("foo", data) js.PublishAsync("bar", data) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } _, err := js.AddConsumer("TEST", &nats.ConsumerConfig{Durable: "dlc", AckPolicy: nats.AckExplicitPolicy}) if err != nil { t.Fatalf("Unexpected error: %v", err) } // Restart nc.Close() s.Shutdown() ncs := fmt.Sprintf("\nlisten: 127.0.0.1:-1\njetstream: {key: %q, store_dir: %q}\n", "s3cr3t!", config.StoreDir) conf = createConfFile(t, []byte(ncs)) // Try to drain entropy to see if effects startup time. drain := make([]byte, 32*1024*1024) // Pull 32Mb of crypto rand. crand.Read(drain) start := time.Now() s, _ = RunServerWithConfig(conf) defer s.Shutdown() dd := time.Since(start) if dd > 5*time.Second { t.Fatalf("Restart took longer than expected: %v", dd) } } // This test was from Ivan K. and showed a bug in the filestore implementation. // This is skipped by default since it takes >40s to run. func TestNoRaceJetStreamOrderedConsumerMissingMsg(t *testing.T) { // Uncomment to run. Needs to be on a big machine. Do not want as part of Travis tests atm. skip(t) s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, js := jsClientConnect(t, s) defer nc.Close() if _, err := js.AddStream(&nats.StreamConfig{ Name: "benchstream", Subjects: []string{"testsubject"}, Replicas: 1, }); err != nil { t.Fatalf("add stream failed: %s", err) } total := 1_000_000 numSubs := 10 ch := make(chan struct{}, numSubs) wg := sync.WaitGroup{} wg.Add(numSubs) errCh := make(chan error, 1) for i := 0; i < numSubs; i++ { nc, js := jsClientConnect(t, s) defer nc.Close() go func(nc *nats.Conn, js nats.JetStreamContext) { defer wg.Done() received := 0 _, err := js.Subscribe("testsubject", func(m *nats.Msg) { meta, _ := m.Metadata() if meta.Sequence.Consumer != meta.Sequence.Stream { nc.Close() errCh <- fmt.Errorf("Bad meta: %+v", meta) } received++ if received == total { ch <- struct{}{} } }, nats.OrderedConsumer()) if err != nil { select { case errCh <- fmt.Errorf("Error creating sub: %v", err): default: } } }(nc, js) } wg.Wait() select { case e := <-errCh: t.Fatal(e) default: } payload := make([]byte, 500) for i := 1; i <= total; i++ { js.PublishAsync("testsubject", payload) } select { case <-js.PublishAsyncComplete(): case <-time.After(10 * time.Second): t.Fatalf("Did not send all messages") } // Now wait for consumers to be done: for i := 0; i < numSubs; i++ { select { case <-ch: case <-time.After(10 * time.Second): t.Fatal("Did not receive all messages for all consumers in time") } } } // Issue #2488 - Bad accounting, can not reproduce the stalled consumers after last several PRs. // Issue did show bug in ack logic for no-ack and interest based retention. func TestNoRaceJetStreamClusterInterestPolicyAckNone(t *testing.T) { for _, test := range []struct { name string durable string }{ {"durable", "dlc"}, {"ephemeral", _EMPTY_}, } { t.Run(test.name, func(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() // Client based API nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "cluster", Subjects: []string{"cluster.*"}, Retention: nats.InterestPolicy, Discard: nats.DiscardOld, Replicas: 3, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } var received uint32 mh := func(m *nats.Msg) { atomic.AddUint32(&received, 1) } opts := []nats.SubOpt{nats.DeliverNew(), nats.AckNone()} if test.durable != _EMPTY_ { opts = append(opts, nats.Durable(test.durable)) } _, err = js.Subscribe("cluster.created", mh, opts...) if err != nil { t.Fatalf("Unexepected error: %v", err) } msg := []byte("ACK ME") const total = uint32(1_000) for i := 0; i < int(total); i++ { if _, err := js.Publish("cluster.created", msg); err != nil { t.Fatalf("Unexpected error: %v", err) } //time.Sleep(100 * time.Microsecond) } // Wait for all messages to be received. checkFor(t, 2*time.Second, 100*time.Millisecond, func() error { r := atomic.LoadUint32(&received) if r == total { return nil } return fmt.Errorf("Received only %d out of %d", r, total) }) checkFor(t, 5*time.Second, 100*time.Millisecond, func() error { si, err := js.StreamInfo("cluster") if err != nil { t.Fatalf("Error getting stream info: %v", err) } if si.State.Msgs != 0 { return fmt.Errorf("Expected no messages, got %d", si.State.Msgs) } return nil }) }) } } // There was a bug in the filestore compact code that would cause a store // with JSExpectedLastSubjSeq to fail with "wrong last sequence: 0" func TestNoRaceJetStreamLastSubjSeqAndFilestoreCompact(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() // Client based API nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "MQTT_sess", Subjects: []string{"MQTT.sess.>"}, Storage: nats.FileStorage, Retention: nats.LimitsPolicy, Replicas: 1, MaxMsgsPerSubject: 1, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } firstPayload := make([]byte, 40) secondPayload := make([]byte, 380) for iter := 0; iter < 2; iter++ { for i := 0; i < 4000; i++ { subj := "MQTT.sess." + getHash(fmt.Sprintf("client_%d", i)) pa, err := js.Publish(subj, firstPayload) if err != nil { t.Fatalf("Error on publish: %v", err) } m := nats.NewMsg(subj) m.Data = secondPayload eseq := strconv.FormatInt(int64(pa.Sequence), 10) m.Header.Set(JSExpectedLastSubjSeq, eseq) if _, err := js.PublishMsg(m); err != nil { t.Fatalf("Error on publish (iter=%v seq=%v): %v", iter+1, pa.Sequence, err) } } } } // Issue #2548 func TestNoRaceJetStreamClusterMemoryStreamConsumerRaftGrowth(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "memory-leak", Subjects: []string{"memory-leak"}, Retention: nats.LimitsPolicy, MaxMsgs: 1000, Discard: nats.DiscardOld, MaxAge: time.Minute, Storage: nats.MemoryStorage, Replicas: 3, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } _, err = js.QueueSubscribe("memory-leak", "q1", func(msg *nats.Msg) { time.Sleep(1 * time.Second) msg.AckSync() }) if err != nil { t.Fatalf("Unexpected error: %v", err) } // Send 10k (Must be > 8192 which is compactNumMin from monitorConsumer. msg := []byte("NATS is a connective technology that powers modern distributed systems.") for i := 0; i < 10_000; i++ { if _, err := js.Publish("memory-leak", msg); err != nil { t.Fatalf("Unexpected error: %v", err) } } // We will verify here that the underlying raft layer for the leader is not > 8192 cl := c.consumerLeader("$G", "memory-leak", "q1") mset, err := cl.GlobalAccount().lookupStream("memory-leak") if err != nil { t.Fatalf("Unexpected error: %v", err) } o := mset.lookupConsumer("q1") if o == nil { t.Fatalf("Error looking up consumer %q", "q1") } node := o.raftNode().(*raft) checkFor(t, 10*time.Second, 100*time.Millisecond, func() error { if ms := node.wal.(*memStore); ms.State().Msgs > 8192 { return fmt.Errorf("Did not compact the raft memory WAL") } return nil }) } func TestNoRaceJetStreamClusterCorruptWAL(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() if _, err := js.AddStream(&nats.StreamConfig{Name: "TEST", Subjects: []string{"foo"}, Replicas: 3}); err != nil { t.Fatalf("Unexpected error: %v", err) } sub, err := js.PullSubscribe("foo", "dlc") if err != nil { t.Fatalf("Unexpected error: %v", err) } numMsgs := 1000 for i := 0; i < numMsgs; i++ { js.PublishAsync("foo", []byte("WAL")) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } for i, m := range fetchMsgs(t, sub, 200, 5*time.Second) { // Ack first 50 and every other even on after that.. if i < 50 || i%2 == 1 { m.AckSync() } } // Make sure acks processed. time.Sleep(200 * time.Millisecond) nc.Close() // Check consumer consistency. checkConsumerWith := func(delivered, ackFloor uint64, ackPending int) { t.Helper() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() checkFor(t, 5*time.Second, 100*time.Millisecond, func() error { ci, err := js.ConsumerInfo("TEST", "dlc") if err != nil { return fmt.Errorf("Unexpected error: %v", err) } if ci.Delivered.Consumer != ci.Delivered.Stream || ci.Delivered.Consumer != delivered { return fmt.Errorf("Expected %d for delivered, got %+v", delivered, ci.Delivered) } if ci.AckFloor.Consumer != ci.AckFloor.Stream || ci.AckFloor.Consumer != ackFloor { return fmt.Errorf("Expected %d for ack floor, got %+v", ackFloor, ci.AckFloor) } nm := uint64(numMsgs) if ci.NumPending != nm-delivered { return fmt.Errorf("Expected num pending to be %d, got %d", nm-delivered, ci.NumPending) } if ci.NumAckPending != ackPending { return fmt.Errorf("Expected num ack pending to be %d, got %d", ackPending, ci.NumAckPending) } return nil }) } checkConsumer := func() { t.Helper() checkConsumerWith(200, 50, 75) } checkConsumer() // Grab the consumer leader. cl := c.consumerLeader("$G", "TEST", "dlc") mset, err := cl.GlobalAccount().lookupStream("TEST") if err != nil { t.Fatalf("Unexpected error: %v", err) } o := mset.lookupConsumer("dlc") if o == nil { t.Fatalf("Error looking up consumer %q", "dlc") } // Grab underlying raft node and the WAL (filestore) and we will attempt to "corrupt" it. node := o.raftNode().(*raft) // We are doing a stop here to prevent the internal consumer snapshot from happening on exit node.Stop() fs := node.wal.(*fileStore) fcfg, cfg := fs.fcfg, fs.cfg.StreamConfig // Stop all the servers. c.stopAll() // Manipulate directly with cluster down. fs, err = newFileStore(fcfg, cfg) if err != nil { t.Fatalf("Unexpected error: %v", err) } state := fs.State() sm, err := fs.LoadMsg(state.LastSeq, nil) if err != nil { t.Fatalf("Unexpected error: %v", err) } ae, err := node.decodeAppendEntry(sm.msg, nil, _EMPTY_) if err != nil { t.Fatalf("Unexpected error: %v", err) } dentry := func(dseq, sseq, dc uint64, ts int64) []byte { b := make([]byte, 4*binary.MaxVarintLen64+1) b[0] = byte(updateDeliveredOp) n := 1 n += binary.PutUvarint(b[n:], dseq) n += binary.PutUvarint(b[n:], sseq) n += binary.PutUvarint(b[n:], dc) n += binary.PutVarint(b[n:], ts) return b[:n] } // Let's put a non-contigous AppendEntry into the system. ae.pindex += 10 // Add in delivered record. ae.entries = []*Entry{{EntryNormal, dentry(1000, 1000, 1, time.Now().UnixNano())}} encoded, err := ae.encode(nil) if err != nil { t.Fatalf("Unexpected error: %v", err) } if _, _, err := fs.StoreMsg(_EMPTY_, nil, encoded); err != nil { t.Fatalf("Unexpected error: %v", err) } fs.Stop() c.restartAllSamePorts() c.waitOnStreamLeader("$G", "TEST") c.waitOnConsumerLeader("$G", "TEST", "dlc") checkConsumer() // Now we will truncate out the WAL out from underneath the leader. // Grab the consumer leader. nc, js = jsClientConnect(t, c.randomServer()) defer nc.Close() cl = c.consumerLeader("$G", "TEST", "dlc") mset, err = cl.GlobalAccount().lookupStream("TEST") require_NoError(t, err) o = mset.lookupConsumer("dlc") require_NoError(t, err) // Grab underlying raft node and the WAL (filestore) and truncate it. // This will simulate the WAL losing state due to truncate and we want to make sure it recovers. fs = o.raftNode().(*raft).wal.(*fileStore) state = fs.State() err = fs.Truncate(state.FirstSeq) require_True(t, err == nil || err == ErrInvalidSequence) state = fs.State() sub, err = js.PullSubscribe("foo", "dlc") require_NoError(t, err) // This will cause us to stepdown and truncate our WAL. sub.Fetch(100) c.waitOnConsumerLeader("$G", "TEST", "dlc") // We can't trust the results sans that we have a leader back in place and the ackFloor. ci, err := js.ConsumerInfo("TEST", "dlc") require_NoError(t, err) if ci.AckFloor.Consumer != ci.AckFloor.Stream || ci.AckFloor.Consumer != 50 { t.Fatalf("Expected %d for ack floor, got %+v", 50, ci.AckFloor) } } func TestNoRaceJetStreamClusterInterestRetentionDeadlock(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() // Client based API s := c.randomServer() nc, js := jsClientConnect(t, s) defer nc.Close() // This can trigger deadlock with current architecture. // If stream is !limitsRetention and consumer is DIRECT and ack none we will try to place the msg seq // onto a chan for the stream to consider removing. All conditions above must hold to trigger. // We will attempt to trigger here with a stream mirror setup which uses and R=1 DIRECT consumer to replicate msgs. _, err := js.AddStream(&nats.StreamConfig{Name: "S", Retention: nats.InterestPolicy, Storage: nats.MemoryStorage}) if err != nil { t.Fatalf("Unexpected error: %v", err) } // Create a mirror which will create the consumer profile to trigger. _, err = js.AddStream(&nats.StreamConfig{Name: "M", Mirror: &nats.StreamSource{Name: "S"}}) if err != nil { t.Fatalf("Unexpected error: %v", err) } // Queue up alot of messages. numRequests := 20_000 for i := 0; i < numRequests; i++ { js.PublishAsync("S", []byte("Q")) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } checkFor(t, 5*time.Second, 100*time.Millisecond, func() error { si, err := js.StreamInfo("S") if err != nil { t.Fatalf("Unexpected error: %v", err) } if si.State.Msgs != 0 { return fmt.Errorf("Expected 0 msgs, got state: %+v", si.State) } return nil }) } func TestNoRaceJetStreamClusterMaxConsumersAndDirect(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() // Client based API s := c.randomServer() nc, js := jsClientConnect(t, s) defer nc.Close() // We want to max sure max consumer limits do not affect mirrors or sources etc. _, err := js.AddStream(&nats.StreamConfig{Name: "S", Storage: nats.MemoryStorage, MaxConsumers: 1}) if err != nil { t.Fatalf("Unexpected error: %v", err) } var mirrors []string for i := 0; i < 10; i++ { // Create a mirror. mname := fmt.Sprintf("M-%d", i+1) mirrors = append(mirrors, mname) _, err = js.AddStream(&nats.StreamConfig{Name: mname, Mirror: &nats.StreamSource{Name: "S"}}) if err != nil { t.Fatalf("Unexpected error: %v", err) } } // Queue up messages. numRequests := 20 for i := 0; i < numRequests; i++ { js.Publish("S", []byte("Q")) } checkFor(t, 5*time.Second, 100*time.Millisecond, func() error { for _, mname := range mirrors { si, err := js.StreamInfo(mname) if err != nil { t.Fatalf("Unexpected error: %v", err) } if si.State.Msgs != uint64(numRequests) { return fmt.Errorf("Expected %d msgs for %q, got state: %+v", numRequests, mname, si.State) } } return nil }) } // Make sure when we try to hard reset a stream state in a cluster that we also re-create the consumers. func TestNoRaceJetStreamClusterStreamReset(t *testing.T) { // Speed up raft omin, omax, ohb := minElectionTimeout, maxElectionTimeout, hbInterval minElectionTimeout = 250 * time.Millisecond maxElectionTimeout = time.Second hbInterval = 50 * time.Millisecond defer func() { minElectionTimeout = omin maxElectionTimeout = omax hbInterval = ohb }() c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() // Client based API s := c.randomServer() nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo.*"}, Replicas: 2, Retention: nats.WorkQueuePolicy, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } numRequests := 20 for i := 0; i < numRequests; i++ { js.Publish("foo.created", []byte("REQ")) } // Durable. sub, err := js.SubscribeSync("foo.created", nats.Durable("d1")) if err != nil { t.Fatalf("Unexpected error: %v", err) } defer sub.Unsubscribe() si, err := js.StreamInfo("TEST") require_NoError(t, err) require_True(t, si.State.Msgs == uint64(numRequests)) // Let settle a bit for Go routine checks. time.Sleep(500 * time.Millisecond) // Grab number go routines. base := runtime.NumGoroutine() // Make the consumer busy here by async sending a bunch of messages. for i := 0; i < numRequests*10; i++ { js.PublishAsync("foo.created", []byte("REQ")) } // Grab a server that is the consumer leader for the durable. cl := c.consumerLeader("$G", "TEST", "d1") mset, err := cl.GlobalAccount().lookupStream("TEST") if err != nil { t.Fatalf("Unexpected error: %v", err) } // Do a hard reset here by hand. mset.resetClusteredState(nil) // Wait til we have the consumer leader re-elected. c.waitOnConsumerLeader("$G", "TEST", "d1") // Make sure we can get the consumer info eventually. checkFor(t, 5*time.Second, 200*time.Millisecond, func() error { _, err := js.ConsumerInfo("TEST", "d1", nats.MaxWait(250*time.Millisecond)) return err }) checkFor(t, 5*time.Second, 200*time.Millisecond, func() error { if after := runtime.NumGoroutine(); base > after { return fmt.Errorf("Expected %d go routines, got %d", base, after) } return nil }) // Simulate a low level write error on our consumer and make sure we can recover etc. checkFor(t, 10*time.Second, 200*time.Millisecond, func() error { if cl = c.consumerLeader("$G", "TEST", "d1"); cl != nil { return nil } return errors.New("waiting on consumer leader") }) mset, err = cl.GlobalAccount().lookupStream("TEST") if err != nil { t.Fatalf("Unexpected error: %v", err) } o := mset.lookupConsumer("d1") if o == nil { t.Fatalf("Did not retrieve consumer") } node := o.raftNode().(*raft) if node == nil { t.Fatalf("could not retrieve the raft node for consumer") } nc.Close() node.setWriteErr(io.ErrShortWrite) c.stopAll() c.restartAll() c.waitOnStreamLeader("$G", "TEST") c.waitOnConsumerLeader("$G", "TEST", "d1") } // Reports of high cpu on compaction for a KV store. func TestNoRaceJetStreamKeyValueCompaction(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() // Client based API nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() kv, err := js.CreateKeyValue(&nats.KeyValueConfig{ Bucket: "COMPACT", Replicas: 3, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } value := strings.Repeat("A", 128*1024) for i := 0; i < 5_000; i++ { key := fmt.Sprintf("K-%d", rand.Intn(256)+1) if _, err := kv.PutString(key, value); err != nil { t.Fatalf("Unexpected error: %v", err) } } } // Trying to recreate an issue rip saw with KV and server restarts complaining about // mismatch for a few minutes and growing memory. func TestNoRaceJetStreamClusterStreamSeqMismatchIssue(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() // Client based API nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() kv, err := js.CreateKeyValue(&nats.KeyValueConfig{ Bucket: "MM", Replicas: 3, TTL: 500 * time.Millisecond, }) require_NoError(t, err) for i := 1; i <= 10; i++ { if _, err := kv.PutString("k", "1"); err != nil { t.Fatalf("Unexpected error: %v", err) } } // Close in case we are connected here. Will recreate. nc.Close() // Shutdown a non-leader. s := c.randomNonStreamLeader("$G", "KV_MM") s.Shutdown() nc, js = jsClientConnect(t, c.randomServer()) defer nc.Close() kv, err = js.KeyValue("MM") require_NoError(t, err) // Now change the state of the stream such that we have to do a compact upon restart // of the downed server. for i := 1; i <= 10; i++ { if _, err := kv.PutString("k", "2"); err != nil { t.Fatalf("Unexpected error: %v", err) } } // Raft could save us here so need to run a compact on the leader. snapshotLeader := func() { sl := c.streamLeader("$G", "KV_MM") if sl == nil { t.Fatalf("Did not get the leader") } mset, err := sl.GlobalAccount().lookupStream("KV_MM") require_NoError(t, err) node := mset.raftNode() if node == nil { t.Fatalf("Could not get stream group") } if err := node.InstallSnapshot(mset.stateSnapshot()); err != nil { t.Fatalf("Error installing snapshot: %v", err) } } // Now wait for expiration time.Sleep(time.Second) snapshotLeader() s = c.restartServer(s) c.waitOnServerCurrent(s) // We want to make sure we do not reset the raft state on a catchup due to no request yield. // Bug was if we did not actually request any help from snapshot we did not set mset.lseq properly. // So when we send next batch that would cause raft reset due to cluster reset for our stream. mset, err := s.GlobalAccount().lookupStream("KV_MM") require_NoError(t, err) for i := 1; i <= 10; i++ { if _, err := kv.PutString("k1", "X"); err != nil { t.Fatalf("Unexpected error: %v", err) } } c.waitOnStreamCurrent(s, "$G", "KV_MM") // Make sure we did not reset our stream. msetNew, err := s.GlobalAccount().lookupStream("KV_MM") require_NoError(t, err) if msetNew != mset { t.Fatalf("Stream was reset") } } func TestNoRaceJetStreamClusterStreamDropCLFS(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() // Client based API nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() kv, err := js.CreateKeyValue(&nats.KeyValueConfig{ Bucket: "CLFS", Replicas: 3, }) require_NoError(t, err) // Will work _, err = kv.Create("k.1", []byte("X")) require_NoError(t, err) // Drive up CLFS state on leader. for i := 0; i < 10; i++ { _, err = kv.Create("k.1", []byte("X")) require_Error(t, err) } // Bookend with new key success. _, err = kv.Create("k.2", []byte("Z")) require_NoError(t, err) // Close in case we are connected here. Will recreate. nc.Close() // Shutdown, which will also clear clfs. s := c.randomNonStreamLeader("$G", "KV_CLFS") s.Shutdown() nc, js = jsClientConnect(t, c.randomServer()) defer nc.Close() kv, err = js.KeyValue("CLFS") require_NoError(t, err) // Drive up CLFS state on leader. for i := 0; i < 10; i++ { _, err = kv.Create("k.1", []byte("X")) require_Error(t, err) } sl := c.streamLeader("$G", "KV_CLFS") if sl == nil { t.Fatalf("Did not get the leader") } mset, err := sl.GlobalAccount().lookupStream("KV_CLFS") require_NoError(t, err) node := mset.raftNode() if node == nil { t.Fatalf("Could not get stream group") } if err := node.InstallSnapshot(mset.stateSnapshot()); err != nil { t.Fatalf("Error installing snapshot: %v", err) } _, err = kv.Create("k.3", []byte("ZZZ")) require_NoError(t, err) s = c.restartServer(s) c.waitOnServerCurrent(s) mset, err = s.GlobalAccount().lookupStream("KV_CLFS") require_NoError(t, err) _, err = kv.Create("k.4", []byte("YYY")) require_NoError(t, err) c.waitOnStreamCurrent(s, "$G", "KV_CLFS") // Make sure we did not reset our stream. msetNew, err := s.GlobalAccount().lookupStream("KV_CLFS") require_NoError(t, err) if msetNew != mset { t.Fatalf("Stream was reset") } } func TestNoRaceJetStreamMemstoreWithLargeInteriorDeletes(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() // Client for API requests. nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo", "bar"}, MaxMsgsPerSubject: 1, Storage: nats.MemoryStorage, }) require_NoError(t, err) acc, err := s.lookupAccount("$G") require_NoError(t, err) mset, err := acc.lookupStream("TEST") require_NoError(t, err) msg := []byte("Hello World!") if _, err := js.PublishAsync("foo", msg); err != nil { t.Fatalf("Unexpected publish error: %v", err) } for i := 1; i <= 1_000_000; i++ { if _, err := js.PublishAsync("bar", msg); err != nil { t.Fatalf("Unexpected publish error: %v", err) } } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } now := time.Now() ss := mset.stateWithDetail(true) // Before the fix the snapshot for this test would be > 200ms on my setup. if elapsed := time.Since(now); elapsed > 100*time.Millisecond { t.Fatalf("Took too long to snapshot: %v", elapsed) } else if elapsed > 50*time.Millisecond { t.Logf("WRN: Took longer than usual to snapshot: %v", elapsed) } if ss.Msgs != 2 || ss.FirstSeq != 1 || ss.LastSeq != 1_000_001 || ss.NumDeleted != 999999 { // To not print out on error. ss.Deleted = nil t.Fatalf("Bad State: %+v", ss) } } // This is related to an issue reported where we were exhausting threads by trying to // cleanup too many consumers at the same time. // https://github.com/nats-io/nats-server/issues/2742 func TestNoRaceJetStreamConsumerFileStoreConcurrentDiskIO(t *testing.T) { storeDir := t.TempDir() // Artificially adjust our environment for this test. gmp := runtime.GOMAXPROCS(32) defer runtime.GOMAXPROCS(gmp) maxT := debug.SetMaxThreads(1050) // 1024 now defer debug.SetMaxThreads(maxT) fs, err := newFileStore(FileStoreConfig{StoreDir: storeDir}, StreamConfig{Name: "MT", Storage: FileStorage}) require_NoError(t, err) defer fs.Stop() startCh := make(chan bool) var wg sync.WaitGroup var swg sync.WaitGroup ts := time.Now().UnixNano() // Create 1000 consumerStores n := 1000 swg.Add(n) for i := 1; i <= n; i++ { name := fmt.Sprintf("o%d", i) o, err := fs.ConsumerStore(name, &ConsumerConfig{AckPolicy: AckExplicit}) require_NoError(t, err) wg.Add(1) swg.Done() go func() { defer wg.Done() // Will make everyone run concurrently. <-startCh o.UpdateDelivered(22, 22, 1, ts) buf, _ := o.(*consumerFileStore).encodeState() o.(*consumerFileStore).writeState(buf) o.Delete() }() } swg.Wait() close(startCh) wg.Wait() } func TestNoRaceJetStreamClusterHealthz(t *testing.T) { c := createJetStreamCluster(t, jsClusterAccountsTempl, "HZ", _EMPTY_, 3, 23033, true) defer c.shutdown() nc1, js1 := jsClientConnect(t, c.randomServer(), nats.UserInfo("one", "p")) defer nc1.Close() nc2, js2 := jsClientConnect(t, c.randomServer(), nats.UserInfo("two", "p")) defer nc2.Close() var err error for _, sname := range []string{"foo", "bar", "baz"} { _, err = js1.AddStream(&nats.StreamConfig{Name: sname, Replicas: 3}) require_NoError(t, err) _, err = js2.AddStream(&nats.StreamConfig{Name: sname, Replicas: 3}) require_NoError(t, err) } // R1 _, err = js1.AddStream(&nats.StreamConfig{Name: "r1", Replicas: 1}) require_NoError(t, err) // Now shutdown then send a bunch of data. s := c.servers[0] s.Shutdown() for i := 0; i < 5_000; i++ { _, err = js1.PublishAsync("foo", []byte("OK")) require_NoError(t, err) _, err = js2.PublishAsync("bar", []byte("OK")) require_NoError(t, err) } select { case <-js1.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } select { case <-js2.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } s = c.restartServer(s) opts := s.getOpts() opts.HTTPHost = "127.0.0.1" opts.HTTPPort = 11222 err = s.StartMonitoring() require_NoError(t, err) url := fmt.Sprintf("http://127.0.0.1:%d/healthz", opts.HTTPPort) getHealth := func() (int, *HealthStatus) { resp, err := http.Get(url) require_NoError(t, err) defer resp.Body.Close() body, err := io.ReadAll(resp.Body) require_NoError(t, err) var hs HealthStatus err = json.Unmarshal(body, &hs) require_NoError(t, err) return resp.StatusCode, &hs } errors := 0 checkFor(t, 20*time.Second, 100*time.Millisecond, func() error { code, hs := getHealth() if code >= 200 && code < 300 { return nil } errors++ return fmt.Errorf("Got %d status with %+v", code, hs) }) if errors == 0 { t.Fatalf("Expected to have some errors until we became current, got none") } } // Test that we can receive larger messages with stream subject details. // Also test that we will fail at some point and the user can fall back to // an orderedconsumer like we do with watch for KV Keys() call. func TestNoRaceJetStreamStreamInfoSubjectDetailsLimits(t *testing.T) { conf := createConfFile(t, []byte(fmt.Sprintf(` listen: 127.0.0.1:-1 jetstream { store_dir = %q } accounts: { default: { jetstream: true users: [ {user: me, password: pwd} ] limits { max_payload: 512 } } } `, t.TempDir()))) s, _ := RunServerWithConfig(conf) if config := s.JetStreamConfig(); config != nil { defer removeDir(t, config.StoreDir) } defer s.Shutdown() nc, js := jsClientConnect(t, s, nats.UserInfo("me", "pwd")) defer nc.Close() // Make sure to flush so we process the 2nd INFO. nc.Flush() // Make sure we cannot send larger than 512 bytes. // But we can receive larger. sub, err := nc.SubscribeSync("foo") require_NoError(t, err) err = nc.Publish("foo", []byte(strings.Repeat("A", 600))) require_Error(t, err, nats.ErrMaxPayload) sub.Unsubscribe() _, err = js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"*", "X.*"}, }) require_NoError(t, err) n := JSMaxSubjectDetails for i := 0; i < n; i++ { _, err := js.PublishAsync(fmt.Sprintf("X.%d", i), []byte("OK")) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } // Need to grab StreamInfo by hand for now. req, err := json.Marshal(&JSApiStreamInfoRequest{SubjectsFilter: "X.*"}) require_NoError(t, err) resp, err := nc.Request(fmt.Sprintf(JSApiStreamInfoT, "TEST"), req, 5*time.Second) require_NoError(t, err) var si StreamInfo err = json.Unmarshal(resp.Data, &si) require_NoError(t, err) if len(si.State.Subjects) != n { t.Fatalf("Expected to get %d subject details, got %d", n, len(si.State.Subjects)) } // Now add one more message to check pagination _, err = js.Publish("foo", []byte("TOO MUCH")) require_NoError(t, err) req, err = json.Marshal(&JSApiStreamInfoRequest{ApiPagedRequest: ApiPagedRequest{Offset: n}, SubjectsFilter: nats.AllKeys}) require_NoError(t, err) resp, err = nc.Request(fmt.Sprintf(JSApiStreamInfoT, "TEST"), req, 5*time.Second) require_NoError(t, err) var sir JSApiStreamInfoResponse err = json.Unmarshal(resp.Data, &sir) require_NoError(t, err) if len(sir.State.Subjects) != 1 { t.Fatalf("Expected to get 1 extra subject detail, got %d", len(sir.State.Subjects)) } } func TestNoRaceJetStreamSparseConsumers(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, js := jsClientConnect(t, s) defer nc.Close() msg := []byte("ok") cases := []struct { name string mconfig *nats.StreamConfig }{ {"MemoryStore", &nats.StreamConfig{Name: "TEST", Storage: nats.MemoryStorage, MaxMsgsPerSubject: 25_000_000, Subjects: []string{"*"}}}, {"FileStore", &nats.StreamConfig{Name: "TEST", Storage: nats.FileStorage, MaxMsgsPerSubject: 25_000_000, Subjects: []string{"*"}}}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { js.DeleteStream("TEST") _, err := js.AddStream(c.mconfig) require_NoError(t, err) // We will purposely place foo msgs near the beginning, then in middle, then at the end. for n := 0; n < 2; n++ { _, err = js.PublishAsync("foo", msg, nats.StallWait(800*time.Millisecond)) require_NoError(t, err) for i := 0; i < 1_000_000; i++ { _, err = js.PublishAsync("bar", msg, nats.StallWait(800*time.Millisecond)) require_NoError(t, err) } _, err = js.PublishAsync("foo", msg, nats.StallWait(800*time.Millisecond)) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } // Now create a consumer on foo. ci, err := js.AddConsumer("TEST", &nats.ConsumerConfig{DeliverSubject: "x.x", FilterSubject: "foo", AckPolicy: nats.AckNonePolicy}) require_NoError(t, err) done, received := make(chan bool), uint64(0) cb := func(m *nats.Msg) { received++ if received >= ci.NumPending { done <- true } } sub, err := nc.Subscribe("x.x", cb) require_NoError(t, err) defer sub.Unsubscribe() start := time.Now() var elapsed time.Duration select { case <-done: elapsed = time.Since(start) case <-time.After(10 * time.Second): t.Fatal("Did not receive all messages for all consumers in time") } if elapsed > 500*time.Millisecond { t.Fatalf("Getting all messages took longer than expected: %v", elapsed) } }) } } func TestNoRaceJetStreamConsumerFilterPerfDegradation(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, _ := jsClientConnect(t, s) defer nc.Close() js, err := nc.JetStream(nats.PublishAsyncMaxPending(256)) require_NoError(t, err) _, err = js.AddStream(&nats.StreamConfig{ Name: "test", Subjects: []string{"test.*.subj"}, Replicas: 1, }) require_NoError(t, err) toSend := 50_000 count := 0 ch := make(chan struct{}, 6) _, err = js.Subscribe("test.*.subj", func(m *nats.Msg) { m.Ack() if count++; count == toSend { ch <- struct{}{} } }, nats.DeliverNew(), nats.ManualAck()) require_NoError(t, err) msg := make([]byte, 1024) sent := int32(0) send := func() { defer func() { ch <- struct{}{} }() for i := 0; i < toSend/5; i++ { msgID := atomic.AddInt32(&sent, 1) _, err := js.Publish(fmt.Sprintf("test.%d.subj", msgID), msg) if err != nil { t.Error(err) return } } } for i := 0; i < 5; i++ { go send() } timeout := time.NewTimer(10 * time.Second) for i := 0; i < 6; i++ { select { case <-ch: case <-timeout.C: t.Fatal("Took too long") } } } func TestNoRaceJetStreamFileStoreKeyFileCleanup(t *testing.T) { storeDir := t.TempDir() prf := func(context []byte) ([]byte, error) { h := hmac.New(sha256.New, []byte("dlc22")) if _, err := h.Write(context); err != nil { return nil, err } return h.Sum(nil), nil } fs, err := newFileStoreWithCreated( FileStoreConfig{StoreDir: storeDir, BlockSize: 1024 * 1024}, StreamConfig{Name: "TEST", Storage: FileStorage}, time.Now(), prf, nil) require_NoError(t, err) defer fs.Stop() n, msg := 10_000, []byte(strings.Repeat("Z", 1024)) for i := 0; i < n; i++ { _, _, err := fs.StoreMsg(fmt.Sprintf("X.%d", i), nil, msg) require_NoError(t, err) } var seqs []uint64 for i := 1; i <= n; i++ { seqs = append(seqs, uint64(i)) } // Randomly delete msgs, make sure we cleanup as we empty the message blocks. rand.Shuffle(len(seqs), func(i, j int) { seqs[i], seqs[j] = seqs[j], seqs[i] }) for _, seq := range seqs { _, err := fs.RemoveMsg(seq) require_NoError(t, err) } // We will have cleanup the main .blk and .idx sans the lmb, but we should not have any *.fss files. kms, err := filepath.Glob(filepath.Join(storeDir, msgDir, keyScanAll)) require_NoError(t, err) if len(kms) > 1 { t.Fatalf("Expected to find only 1 key file, found %d", len(kms)) } } func TestNoRaceJetStreamMsgIdPerfDuringCatchup(t *testing.T) { // Uncomment to run. Needs to be on a bigger machine. Do not want as part of Travis tests atm. skip(t) c := createJetStreamClusterExplicit(t, "JSC", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.serverByName("S-1")) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Replicas: 3, }) require_NoError(t, err) // This will be the one we restart. sl := c.streamLeader("$G", "TEST") // Now move leader. _, err = nc.Request(fmt.Sprintf(JSApiStreamLeaderStepDownT, "TEST"), nil, time.Second) require_NoError(t, err) c.waitOnStreamLeader("$G", "TEST") // Connect to new leader. nc, _ = jsClientConnect(t, c.streamLeader("$G", "TEST")) defer nc.Close() js, err = nc.JetStream(nats.PublishAsyncMaxPending(1024)) require_NoError(t, err) n, ss, sr := 1_000_000, 250_000, 800_000 m := nats.NewMsg("TEST") m.Data = []byte(strings.Repeat("Z", 2048)) // Target rate 10k msgs/sec start := time.Now() for i := 0; i < n; i++ { m.Header.Set(JSMsgId, strconv.Itoa(i)) _, err := js.PublishMsgAsync(m) require_NoError(t, err) //time.Sleep(42 * time.Microsecond) if i == ss { fmt.Printf("SD") sl.Shutdown() } else if i == sr { nc.Flush() select { case <-js.PublishAsyncComplete(): case <-time.After(10 * time.Second): } fmt.Printf("RS") sl = c.restartServer(sl) } if i%10_000 == 0 { fmt.Print("#") } } fmt.Println() // Wait to receive all messages. select { case <-js.PublishAsyncComplete(): case <-time.After(20 * time.Second): t.Fatalf("Did not receive completion signal") } tt := time.Since(start) si, err := js.StreamInfo("TEST") require_NoError(t, err) fmt.Printf("Took %v to send %d msgs\n", tt, n) fmt.Printf("%.0f msgs/s\n", float64(n)/tt.Seconds()) fmt.Printf("%.0f mb/s\n\n", float64(si.State.Bytes/(1024*1024))/tt.Seconds()) c.waitOnStreamCurrent(sl, "$G", "TEST") for _, s := range c.servers { mset, _ := s.GlobalAccount().lookupStream("TEST") if state := mset.store.State(); state.Msgs != uint64(n) { t.Fatalf("Expected server %v to have correct number of msgs %d but got %d", s, n, state.Msgs) } } } func TestNoRaceJetStreamRebuildDeDupeAndMemoryPerf(t *testing.T) { skip(t) s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{Name: "DD"}) require_NoError(t, err) m := nats.NewMsg("DD") m.Data = []byte(strings.Repeat("Z", 2048)) start := time.Now() n := 1_000_000 for i := 0; i < n; i++ { m.Header.Set(JSMsgId, strconv.Itoa(i)) _, err := js.PublishMsgAsync(m) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(20 * time.Second): t.Fatalf("Did not receive completion signal") } tt := time.Since(start) si, err := js.StreamInfo("DD") require_NoError(t, err) fmt.Printf("Took %v to send %d msgs\n", tt, n) fmt.Printf("%.0f msgs/s\n", float64(n)/tt.Seconds()) fmt.Printf("%.0f mb/s\n\n", float64(si.State.Bytes/(1024*1024))/tt.Seconds()) v, _ := s.Varz(nil) fmt.Printf("Memory AFTER SEND: %v\n", friendlyBytes(v.Mem)) mset, err := s.GlobalAccount().lookupStream("DD") require_NoError(t, err) mset.mu.Lock() mset.ddloaded = false start = time.Now() mset.rebuildDedupe() fmt.Printf("TOOK %v to rebuild dd\n", time.Since(start)) mset.mu.Unlock() v, _ = s.Varz(nil) fmt.Printf("Memory: %v\n", friendlyBytes(v.Mem)) // Now do an ephemeral consumer and whip through every message. Doing same calculations. start = time.Now() received, done := 0, make(chan bool) sub, err := js.Subscribe("DD", func(m *nats.Msg) { received++ if received >= n { done <- true } }, nats.OrderedConsumer()) require_NoError(t, err) select { case <-done: case <-time.After(10 * time.Second): if s.NumSlowConsumers() > 0 { t.Fatalf("Did not receive all large messages due to slow consumer status: %d of %d", received, n) } t.Fatalf("Failed to receive all large messages: %d of %d\n", received, n) } fmt.Printf("TOOK %v to receive all %d msgs\n", time.Since(start), n) sub.Unsubscribe() v, _ = s.Varz(nil) fmt.Printf("Memory: %v\n", friendlyBytes(v.Mem)) } func TestNoRaceJetStreamMemoryUsageOnLimitedStreamWithMirror(t *testing.T) { skip(t) s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{Name: "DD", Subjects: []string{"ORDERS.*"}, MaxMsgs: 10_000}) require_NoError(t, err) _, err = js.AddStream(&nats.StreamConfig{ Name: "M", Mirror: &nats.StreamSource{Name: "DD"}, MaxMsgs: 10_000, }) require_NoError(t, err) m := nats.NewMsg("ORDERS.0") m.Data = []byte(strings.Repeat("Z", 2048)) start := time.Now() n := 1_000_000 for i := 0; i < n; i++ { m.Subject = fmt.Sprintf("ORDERS.%d", i) m.Header.Set(JSMsgId, strconv.Itoa(i)) _, err := js.PublishMsgAsync(m) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(20 * time.Second): t.Fatalf("Did not receive completion signal") } tt := time.Since(start) si, err := js.StreamInfo("DD") require_NoError(t, err) fmt.Printf("Took %v to send %d msgs\n", tt, n) fmt.Printf("%.0f msgs/s\n", float64(n)/tt.Seconds()) fmt.Printf("%.0f mb/s\n\n", float64(si.State.Bytes/(1024*1024))/tt.Seconds()) v, _ := s.Varz(nil) fmt.Printf("Memory AFTER SEND: %v\n", friendlyBytes(v.Mem)) } func TestNoRaceJetStreamOrderedConsumerLongRTTPerformance(t *testing.T) { skip(t) s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, _ := jsClientConnect(t, s) defer nc.Close() js, err := nc.JetStream(nats.PublishAsyncMaxPending(1000)) require_NoError(t, err) _, err = js.AddStream(&nats.StreamConfig{Name: "OCP"}) require_NoError(t, err) n, msg := 100_000, []byte(strings.Repeat("D", 30_000)) for i := 0; i < n; i++ { _, err := js.PublishAsync("OCP", msg) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } // Approximately 3GB si, err := js.StreamInfo("OCP") require_NoError(t, err) start := time.Now() received, done := 0, make(chan bool) sub, err := js.Subscribe("OCP", func(m *nats.Msg) { received++ if received >= n { done <- true } }, nats.OrderedConsumer()) require_NoError(t, err) defer sub.Unsubscribe() // Wait to receive all messages. select { case <-done: case <-time.After(30 * time.Second): t.Fatalf("Did not receive all of our messages") } tt := time.Since(start) fmt.Printf("Took %v to receive %d msgs\n", tt, n) fmt.Printf("%.0f msgs/s\n", float64(n)/tt.Seconds()) fmt.Printf("%.0f mb/s\n\n", float64(si.State.Bytes/(1024*1024))/tt.Seconds()) sub.Unsubscribe() rtt := 10 * time.Millisecond bw := 10 * 1024 * 1024 * 1024 proxy := newNetProxy(rtt, bw, bw, s.ClientURL()) defer proxy.stop() nc, err = nats.Connect(proxy.clientURL()) require_NoError(t, err) defer nc.Close() js, err = nc.JetStream() require_NoError(t, err) start, received = time.Now(), 0 sub, err = js.Subscribe("OCP", func(m *nats.Msg) { received++ if received >= n { done <- true } }, nats.OrderedConsumer()) require_NoError(t, err) defer sub.Unsubscribe() // Wait to receive all messages. select { case <-done: case <-time.After(60 * time.Second): t.Fatalf("Did not receive all of our messages") } tt = time.Since(start) fmt.Printf("Proxy RTT: %v, UP: %d, DOWN: %d\n", rtt, bw, bw) fmt.Printf("Took %v to receive %d msgs\n", tt, n) fmt.Printf("%.0f msgs/s\n", float64(n)/tt.Seconds()) fmt.Printf("%.0f mb/s\n\n", float64(si.State.Bytes/(1024*1024))/tt.Seconds()) } var jsClusterStallCatchupTempl = ` listen: 127.0.0.1:-1 server_name: %s jetstream: {max_mem_store: 256MB, max_file_store: 32GB, store_dir: '%s'} leaf { listen: 127.0.0.1:-1 } cluster { name: %s listen: 127.0.0.1:%d routes = [%s] } # For access to system account. accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } ` // Test our global stall gate for outstanding catchup bytes. func TestNoRaceJetStreamClusterCatchupStallGate(t *testing.T) { skip(t) c := createJetStreamClusterWithTemplate(t, jsClusterStallCatchupTempl, "GSG", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() // ~100k per message. msg := []byte(strings.Repeat("A", 99_960)) // Create 200 streams with 100MB. // Each server has ~2GB var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) go func(x int) { defer wg.Done() for n := 1; n <= 10; n++ { sn := fmt.Sprintf("S-%d", n+x) _, err := js.AddStream(&nats.StreamConfig{ Name: sn, Replicas: 3, }) require_NoError(t, err) for i := 0; i < 100; i++ { _, err := js.Publish(sn, msg) require_NoError(t, err) } } }(i * 20) } wg.Wait() info, err := js.AccountInfo() require_NoError(t, err) require_True(t, info.Streams == 200) runtime.GC() debug.FreeOSMemory() // Now bring a server down and wipe its storage. s := c.servers[0] vz, err := s.Varz(nil) require_NoError(t, err) fmt.Printf("MEM BEFORE is %v\n", friendlyBytes(vz.Mem)) sd := s.JetStreamConfig().StoreDir s.Shutdown() removeDir(t, sd) s = c.restartServer(s) c.waitOnServerHealthz(s) runtime.GC() debug.FreeOSMemory() vz, err = s.Varz(nil) require_NoError(t, err) fmt.Printf("MEM AFTER is %v\n", friendlyBytes(vz.Mem)) } func TestNoRaceJetStreamClusterCatchupBailMidway(t *testing.T) { skip(t) c := createJetStreamClusterWithTemplate(t, jsClusterStallCatchupTempl, "GSG", 3) defer c.shutdown() ml := c.leader() nc, js := jsClientConnect(t, ml) defer nc.Close() msg := []byte(strings.Repeat("A", 480)) for i := 0; i < maxConcurrentSyncRequests*2; i++ { sn := fmt.Sprintf("CUP-%d", i+1) _, err := js.AddStream(&nats.StreamConfig{ Name: sn, Replicas: 3, }) require_NoError(t, err) for i := 0; i < 10_000; i++ { _, err := js.PublishAsync(sn, msg) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(10 * time.Second): t.Fatalf("Did not receive completion signal") } } jsz, _ := ml.Jsz(nil) expectedMsgs := jsz.Messages // Now select a server and shut it down, removing the storage directory. s := c.randomNonLeader() sd := s.JetStreamConfig().StoreDir s.Shutdown() removeDir(t, sd) // Now restart the server. s = c.restartServer(s) // We want to force the follower to bail before the catchup through the // upper level catchup logic completes. checkFor(t, 5*time.Second, 10*time.Millisecond, func() error { jsz, _ := s.Jsz(nil) if jsz.Messages > expectedMsgs/2 { s.Shutdown() return nil } return fmt.Errorf("Not enough yet") }) // Now restart the server. s = c.restartServer(s) checkFor(t, 5*time.Second, 500*time.Millisecond, func() error { jsz, _ := s.Jsz(nil) if jsz.Messages == expectedMsgs { return nil } return fmt.Errorf("Not enough yet") }) } func TestNoRaceJetStreamAccountLimitsAndRestart(t *testing.T) { c := createJetStreamClusterWithTemplate(t, jsClusterAccountLimitsTempl, "A3S", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() if _, err := js.AddStream(&nats.StreamConfig{Name: "TEST", Replicas: 3}); err != nil { t.Fatalf("Unexpected error: %v", err) } for i := 0; i < 20_000; i++ { if _, err := js.Publish("TEST", []byte("A")); err != nil { break } if i == 5_000 { snl := c.randomNonStreamLeader("$JS", "TEST") snl.Shutdown() } } c.stopAll() c.restartAll() c.waitOnLeader() c.waitOnStreamLeader("$JS", "TEST") for _, cs := range c.servers { c.waitOnStreamCurrent(cs, "$JS", "TEST") } } func TestNoRaceJetStreamPullConsumersAndInteriorDeletes(t *testing.T) { c := createJetStreamClusterExplicit(t, "ID", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "foo", Replicas: 3, MaxMsgs: 50000, Retention: nats.InterestPolicy, }) require_NoError(t, err) c.waitOnStreamLeader(globalAccountName, "foo") _, err = js.AddConsumer("foo", &nats.ConsumerConfig{ Durable: "foo", FilterSubject: "foo", MaxAckPending: 20000, AckWait: time.Minute, AckPolicy: nats.AckExplicitPolicy, }) require_NoError(t, err) c.waitOnConsumerLeader(globalAccountName, "foo", "foo") rcv := int32(0) prods := 5 cons := 5 wg := sync.WaitGroup{} wg.Add(prods + cons) toSend := 100000 for i := 0; i < cons; i++ { go func() { defer wg.Done() sub, err := js.PullSubscribe("foo", "foo") if err != nil { return } for { msgs, err := sub.Fetch(200, nats.MaxWait(250*time.Millisecond)) if err != nil { if n := int(atomic.LoadInt32(&rcv)); n >= toSend { return } continue } for _, m := range msgs { m.Ack() atomic.AddInt32(&rcv, 1) } } }() } for i := 0; i < prods; i++ { go func() { defer wg.Done() for i := 0; i < toSend/prods; i++ { js.Publish("foo", []byte("hello")) } }() } time.Sleep(time.Second) resp, err := nc.Request(fmt.Sprintf(JSApiConsumerLeaderStepDownT, "foo", "foo"), nil, time.Second) if err != nil { t.Fatalf("Unexpected error: %v", err) } var cdResp JSApiConsumerLeaderStepDownResponse if err := json.Unmarshal(resp.Data, &cdResp); err != nil { t.Fatalf("Unexpected error: %v", err) } if cdResp.Error != nil { t.Fatalf("Unexpected error: %+v", cdResp.Error) } ch := make(chan struct{}) go func() { wg.Wait() close(ch) }() select { case <-ch: // OK case <-time.After(30 * time.Second): t.Fatalf("Consumers took too long to consumer all messages") } } func TestNoRaceJetStreamClusterInterestPullConsumerStreamLimitBug(t *testing.T) { c := createJetStreamClusterExplicit(t, "JSC", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() limit := uint64(1000) _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo"}, Retention: nats.InterestPolicy, MaxMsgs: int64(limit), Replicas: 3, }) require_NoError(t, err) _, err = js.AddConsumer("TEST", &nats.ConsumerConfig{Durable: "dur", AckPolicy: nats.AckExplicitPolicy}) require_NoError(t, err) qch := make(chan bool) var wg sync.WaitGroup // Publisher wg.Add(1) go func() { defer wg.Done() for { pt := time.NewTimer(time.Duration(rand.Intn(2)) * time.Millisecond) select { case <-pt.C: _, err := js.Publish("foo", []byte("BUG!")) require_NoError(t, err) case <-qch: pt.Stop() return } } }() time.Sleep(time.Second) // Pull Consumers wg.Add(100) for i := 0; i < 100; i++ { go func() { defer wg.Done() nc := natsConnect(t, c.randomServer().ClientURL()) defer nc.Close() js, err := nc.JetStream(nats.MaxWait(time.Second)) require_NoError(t, err) var sub *nats.Subscription for j := 0; j < 5; j++ { sub, err = js.PullSubscribe("foo", "dur") if err == nil { break } } require_NoError(t, err) for { pt := time.NewTimer(time.Duration(rand.Intn(300)) * time.Millisecond) select { case <-pt.C: msgs, err := sub.Fetch(1) if err != nil { t.Logf("Got a Fetch error: %v", err) return } if len(msgs) > 0 { go func() { ackDelay := time.Duration(rand.Intn(375)+15) * time.Millisecond m := msgs[0] time.AfterFunc(ackDelay, func() { m.AckSync() }) }() } case <-qch: return } } }() } // Make sure we have hit the limit for the number of messages we expected. checkFor(t, 20*time.Second, 500*time.Millisecond, func() error { si, err := js.StreamInfo("TEST") require_NoError(t, err) if si.State.Msgs < limit { return fmt.Errorf("Not hit limit yet") } return nil }) close(qch) wg.Wait() checkFor(t, 20*time.Second, 500*time.Millisecond, func() error { si, err := js.StreamInfo("TEST") require_NoError(t, err) ci, err := js.ConsumerInfo("TEST", "dur") require_NoError(t, err) np := ci.NumPending + uint64(ci.NumAckPending) if np != si.State.Msgs { return fmt.Errorf("Expected NumPending to be %d got %d", si.State.Msgs-uint64(ci.NumAckPending), ci.NumPending) } return nil }) } // Test that all peers have the direct access subs that participate in a queue group, // but only when they are current and ready. So we will start with R1, add in messages // then scale up while also still adding messages. func TestNoRaceJetStreamClusterDirectAccessAllPeersSubs(t *testing.T) { c := createJetStreamClusterExplicit(t, "JSC", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() // Start as R1 cfg := &StreamConfig{ Name: "TEST", Subjects: []string{"kv.>"}, MaxMsgsPer: 10, AllowDirect: true, Replicas: 1, Storage: FileStorage, } addStream(t, nc, cfg) // Seed with enough messages to start then we will scale up while still adding more messages. num, msg := 1000, bytes.Repeat([]byte("XYZ"), 64) for i := 0; i < num; i++ { js.PublishAsync(fmt.Sprintf("kv.%d", i), msg) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } getSubj := fmt.Sprintf(JSDirectMsgGetT, "TEST") getMsg := func(key string) *nats.Msg { t.Helper() req := []byte(fmt.Sprintf(`{"last_by_subj":%q}`, key)) m, err := nc.Request(getSubj, req, time.Second) require_NoError(t, err) require_True(t, m.Header.Get(JSSubject) == key) return m } // Just make sure we can succeed here. getMsg("kv.22") // Now crank up a go routine to continue sending more messages. qch := make(chan bool) var wg sync.WaitGroup for i := 0; i < 5; i++ { wg.Add(1) go func() { defer wg.Done() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() for { select { case <-qch: select { case <-js.PublishAsyncComplete(): case <-time.After(10 * time.Second): } return default: // Send as fast as we can. js.Publish(fmt.Sprintf("kv.%d", rand.Intn(1000)), msg) } } }() } time.Sleep(200 * time.Millisecond) // Now let's scale up to an R3. cfg.Replicas = 3 updateStream(t, nc, cfg) // Wait for the stream to register the new replicas and have a leader. checkFor(t, 20*time.Second, 500*time.Millisecond, func() error { si, err := js.StreamInfo("TEST") if err != nil { return err } if si.Cluster == nil { return fmt.Errorf("No cluster yet") } if si.Cluster.Leader == _EMPTY_ || len(si.Cluster.Replicas) != 2 { return fmt.Errorf("Cluster not ready yet") } return nil }) close(qch) wg.Wait() // Just make sure we can succeed here. getMsg("kv.22") // For each non-leader check that the direct sub fires up. // We just test all, the leader will already have a directSub. for _, s := range c.servers { mset, err := s.GlobalAccount().lookupStream("TEST") require_NoError(t, err) checkFor(t, 20*time.Second, 500*time.Millisecond, func() error { mset.mu.RLock() ok := mset.directSub != nil mset.mu.RUnlock() if ok { return nil } return fmt.Errorf("No directSub yet") }) } si, err := js.StreamInfo("TEST") require_NoError(t, err) if si.State.Msgs == uint64(num) { t.Fatalf("Expected to see messages increase, got %d", si.State.Msgs) } checkFor(t, 10*time.Second, 500*time.Millisecond, func() error { // Make sure they are all the same from a state perspective. // Leader will have the expected state. lmset, err := c.streamLeader("$G", "TEST").GlobalAccount().lookupStream("TEST") require_NoError(t, err) expected := lmset.state() for _, s := range c.servers { mset, err := s.GlobalAccount().lookupStream("TEST") require_NoError(t, err) if state := mset.state(); !reflect.DeepEqual(expected, state) { return fmt.Errorf("Expected %+v, got %+v", expected, state) } } return nil }) } func TestNoRaceJetStreamClusterStreamNamesAndInfosMoreThanAPILimit(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() s := c.randomServer() nc, js := jsClientConnect(t, s) defer nc.Close() createStream := func(name string) { t.Helper() if _, err := js.AddStream(&nats.StreamConfig{Name: name}); err != nil { t.Fatalf("Unexpected error: %v", err) } } max := JSApiListLimit if JSApiNamesLimit > max { max = JSApiNamesLimit } max += 10 for i := 0; i < max; i++ { name := fmt.Sprintf("foo_%d", i) createStream(name) } // Not using the JS API here beacause we want to make sure that the // server returns the proper Total count, but also that it does not // send more than when the API limit is in one go. check := func(subj string, limit int) { t.Helper() nreq := JSApiStreamNamesRequest{} b, _ := json.Marshal(nreq) msg, err := nc.Request(subj, b, 2*time.Second) require_NoError(t, err) nresp := JSApiStreamNamesResponse{} json.Unmarshal(msg.Data, &nresp) if n := nresp.ApiPaged.Total; n != max { t.Fatalf("Expected total to be %v, got %v", max, n) } if n := nresp.ApiPaged.Limit; n != limit { t.Fatalf("Expected limit to be %v, got %v", limit, n) } if n := len(nresp.Streams); n != limit { t.Fatalf("Expected number of streams to be %v, got %v", limit, n) } } check(JSApiStreams, JSApiNamesLimit) check(JSApiStreamList, JSApiListLimit) } func TestNoRaceJetStreamClusterConsumerListPaging(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() s := c.randomNonLeader() nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo"}, Replicas: 3, }) require_NoError(t, err) c.waitOnStreamLeader(globalAccountName, "TEST") cfg := &nats.ConsumerConfig{ Replicas: 1, MemoryStorage: true, AckPolicy: nats.AckExplicitPolicy, } // create 3000 consumers. numConsumers := 3000 for i := 1; i <= numConsumers; i++ { cfg.Durable = fmt.Sprintf("d-%.4d", i) _, err := js.AddConsumer("TEST", cfg) require_NoError(t, err) } // Test both names and list operations. // Names reqSubj := fmt.Sprintf(JSApiConsumersT, "TEST") grabConsumerNames := func(offset int) []string { req := fmt.Sprintf(`{"offset":%d}`, offset) respMsg, err := nc.Request(reqSubj, []byte(req), time.Second) require_NoError(t, err) var resp JSApiConsumerNamesResponse err = json.Unmarshal(respMsg.Data, &resp) require_NoError(t, err) // Sanity check that we are actually paging properly around limits. if resp.Limit < len(resp.Consumers) { t.Fatalf("Expected total limited to %d but got %d", resp.Limit, len(resp.Consumers)) } if resp.Total != numConsumers { t.Fatalf("Invalid total response: expected %d got %d", numConsumers, resp.Total) } return resp.Consumers } results := make(map[string]bool) for offset := 0; len(results) < numConsumers; { consumers := grabConsumerNames(offset) offset += len(consumers) for _, name := range consumers { if results[name] { t.Fatalf("Found duplicate %q", name) } results[name] = true } } // List reqSubj = fmt.Sprintf(JSApiConsumerListT, "TEST") grabConsumerList := func(offset int) []*ConsumerInfo { req := fmt.Sprintf(`{"offset":%d}`, offset) respMsg, err := nc.Request(reqSubj, []byte(req), time.Second) require_NoError(t, err) var resp JSApiConsumerListResponse err = json.Unmarshal(respMsg.Data, &resp) require_NoError(t, err) // Sanity check that we are actually paging properly around limits. if resp.Limit < len(resp.Consumers) { t.Fatalf("Expected total limited to %d but got %d", resp.Limit, len(resp.Consumers)) } if resp.Total != numConsumers { t.Fatalf("Invalid total response: expected %d got %d", numConsumers, resp.Total) } return resp.Consumers } results = make(map[string]bool) for offset := 0; len(results) < numConsumers; { consumers := grabConsumerList(offset) offset += len(consumers) for _, ci := range consumers { name := ci.Config.Durable if results[name] { t.Fatalf("Found duplicate %q", name) } results[name] = true } } if len(results) != numConsumers { t.Fatalf("Received %d / %d consumers", len(results), numConsumers) } } func TestNoRaceJetStreamFileStoreLargeKVAccessTiming(t *testing.T) { storeDir := t.TempDir() blkSize := uint64(4 * 1024) // Compensate for slower IO on MacOSX if runtime.GOOS == "darwin" { blkSize *= 4 } fs, err := newFileStore( FileStoreConfig{StoreDir: storeDir, BlockSize: blkSize, CacheExpire: 30 * time.Second}, StreamConfig{Name: "zzz", Subjects: []string{"KV.STREAM_NAME.*"}, Storage: FileStorage, MaxMsgsPer: 1}, ) require_NoError(t, err) defer fs.Stop() tmpl := "KV.STREAM_NAME.%d" nkeys, val := 100_000, bytes.Repeat([]byte("Z"), 1024) for i := 1; i <= nkeys; i++ { subj := fmt.Sprintf(tmpl, i) _, _, err := fs.StoreMsg(subj, nil, val) require_NoError(t, err) } first := fmt.Sprintf(tmpl, 1) last := fmt.Sprintf(tmpl, nkeys) start := time.Now() sm, err := fs.LoadLastMsg(last, nil) require_NoError(t, err) base := time.Since(start) if !bytes.Equal(sm.msg, val) { t.Fatalf("Retrieved value did not match") } start = time.Now() _, err = fs.LoadLastMsg(first, nil) require_NoError(t, err) slow := time.Since(start) if slow > 4*base || slow > time.Millisecond { t.Fatalf("Took too long to look up first key vs last: %v vs %v", base, slow) } // time first seq lookup for both as well. // Base will be first in this case. fs.mu.RLock() start = time.Now() fs.firstSeqForSubj(first) base = time.Since(start) start = time.Now() fs.firstSeqForSubj(last) slow = time.Since(start) fs.mu.RUnlock() if slow > 4*base || slow > time.Millisecond { t.Fatalf("Took too long to look up last key by subject vs first: %v vs %v", base, slow) } } func TestNoRaceJetStreamKVLock(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.CreateKeyValue(&nats.KeyValueConfig{Bucket: "LOCKS"}) require_NoError(t, err) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() var wg sync.WaitGroup start := make(chan bool) var tracker int64 for i := 0; i < 100; i++ { wg.Add(1) go func() { defer wg.Done() nc, js := jsClientConnect(t, s) defer nc.Close() kv, err := js.KeyValue("LOCKS") require_NoError(t, err) <-start for { last, err := kv.Create("MY_LOCK", []byte("Z")) if err != nil { select { case <-time.After(10 * time.Millisecond): continue case <-ctx.Done(): return } } if v := atomic.AddInt64(&tracker, 1); v != 1 { t.Logf("TRACKER NOT 1 -> %d\n", v) cancel() } time.Sleep(10 * time.Millisecond) if v := atomic.AddInt64(&tracker, -1); v != 0 { t.Logf("TRACKER NOT 0 AFTER RELEASE -> %d\n", v) cancel() } err = kv.Delete("MY_LOCK", nats.LastRevision(last)) if err != nil { t.Logf("Could not unlock for last %d: %v", last, err) } if ctx.Err() != nil { return } } }() } close(start) wg.Wait() } func TestNoRaceJetStreamSuperClusterStreamMoveLongRTT(t *testing.T) { // Make C2 far away. gwm := gwProxyMap{ "C2": &gwProxy{ rtt: 20 * time.Millisecond, up: 1 * 1024 * 1024 * 1024, // 1gbit down: 1 * 1024 * 1024 * 1024, // 1gbit }, } sc := createJetStreamTaggedSuperClusterWithGWProxy(t, gwm) defer sc.shutdown() nc, js := jsClientConnect(t, sc.randomServer()) defer nc.Close() cfg := &nats.StreamConfig{ Name: "TEST", Subjects: []string{"chunk.*"}, Placement: &nats.Placement{Tags: []string{"cloud:aws", "country:us"}}, Replicas: 3, } // Place a stream in C1. _, err := js.AddStream(cfg, nats.MaxWait(10*time.Second)) require_NoError(t, err) chunk := bytes.Repeat([]byte("Z"), 1000*1024) // ~1MB // 256 MB for i := 0; i < 256; i++ { subj := fmt.Sprintf("chunk.%d", i) js.PublishAsync(subj, chunk) } select { case <-js.PublishAsyncComplete(): case <-time.After(10 * time.Second): t.Fatalf("Did not receive completion signal") } // C2, slow RTT. cfg.Placement = &nats.Placement{Tags: []string{"cloud:gcp", "country:uk"}} _, err = js.UpdateStream(cfg) require_NoError(t, err) checkFor(t, 20*time.Second, time.Second, func() error { si, err := js.StreamInfo("TEST", nats.MaxWait(time.Second)) if err != nil { return err } if si.Cluster.Name != "C2" { return fmt.Errorf("Wrong cluster: %q", si.Cluster.Name) } if si.Cluster.Leader == _EMPTY_ { return fmt.Errorf("No leader yet") } else if !strings.HasPrefix(si.Cluster.Leader, "C2-") { return fmt.Errorf("Wrong leader: %q", si.Cluster.Leader) } // Now we want to see that we shrink back to original. if len(si.Cluster.Replicas) != cfg.Replicas-1 { return fmt.Errorf("Expected %d replicas, got %d", cfg.Replicas-1, len(si.Cluster.Replicas)) } return nil }) } // https://github.com/nats-io/nats-server/issues/3455 func TestNoRaceJetStreamConcurrentPullConsumerBatch(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"ORDERS.*"}, Storage: nats.MemoryStorage, Retention: nats.WorkQueuePolicy, }) require_NoError(t, err) toSend := int32(100_000) for i := 0; i < 100_000; i++ { subj := fmt.Sprintf("ORDERS.%d", i+1) js.PublishAsync(subj, []byte("BUY")) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } _, err = js.AddConsumer("TEST", &nats.ConsumerConfig{ Durable: "PROCESSOR", AckPolicy: nats.AckExplicitPolicy, MaxAckPending: 5000, }) require_NoError(t, err) nc, js = jsClientConnect(t, s) defer nc.Close() sub1, err := js.PullSubscribe(_EMPTY_, _EMPTY_, nats.Bind("TEST", "PROCESSOR")) require_NoError(t, err) nc, js = jsClientConnect(t, s) defer nc.Close() sub2, err := js.PullSubscribe(_EMPTY_, _EMPTY_, nats.Bind("TEST", "PROCESSOR")) require_NoError(t, err) startCh := make(chan bool) var received int32 wg := sync.WaitGroup{} fetchSize := 1000 fetch := func(sub *nats.Subscription) { <-startCh defer wg.Done() for { msgs, err := sub.Fetch(fetchSize, nats.MaxWait(time.Second)) if atomic.AddInt32(&received, int32(len(msgs))) >= toSend { break } // We should always receive a full batch here if not last competing fetch. if err != nil || len(msgs) != fetchSize { break } for _, m := range msgs { m.Ack() } } } wg.Add(2) go fetch(sub1) go fetch(sub2) close(startCh) wg.Wait() require_True(t, received == toSend) } func TestNoRaceJetStreamManyPullConsumersNeedAckOptimization(t *testing.T) { // Uncomment to run. Do not want as part of Travis tests atm. // Run with cpu and memory profiling to make sure we have improved. skip(t) s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "ORDERS", Subjects: []string{"ORDERS.*"}, Storage: nats.MemoryStorage, Retention: nats.InterestPolicy, }) require_NoError(t, err) toSend := 100_000 numConsumers := 500 // Create 500 consumers for i := 1; i <= numConsumers; i++ { _, err := js.AddConsumer("ORDERS", &nats.ConsumerConfig{ Durable: fmt.Sprintf("ORDERS_%d", i), FilterSubject: fmt.Sprintf("ORDERS.%d", i), AckPolicy: nats.AckAllPolicy, }) require_NoError(t, err) } for i := 1; i <= toSend; i++ { subj := fmt.Sprintf("ORDERS.%d", i%numConsumers+1) js.PublishAsync(subj, []byte("HELLO")) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } sub, err := js.PullSubscribe("ORDERS.500", "ORDERS_500") require_NoError(t, err) fetchSize := toSend / numConsumers msgs, err := sub.Fetch(fetchSize, nats.MaxWait(time.Second)) require_NoError(t, err) last := msgs[len(msgs)-1] last.AckSync() } // https://github.com/nats-io/nats-server/issues/3499 func TestNoRaceJetStreamDeleteConsumerWithInterestStreamAndHighSeqs(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() // Client for API requests. nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"log.>"}, Retention: nats.InterestPolicy, }) require_NoError(t, err) _, err = js.AddConsumer("TEST", &nats.ConsumerConfig{ Durable: "c", AckPolicy: nats.AckExplicitPolicy, }) require_NoError(t, err) // Set baseline for time to delete so we can see linear increase as sequence numbers increase. start := time.Now() err = js.DeleteConsumer("TEST", "c") require_NoError(t, err) elapsed := time.Since(start) // Crank up sequence numbers. msg := []byte(strings.Repeat("ZZZ", 128)) for i := 0; i < 5_000_000; i++ { nc.Publish("log.Z", msg) } nc.Flush() _, err = js.AddConsumer("TEST", &nats.ConsumerConfig{ Durable: "c", AckPolicy: nats.AckExplicitPolicy, }) require_NoError(t, err) // We have a bug that spins unecessarily through all the sequences from this consumer's // ackfloor(0) and the last sequence for the stream. We will detect by looking for the time // to delete being 100x more. Should be the same since both times no messages exist in the stream. start = time.Now() err = js.DeleteConsumer("TEST", "c") require_NoError(t, err) if e := time.Since(start); e > 100*elapsed { t.Fatalf("Consumer delete took too long: %v vs baseline %v", e, elapsed) } } // Bug when we encode a timestamp that upon decode causes an error which causes server to panic. // This can happen on consumer redelivery since they adjusted timstamps can be in the future, and result // in a negative encoding. If that encoding was exactly -1 seconds, would cause decodeConsumerState to fail // and the server to panic. func TestNoRaceEncodeConsumerStateBug(t *testing.T) { for i := 0; i < 200_000; i++ { // Pretend we redelivered and updated the timestamp to reflect the new start time for expiration. // The bug will trip when time.Now() rounded to seconds in encode is 1 second below the truncated version // of pending. pending := Pending{Sequence: 1, Timestamp: time.Now().Add(time.Second).UnixNano()} state := ConsumerState{ Delivered: SequencePair{Consumer: 1, Stream: 1}, Pending: map[uint64]*Pending{1: &pending}, } buf := encodeConsumerState(&state) _, err := decodeConsumerState(buf) require_NoError(t, err) } } // Performance impact on stream ingress with large number of consumers. func TestNoRaceJetStreamLargeNumConsumersPerfImpact(t *testing.T) { skip(t) s := RunBasicJetStreamServer(t) defer s.Shutdown() // Client for API requests. nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo"}, }) require_NoError(t, err) // Baseline with no consumers. toSend := 1_000_000 start := time.Now() for i := 0; i < toSend; i++ { js.PublishAsync("foo", []byte("OK")) } <-js.PublishAsyncComplete() tt := time.Since(start) fmt.Printf("Base time is %v\n", tt) fmt.Printf("%.0f msgs/sec\n", float64(toSend)/tt.Seconds()) err = js.PurgeStream("TEST") require_NoError(t, err) // Now add in 10 idle consumers. for i := 1; i <= 10; i++ { _, err := js.AddConsumer("TEST", &nats.ConsumerConfig{ Durable: fmt.Sprintf("d-%d", i), AckPolicy: nats.AckExplicitPolicy, }) require_NoError(t, err) } start = time.Now() for i := 0; i < toSend; i++ { js.PublishAsync("foo", []byte("OK")) } <-js.PublishAsyncComplete() tt = time.Since(start) fmt.Printf("\n10 consumers time is %v\n", tt) fmt.Printf("%.0f msgs/sec\n", float64(toSend)/tt.Seconds()) err = js.PurgeStream("TEST") require_NoError(t, err) // Now add in 90 more idle consumers. for i := 11; i <= 100; i++ { _, err := js.AddConsumer("TEST", &nats.ConsumerConfig{ Durable: fmt.Sprintf("d-%d", i), AckPolicy: nats.AckExplicitPolicy, }) require_NoError(t, err) } start = time.Now() for i := 0; i < toSend; i++ { js.PublishAsync("foo", []byte("OK")) } <-js.PublishAsyncComplete() tt = time.Since(start) fmt.Printf("\n100 consumers time is %v\n", tt) fmt.Printf("%.0f msgs/sec\n", float64(toSend)/tt.Seconds()) err = js.PurgeStream("TEST") require_NoError(t, err) // Now add in 900 more for i := 101; i <= 1000; i++ { _, err := js.AddConsumer("TEST", &nats.ConsumerConfig{ Durable: fmt.Sprintf("d-%d", i), AckPolicy: nats.AckExplicitPolicy, }) require_NoError(t, err) } start = time.Now() for i := 0; i < toSend; i++ { js.PublishAsync("foo", []byte("OK")) } <-js.PublishAsyncComplete() tt = time.Since(start) fmt.Printf("\n1000 consumers time is %v\n", tt) fmt.Printf("%.0f msgs/sec\n", float64(toSend)/tt.Seconds()) } // Performance impact on large number of consumers but sparse delivery. func TestNoRaceJetStreamLargeNumConsumersSparseDelivery(t *testing.T) { skip(t) s := RunBasicJetStreamServer(t) defer s.Shutdown() // Client for API requests. nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"ID.*"}, }) require_NoError(t, err) // Now add in ~10k consumers on different subjects. for i := 3; i <= 10_000; i++ { _, err := js.AddConsumer("TEST", &nats.ConsumerConfig{ Durable: fmt.Sprintf("d-%d", i), FilterSubject: fmt.Sprintf("ID.%d", i), AckPolicy: nats.AckNonePolicy, }) require_NoError(t, err) } toSend := 100_000 // Bind a consumer to ID.2. var received int done := make(chan bool) nc, js = jsClientConnect(t, s) defer nc.Close() mh := func(m *nats.Msg) { received++ if received >= toSend { close(done) } } _, err = js.Subscribe("ID.2", mh) require_NoError(t, err) last := make(chan bool) _, err = js.Subscribe("ID.1", func(_ *nats.Msg) { close(last) }) require_NoError(t, err) nc, _ = jsClientConnect(t, s) defer nc.Close() js, err = nc.JetStream(nats.PublishAsyncMaxPending(8 * 1024)) require_NoError(t, err) start := time.Now() for i := 0; i < toSend; i++ { js.PublishAsync("ID.2", []byte("ok")) } // Check latency for this one message. // This will show the issue better than throughput which can bypass signal processing. js.PublishAsync("ID.1", []byte("ok")) select { case <-done: break case <-time.After(10 * time.Second): t.Fatalf("Failed to receive all messages: %d of %d\n", received, toSend) } tt := time.Since(start) fmt.Printf("Took %v to receive %d msgs\n", tt, toSend) fmt.Printf("%.0f msgs/s\n", float64(toSend)/tt.Seconds()) select { case <-last: break case <-time.After(30 * time.Second): t.Fatalf("Failed to receive last message\n") } lt := time.Since(start) fmt.Printf("Took %v to receive last msg\n", lt) } func TestNoRaceJetStreamEndToEndLatency(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() // Client for API requests. nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo"}, }) require_NoError(t, err) nc, js = jsClientConnect(t, s) defer nc.Close() var sent time.Time var max time.Duration next := make(chan struct{}) mh := func(m *nats.Msg) { received := time.Now() tt := received.Sub(sent) if max == 0 || tt > max { max = tt } next <- struct{}{} } sub, err := js.Subscribe("foo", mh) require_NoError(t, err) nc, js = jsClientConnect(t, s) defer nc.Close() toSend := 50_000 for i := 0; i < toSend; i++ { sent = time.Now() js.Publish("foo", []byte("ok")) <-next } sub.Unsubscribe() if max > 250*time.Millisecond { t.Fatalf("Expected max latency to be < 250ms, got %v", max) } } func TestNoRaceJetStreamClusterEnsureWALCompact(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo"}, Replicas: 3, }) require_NoError(t, err) _, err = js.AddConsumer("TEST", &nats.ConsumerConfig{ Durable: "dlc", DeliverSubject: "zz", Replicas: 3, }) require_NoError(t, err) // Force snapshot on stream leader. sl := c.streamLeader(globalAccountName, "TEST") mset, err := sl.GlobalAccount().lookupStream("TEST") require_NoError(t, err) node := mset.raftNode() require_True(t, node != nil) err = node.InstallSnapshot(mset.stateSnapshot()) require_NoError(t, err) // Now publish more than should be needed to cause an additional snapshot. ns := 75_000 for i := 0; i <= ns; i++ { _, err := js.Publish("foo", []byte("bar")) require_NoError(t, err) } // Grab progress and use that to look into WAL entries. _, _, applied := node.Progress() // If ne == ns that means snapshots and compacts were not happening when // they should have been. if ne, _ := node.Applied(applied); ne >= uint64(ns) { t.Fatalf("Did not snapshot and compact the raft WAL, entries == %d", ne) } // Now check consumer. // Force snapshot on consumerleader. cl := c.consumerLeader(globalAccountName, "TEST", "dlc") mset, err = cl.GlobalAccount().lookupStream("TEST") require_NoError(t, err) o := mset.lookupConsumer("dlc") require_True(t, o != nil) node = o.raftNode() require_True(t, node != nil) snap, err := o.store.EncodedState() require_NoError(t, err) err = node.InstallSnapshot(snap) require_NoError(t, err) received, done := 0, make(chan bool, 1) nc.Subscribe("zz", func(m *nats.Msg) { received++ if received >= ns { select { case done <- true: default: } } m.Ack() }) select { case <-done: return case <-time.After(10 * time.Second): t.Fatalf("Did not received all %d msgs, only %d", ns, received) } // Do same trick and check that WAL was compacted. // Grab progress and use that to look into WAL entries. _, _, applied = node.Progress() // If ne == ns that means snapshots and compacts were not happening when // they should have been. if ne, _ := node.Applied(applied); ne >= uint64(ns) { t.Fatalf("Did not snapshot and compact the raft WAL, entries == %d", ne) } } func TestNoRaceFileStoreStreamMaxAgePerformance(t *testing.T) { // Uncomment to run. skip(t) storeDir := t.TempDir() maxAge := 5 * time.Second fs, err := newFileStore( FileStoreConfig{StoreDir: storeDir}, StreamConfig{Name: "MA", Subjects: []string{"foo.*"}, MaxAge: maxAge, Storage: FileStorage}, ) require_NoError(t, err) defer fs.Stop() // Simulate a callback similar to consumers decrementing. var mu sync.RWMutex var pending int64 fs.RegisterStorageUpdates(func(md, bd int64, seq uint64, subj string) { mu.Lock() defer mu.Unlock() pending += md }) start, num, subj := time.Now(), 0, "foo.foo" timeout := start.Add(maxAge) for time.Now().Before(timeout) { // We will store in blocks of 100. for i := 0; i < 100; i++ { _, _, err := fs.StoreMsg(subj, nil, []byte("Hello World")) require_NoError(t, err) num++ } } elapsed := time.Since(start) fmt.Printf("Took %v to store %d\n", elapsed, num) fmt.Printf("%.0f msgs/sec\n", float64(num)/elapsed.Seconds()) // Now keep running for 2x longer knowing we are expiring messages in the background. // We want to see the effect on performance. start = time.Now() timeout = start.Add(maxAge * 2) for time.Now().Before(timeout) { // We will store in blocks of 100. for i := 0; i < 100; i++ { _, _, err := fs.StoreMsg(subj, nil, []byte("Hello World")) require_NoError(t, err) num++ } } elapsed = time.Since(start) fmt.Printf("Took %v to store %d\n", elapsed, num) fmt.Printf("%.0f msgs/sec\n", float64(num)/elapsed.Seconds()) } // SequenceSet memory tests vs dmaps. func TestNoRaceSeqSetSizeComparison(t *testing.T) { // Create 5M random entries (dupes possible but ok for this test) out of 8M range. num := 5_000_000 max := 7_000_000 seqs := make([]uint64, 0, num) for i := 0; i < num; i++ { n := uint64(rand.Int63n(int64(max + 1))) seqs = append(seqs, n) } runtime.GC() // Disable to get stable results. gcp := debug.SetGCPercent(-1) defer debug.SetGCPercent(gcp) mem := runtime.MemStats{} runtime.ReadMemStats(&mem) inUseBefore := mem.HeapInuse dmap := make(map[uint64]struct{}, num) for _, n := range seqs { dmap[n] = struct{}{} } runtime.ReadMemStats(&mem) dmapUse := mem.HeapInuse - inUseBefore inUseBefore = mem.HeapInuse // Now do SequenceSet on same dataset. var sset avl.SequenceSet for _, n := range seqs { sset.Insert(n) } runtime.ReadMemStats(&mem) seqSetUse := mem.HeapInuse - inUseBefore if seqSetUse > 2*1024*1024 { t.Fatalf("Expected SequenceSet size to be < 2M, got %v", friendlyBytes(int64(seqSetUse))) } if seqSetUse*50 > dmapUse { t.Fatalf("Expected SequenceSet to be at least 50x better then dmap approach: %v vs %v", friendlyBytes(int64(seqSetUse)), friendlyBytes(int64(dmapUse)), ) } } // FilteredState for ">" with large interior deletes was very slow. func TestNoRaceFileStoreFilteredStateWithLargeDeletes(t *testing.T) { storeDir := t.TempDir() fs, err := newFileStore( FileStoreConfig{StoreDir: storeDir, BlockSize: 4096}, StreamConfig{Name: "zzz", Subjects: []string{"foo"}, Storage: FileStorage}, ) require_NoError(t, err) defer fs.Stop() subj, msg := "foo", []byte("Hello World") toStore := 500_000 for i := 0; i < toStore; i++ { _, _, err := fs.StoreMsg(subj, nil, msg) require_NoError(t, err) } // Now delete every other one. for seq := 2; seq <= toStore; seq += 2 { _, err := fs.RemoveMsg(uint64(seq)) require_NoError(t, err) } runtime.GC() // Disable to get stable results. gcp := debug.SetGCPercent(-1) defer debug.SetGCPercent(gcp) start := time.Now() fss := fs.FilteredState(1, _EMPTY_) elapsed := time.Since(start) require_True(t, fss.Msgs == uint64(toStore/2)) require_True(t, elapsed < 500*time.Microsecond) } // ConsumerInfo seems to being called quite a bit more than we had anticipated. // Under certain circumstances, since we reset num pending, this can be very costly. // We will use the fast path to alleviate that performance bottleneck but also make // sure we are still being accurate. func TestNoRaceJetStreamClusterConsumerInfoSpeed(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() c.waitOnLeader() server := c.randomNonLeader() nc, js := jsClientConnect(t, server) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"events.>"}, Replicas: 3, }) require_NoError(t, err) // The issue is compounded when we have lots of different subjects captured // by a terminal fwc. The consumer will have a terminal pwc. // Here make all subjects unique. sub, err := js.PullSubscribe("events.*", "DLC") require_NoError(t, err) toSend := 250_000 for i := 0; i < toSend; i++ { subj := fmt.Sprintf("events.%d", i+1) js.PublishAsync(subj, []byte("ok")) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } checkNumPending := func(expected int) { t.Helper() start := time.Now() ci, err := js.ConsumerInfo("TEST", "DLC") require_NoError(t, err) // Make sure these are fast now. if elapsed := time.Since(start); elapsed > 5*time.Millisecond { t.Fatalf("ConsumerInfo took too long: %v", elapsed) } // Make sure pending == expected. if ci.NumPending != uint64(expected) { t.Fatalf("Expected %d NumPending, got %d", expected, ci.NumPending) } } // Make sure in simple case it is correct. checkNumPending(toSend) // Do a few acks. toAck := 25 for _, m := range fetchMsgs(t, sub, 25, time.Second) { err = m.AckSync() require_NoError(t, err) } checkNumPending(toSend - toAck) // Now do a purge such that we only keep so many. // We want to make sure we do the right thing here and have correct calculations. toKeep := 100_000 err = js.PurgeStream("TEST", &nats.StreamPurgeRequest{Keep: uint64(toKeep)}) require_NoError(t, err) checkNumPending(toKeep) } func TestNoRaceJetStreamKVAccountWithServerRestarts(t *testing.T) { // Uncomment to run. Needs fast machine to not time out on KeyValue lookup. skip(t) c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() _, err := js.CreateKeyValue(&nats.KeyValueConfig{ Bucket: "TEST", Replicas: 3, }) require_NoError(t, err) npubs := 10_000 par := 8 iter := 2 nsubjs := 250 wg := sync.WaitGroup{} putKeys := func() { wg.Add(1) go func() { defer wg.Done() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() kv, err := js.KeyValue("TEST") require_NoError(t, err) for i := 0; i < npubs; i++ { subj := fmt.Sprintf("KEY-%d", rand.Intn(nsubjs)) if _, err := kv.PutString(subj, "hello"); err != nil { nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() kv, err = js.KeyValue("TEST") require_NoError(t, err) } } }() } restartServers := func() { time.Sleep(2 * time.Second) // Rotate through and restart the servers. for _, server := range c.servers { server.Shutdown() restarted := c.restartServer(server) checkFor(t, time.Second, 200*time.Millisecond, func() error { hs := restarted.healthz(&HealthzOptions{ JSEnabled: true, JSServerOnly: true, }) if hs.Error != _EMPTY_ { return errors.New(hs.Error) } return nil }) } c.waitOnLeader() c.waitOnStreamLeader(globalAccountName, "KV_TEST") } for n := 0; n < iter; n++ { for i := 0; i < par; i++ { putKeys() } restartServers() } wg.Wait() nc, js = jsClientConnect(t, c.randomServer()) defer nc.Close() si, err := js.StreamInfo("KV_TEST") require_NoError(t, err) require_True(t, si.State.NumSubjects == uint64(nsubjs)) } // Test for consumer create when the subject cardinality is high and the // consumer is filtered with a wildcard that forces linear scans. // We have an optimization to use in memory structures in filestore to speed up. // Only if asking to scan all (DeliverAll). func TestNoRaceJetStreamConsumerCreateTimeNumPending(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"events.>"}, }) require_NoError(t, err) n := 500_000 msg := bytes.Repeat([]byte("X"), 8*1024) for i := 0; i < n; i++ { subj := fmt.Sprintf("events.%d", rand.Intn(100_000)) js.PublishAsync(subj, msg) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): } // Should stay under 5ms now, but for Travis variability say 50ms. threshold := 50 * time.Millisecond start := time.Now() _, err = js.PullSubscribe("events.*", "dlc") require_NoError(t, err) if elapsed := time.Since(start); elapsed > threshold { t.Fatalf("Consumer create took longer than expected, %v vs %v", elapsed, threshold) } start = time.Now() _, err = js.PullSubscribe("events.99999", "xxx") require_NoError(t, err) if elapsed := time.Since(start); elapsed > threshold { t.Fatalf("Consumer create took longer than expected, %v vs %v", elapsed, threshold) } start = time.Now() _, err = js.PullSubscribe(">", "zzz") require_NoError(t, err) if elapsed := time.Since(start); elapsed > threshold { t.Fatalf("Consumer create took longer than expected, %v vs %v", elapsed, threshold) } } func TestNoRaceJetStreamClusterGhostConsumers(t *testing.T) { c := createJetStreamClusterExplicit(t, "GHOST", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"events.>"}, Replicas: 3, }) require_NoError(t, err) for i := 0; i < 10; i++ { for j := 0; j < 10; j++ { require_NoError(t, nc.Publish(fmt.Sprintf("events.%d.%d", i, j), []byte(`test`))) } } fetch := func(id int) { subject := fmt.Sprintf("events.%d.*", id) subscription, err := js.PullSubscribe(subject, _EMPTY_, // ephemeral consumer nats.DeliverAll(), nats.ReplayInstant(), nats.BindStream("TEST"), nats.ConsumerReplicas(1), nats.ConsumerMemoryStorage(), ) if err != nil { return } defer subscription.Unsubscribe() info, err := subscription.ConsumerInfo() if err != nil { return } subscription.Fetch(int(info.NumPending)) } replay := func(ctx context.Context, id int) { for { select { case <-ctx.Done(): return default: fetch(id) } } } ctx, cancel := context.WithCancel(context.Background()) go replay(ctx, 0) go replay(ctx, 1) go replay(ctx, 2) go replay(ctx, 3) go replay(ctx, 4) go replay(ctx, 5) go replay(ctx, 6) go replay(ctx, 7) go replay(ctx, 8) go replay(ctx, 9) time.Sleep(5 * time.Second) for _, server := range c.servers { server.Shutdown() restarted := c.restartServer(server) checkFor(t, time.Second, 200*time.Millisecond, func() error { hs := restarted.healthz(&HealthzOptions{ JSEnabled: true, JSServerOnly: true, }) if hs.Error != _EMPTY_ { return errors.New(hs.Error) } return nil }) c.waitOnStreamLeader(globalAccountName, "TEST") time.Sleep(time.Second * 2) go replay(ctx, 5) go replay(ctx, 6) go replay(ctx, 7) go replay(ctx, 8) go replay(ctx, 9) } time.Sleep(5 * time.Second) cancel() getMissing := func() []string { m, err := nc.Request("$JS.API.CONSUMER.LIST.TEST", nil, time.Second*10) require_NoError(t, err) var resp JSApiConsumerListResponse err = json.Unmarshal(m.Data, &resp) require_NoError(t, err) return resp.Missing } checkFor(t, 10*time.Second, 500*time.Millisecond, func() error { missing := getMissing() if len(missing) == 0 { return nil } return fmt.Errorf("Still have missing: %+v", missing) }) } // This is to test a publish slowdown and general instability experienced in a setup simular to this. // We have feeder streams that are all sourced to an aggregate stream. All streams are interest retention. // We want to monitor the avg publish time for the sync publishers to the feeder streams, the ingest rate to // the aggregate stream, and general health of the consumers on the aggregate stream. // Target publish rate is ~2k/s with publish time being ~40-60ms but remaining stable. // We can also simulate max redeliveries that create interior deletes in streams. func TestNoRaceJetStreamClusterF3Setup(t *testing.T) { // Uncomment to run. Needs to be on a pretty big machine. Do not want as part of Travis tests atm. skip(t) // These and the settings below achieve ~60ms pub time on avg and ~2k msgs per sec inbound to the aggregate stream. // On my machine though. np := clusterProxy{ rtt: 2 * time.Millisecond, up: 1 * 1024 * 1024 * 1024, // 1gbit down: 1 * 1024 * 1024 * 1024, // 1gbit } // Test params. numSourceStreams := 20 numConsumersPerSource := 1 numPullersPerConsumer := 50 numPublishers := 100 setHighStartSequence := false simulateMaxRedeliveries := false maxBadPubTimes := uint32(20) badPubThresh := 500 * time.Millisecond testTime := 5 * time.Minute // make sure to do --timeout=65m t.Logf("Starting Test: Total Test Time %v", testTime) c := createJetStreamClusterWithNetProxy(t, "R3S", 3, &np) defer c.shutdown() // Do some quick sanity checking for latency stuff. { nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Replicas: 3, Subjects: []string{"foo"}, Retention: nats.InterestPolicy, }) require_NoError(t, err) defer js.DeleteStream("TEST") sl := c.streamLeader(globalAccountName, "TEST") nc, js = jsClientConnect(t, sl) defer nc.Close() start := time.Now() _, err = js.Publish("foo", []byte("hello")) require_NoError(t, err) // This is best case, and with client connection being close to free, this should be at least > rtt if elapsed := time.Since(start); elapsed < np.rtt { t.Fatalf("Expected publish time to be > %v, got %v", np.rtt, elapsed) } nl := c.randomNonStreamLeader(globalAccountName, "TEST") nc, js = jsClientConnect(t, nl) defer nc.Close() start = time.Now() _, err = js.Publish("foo", []byte("hello")) require_NoError(t, err) // This is worst case, meaning message has to travel to leader, then to fastest replica, then back. // So should be at 3x rtt, so check at least > 2x rtt. if elapsed := time.Since(start); elapsed < 2*np.rtt { t.Fatalf("Expected publish time to be > %v, got %v", 2*np.rtt, elapsed) } } // Setup source streams. nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() t.Logf("Creating %d Source Streams", numSourceStreams) var sources []string wg := sync.WaitGroup{} for i := 0; i < numSourceStreams; i++ { sname := fmt.Sprintf("EVENT-%s", nuid.Next()) sources = append(sources, sname) wg.Add(1) go func(stream string) { defer wg.Done() t.Logf(" %q", stream) subj := fmt.Sprintf("%s.>", stream) _, err := js.AddStream(&nats.StreamConfig{ Name: stream, Subjects: []string{subj}, Replicas: 3, Retention: nats.InterestPolicy, }) require_NoError(t, err) for j := 0; j < numConsumersPerSource; j++ { consumer := fmt.Sprintf("C%d", j) _, err := js.Subscribe(_EMPTY_, func(msg *nats.Msg) { msg.Ack() }, nats.BindStream(stream), nats.Durable(consumer), nats.ManualAck()) require_NoError(t, err) } }(sname) } wg.Wait() var streamSources []*nats.StreamSource for _, src := range sources { streamSources = append(streamSources, &nats.StreamSource{Name: src}) } t.Log("Creating Aggregate Stream") // Now create the aggregate stream. _, err := js.AddStream(&nats.StreamConfig{ Name: "EVENTS", Replicas: 3, Retention: nats.InterestPolicy, Sources: streamSources, }) require_NoError(t, err) // Set first sequence to a high number. if setHighStartSequence { require_NoError(t, js.PurgeStream("EVENTS", &nats.StreamPurgeRequest{Sequence: 32_000_001})) } // Now create 2 pull consumers. _, err = js.PullSubscribe(_EMPTY_, "C1", nats.BindStream("EVENTS"), nats.MaxDeliver(1), nats.AckWait(10*time.Second), nats.ManualAck(), ) require_NoError(t, err) _, err = js.PullSubscribe(_EMPTY_, "C2", nats.BindStream("EVENTS"), nats.MaxDeliver(1), nats.AckWait(10*time.Second), nats.ManualAck(), ) require_NoError(t, err) t.Logf("Creating %d x 2 Pull Subscribers", numPullersPerConsumer) // Now create the pullers. for _, subName := range []string{"C1", "C2"} { for i := 0; i < numPullersPerConsumer; i++ { go func(subName string) { nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() sub, err := js.PullSubscribe(_EMPTY_, subName, nats.BindStream("EVENTS"), nats.MaxDeliver(1), nats.AckWait(10*time.Second), nats.ManualAck(), ) require_NoError(t, err) for { msgs, err := sub.Fetch(25, nats.MaxWait(2*time.Second)) if err != nil && err != nats.ErrTimeout { t.Logf("Exiting pull subscriber %q: %v", subName, err) return } // Shuffle rand.Shuffle(len(msgs), func(i, j int) { msgs[i], msgs[j] = msgs[j], msgs[i] }) // Wait for a random interval up to 100ms. time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) for _, m := range msgs { // If we want to simulate max redeliveries being hit, since not acking // once will cause it due to subscriber setup. // 100_000 == 0.01% if simulateMaxRedeliveries && rand.Intn(100_000) == 0 { md, err := m.Metadata() require_NoError(t, err) t.Logf("** Skipping Ack: %d **", md.Sequence.Stream) } else { m.Ack() } } } }(subName) } } // Now create feeder publishers. eventTypes := []string{"PAYMENT", "SUBMISSION", "CANCEL"} msg := make([]byte, 2*1024) // 2k payload crand.Read(msg) // For tracking pub times. var pubs int var totalPubTime time.Duration var pmu sync.Mutex last := time.Now() updatePubStats := func(elapsed time.Duration) { pmu.Lock() defer pmu.Unlock() // Reset every 5s if time.Since(last) > 5*time.Second { pubs = 0 totalPubTime = 0 last = time.Now() } pubs++ totalPubTime += elapsed } avgPubTime := func() time.Duration { pmu.Lock() np := pubs tpt := totalPubTime pmu.Unlock() return tpt / time.Duration(np) } t.Logf("Creating %d Publishers", numPublishers) var numLimitsExceeded atomic.Uint32 errCh := make(chan error, 100) for i := 0; i < numPublishers; i++ { go func() { nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() for { // Grab a random source stream stream := sources[rand.Intn(len(sources))] // Grab random event type. evt := eventTypes[rand.Intn(len(eventTypes))] subj := fmt.Sprintf("%s.%s", stream, evt) start := time.Now() _, err := js.Publish(subj, msg) if err != nil { t.Logf("Exiting publisher: %v", err) return } elapsed := time.Since(start) if elapsed > badPubThresh { t.Logf("Publish time took more than expected: %v", elapsed) numLimitsExceeded.Add(1) if ne := numLimitsExceeded.Load(); ne > maxBadPubTimes { errCh <- fmt.Errorf("Too many exceeded times on publish: %d", ne) return } } updatePubStats(elapsed) } }() } t.Log("Creating Monitoring Routine - Data in ~10s") // Create monitoring routine. go func() { nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() fseq, lseq := uint64(0), uint64(0) for { // Grab consumers var minAckFloor uint64 = math.MaxUint64 for _, consumer := range []string{"C1", "C2"} { ci, err := js.ConsumerInfo("EVENTS", consumer) if err != nil { t.Logf("Exiting Monitor: %v", err) return } if lseq > 0 { t.Logf("%s:\n Delivered:\t%d\n AckFloor:\t%d\n AckPending:\t%d\n NumPending:\t%d", consumer, ci.Delivered.Stream, ci.AckFloor.Stream, ci.NumAckPending, ci.NumPending) } if ci.AckFloor.Stream < minAckFloor { minAckFloor = ci.AckFloor.Stream } } // Now grab aggregate stream state. si, err := js.StreamInfo("EVENTS") if err != nil { t.Logf("Exiting Monitor: %v", err) return } state := si.State if lseq != 0 { t.Logf("Stream:\n Msgs: \t%d\n First:\t%d\n Last: \t%d\n Deletes:\t%d\n", state.Msgs, state.FirstSeq, state.LastSeq, state.NumDeleted) t.Logf("Publish Stats:\n Msgs/s:\t%0.2f\n Avg Pub:\t%v\n\n", float64(si.State.LastSeq-lseq)/5.0, avgPubTime()) if si.State.FirstSeq < minAckFloor && si.State.FirstSeq == fseq { t.Log("Stream first seq < minimum ack floor") } } fseq, lseq = si.State.FirstSeq, si.State.LastSeq time.Sleep(5 * time.Second) } }() select { case e := <-errCh: t.Fatal(e) case <-time.After(testTime): t.Fatalf("Did not receive completion signal") } } // Unbalanced stretch cluster. // S2 (stream leader) will have a slow path to S1 (via proxy) and S3 (consumer leader) will have a fast path. // // Route Ports // "S1": 14622 // "S2": 15622 // "S3": 16622 func createStretchUnbalancedCluster(t testing.TB) (c *cluster, np *netProxy) { t.Helper() tmpl := ` listen: 127.0.0.1:-1 server_name: %s jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} cluster { name: "F3" listen: 127.0.0.1:%d routes = [%s] } accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } ` // Do these in order, S1, S2 (proxy) then S3. c = &cluster{t: t, servers: make([]*Server, 3), opts: make([]*Options, 3), name: "F3"} // S1 conf := fmt.Sprintf(tmpl, "S1", t.TempDir(), 14622, "route://127.0.0.1:15622, route://127.0.0.1:16622") c.servers[0], c.opts[0] = RunServerWithConfig(createConfFile(t, []byte(conf))) // S2 // Create the proxy first. Connect this to S1. Make it slow, e.g. 5ms RTT. np = createNetProxy(1*time.Millisecond, 1024*1024*1024, 1024*1024*1024, "route://127.0.0.1:14622", true) routes := fmt.Sprintf("%s, route://127.0.0.1:16622", np.routeURL()) conf = fmt.Sprintf(tmpl, "S2", t.TempDir(), 15622, routes) c.servers[1], c.opts[1] = RunServerWithConfig(createConfFile(t, []byte(conf))) // S3 conf = fmt.Sprintf(tmpl, "S3", t.TempDir(), 16622, "route://127.0.0.1:14622, route://127.0.0.1:15622") c.servers[2], c.opts[2] = RunServerWithConfig(createConfFile(t, []byte(conf))) c.checkClusterFormed() c.waitOnClusterReady() return c, np } // We test an interest based stream that has a cluster with a node with asymmetric paths from // the stream leader and the consumer leader such that the consumer leader path is fast and // replicated acks arrive sooner then the actual message. This path was considered, but also // categorized as very rare and was expensive as it tried to forward a new stream msg delete // proposal to the original stream leader. It now will deal with the issue locally and not // slow down the ingest rate to the stream's publishers. func TestNoRaceJetStreamClusterDifferentRTTInterestBasedStreamSetup(t *testing.T) { // Uncomment to run. Do not want as part of Travis tests atm. skip(t) c, np := createStretchUnbalancedCluster(t) defer c.shutdown() defer np.stop() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() // Now create the stream. _, err := js.AddStream(&nats.StreamConfig{ Name: "EVENTS", Subjects: []string{"EV.>"}, Replicas: 3, Retention: nats.InterestPolicy, }) require_NoError(t, err) // Make sure it's leader is on S2. sl := c.servers[1] checkFor(t, 20*time.Second, 200*time.Millisecond, func() error { c.waitOnStreamLeader(globalAccountName, "EVENTS") if s := c.streamLeader(globalAccountName, "EVENTS"); s != sl { s.JetStreamStepdownStream(globalAccountName, "EVENTS") return fmt.Errorf("Server %s is not stream leader yet", sl) } return nil }) // Now create the consumer. _, err = js.PullSubscribe(_EMPTY_, "C", nats.BindStream("EVENTS"), nats.ManualAck()) require_NoError(t, err) // Make sure the consumer leader is on S3. cl := c.servers[2] checkFor(t, 20*time.Second, 200*time.Millisecond, func() error { c.waitOnConsumerLeader(globalAccountName, "EVENTS", "C") if s := c.consumerLeader(globalAccountName, "EVENTS", "C"); s != cl { s.JetStreamStepdownConsumer(globalAccountName, "EVENTS", "C") return fmt.Errorf("Server %s is not consumer leader yet", cl) } return nil }) go func(js nats.JetStream) { sub, err := js.PullSubscribe(_EMPTY_, "C", nats.BindStream("EVENTS"), nats.ManualAck()) require_NoError(t, err) for { msgs, err := sub.Fetch(100, nats.MaxWait(2*time.Second)) if err != nil && err != nats.ErrTimeout { return } // Shuffle rand.Shuffle(len(msgs), func(i, j int) { msgs[i], msgs[j] = msgs[j], msgs[i] }) for _, m := range msgs { m.Ack() } } }(js) numPublishers := 25 pubThresh := 2 * time.Second var maxExceeded atomic.Int64 errCh := make(chan error, numPublishers) wg := sync.WaitGroup{} msg := make([]byte, 2*1024) // 2k payload crand.Read(msg) // Publishers. for i := 0; i < numPublishers; i++ { wg.Add(1) go func(iter int) { defer wg.Done() // Connect to random, the slow ones will be connected to the slow node. // But if you connect them all there it will pass. s := c.randomServer() nc, js := jsClientConnect(t, s) defer nc.Close() for i := 0; i < 1_000; i++ { start := time.Now() _, err := js.Publish("EV.PAID", msg) if err != nil { errCh <- fmt.Errorf("Publish error: %v", err) return } if elapsed := time.Since(start); elapsed > pubThresh { errCh <- fmt.Errorf("Publish time exceeded") if int64(elapsed) > maxExceeded.Load() { maxExceeded.Store(int64(elapsed)) } return } } }(i) } wg.Wait() select { case e := <-errCh: t.Fatalf("%v: threshold is %v, maximum seen: %v", e, pubThresh, time.Duration(maxExceeded.Load())) default: } } func TestNoRaceJetStreamInterestStreamCheckInterestRaceBug(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo"}, Replicas: 3, Retention: nats.InterestPolicy, }) require_NoError(t, err) numConsumers := 10 for i := 0; i < numConsumers; i++ { nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() _, err = js.Subscribe("foo", func(m *nats.Msg) { m.Ack() }, nats.Durable(fmt.Sprintf("C%d", i)), nats.ManualAck()) require_NoError(t, err) } numToSend := 10_000 for i := 0; i < numToSend; i++ { _, err := js.PublishAsync("foo", nil, nats.StallWait(800*time.Millisecond)) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(20 * time.Second): t.Fatalf("Did not receive completion signal") } // Wait til ackfloor is correct for all consumers. checkFor(t, 20*time.Second, 100*time.Millisecond, func() error { for _, s := range c.servers { mset, err := s.GlobalAccount().lookupStream("TEST") require_NoError(t, err) mset.mu.RLock() defer mset.mu.RUnlock() require_True(t, len(mset.consumers) == numConsumers) for _, o := range mset.consumers { state, err := o.store.State() require_NoError(t, err) if state.AckFloor.Stream != uint64(numToSend) { return fmt.Errorf("Ackfloor not correct yet") } } } return nil }) for _, s := range c.servers { mset, err := s.GlobalAccount().lookupStream("TEST") require_NoError(t, err) mset.mu.RLock() defer mset.mu.RUnlock() state := mset.state() require_True(t, state.Msgs == 0) require_True(t, state.FirstSeq == uint64(numToSend+1)) } } func TestNoRaceJetStreamClusterInterestStreamConsistencyAfterRollingRestart(t *testing.T) { // Uncomment to run. Needs to be on a big machine. Do not want as part of Travis tests atm. skip(t) c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() numStreams := 200 numConsumersPer := 5 numPublishers := 10 nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() qch := make(chan bool) var mm sync.Mutex ackMap := make(map[string]map[uint64][]string) addAckTracking := func(seq uint64, stream, consumer string) { mm.Lock() defer mm.Unlock() sam := ackMap[stream] if sam == nil { sam = make(map[uint64][]string) ackMap[stream] = sam } sam[seq] = append(sam[seq], consumer) } doPullSubscriber := func(stream, consumer, filter string) { nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() var err error var sub *nats.Subscription timeout := time.Now().Add(5 * time.Second) for time.Now().Before(timeout) { sub, err = js.PullSubscribe(filter, consumer, nats.BindStream(stream), nats.ManualAck()) if err == nil { break } } if err != nil { t.Logf("Error on pull subscriber: %v", err) return } for { select { case <-time.After(500 * time.Millisecond): msgs, err := sub.Fetch(100, nats.MaxWait(time.Second)) if err != nil { continue } // Shuffle rand.Shuffle(len(msgs), func(i, j int) { msgs[i], msgs[j] = msgs[j], msgs[i] }) for _, m := range msgs { meta, err := m.Metadata() require_NoError(t, err) m.Ack() addAckTracking(meta.Sequence.Stream, stream, consumer) if meta.NumDelivered > 1 { t.Logf("Got a msg redelivered %d for sequence %d on %q %q\n", meta.NumDelivered, meta.Sequence.Stream, stream, consumer) } } case <-qch: nc.Flush() return } } } // Setup wg := sync.WaitGroup{} for i := 0; i < numStreams; i++ { wg.Add(1) go func(stream string) { defer wg.Done() subj := fmt.Sprintf("%s.>", stream) _, err := js.AddStream(&nats.StreamConfig{ Name: stream, Subjects: []string{subj}, Replicas: 3, Retention: nats.InterestPolicy, }) require_NoError(t, err) for i := 0; i < numConsumersPer; i++ { consumer := fmt.Sprintf("C%d", i) filter := fmt.Sprintf("%s.%d", stream, i) _, err = js.AddConsumer(stream, &nats.ConsumerConfig{ Durable: consumer, FilterSubject: filter, AckPolicy: nats.AckExplicitPolicy, AckWait: 2 * time.Second, }) require_NoError(t, err) c.waitOnConsumerLeader(globalAccountName, stream, consumer) go doPullSubscriber(stream, consumer, filter) } }(fmt.Sprintf("A-%d", i)) } wg.Wait() msg := make([]byte, 2*1024) // 2k payload crand.Read(msg) // Controls if publishing is on or off. var pubActive atomic.Bool doPublish := func() { nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() for { select { case <-time.After(100 * time.Millisecond): if pubActive.Load() { for i := 0; i < numStreams; i++ { for j := 0; j < numConsumersPer; j++ { subj := fmt.Sprintf("A-%d.%d", i, j) // Don't care about errors here for this test. js.Publish(subj, msg) } } } case <-qch: return } } } pubActive.Store(true) for i := 0; i < numPublishers; i++ { go doPublish() } // Let run for a bit. time.Sleep(20 * time.Second) // Do a rolling restart. for _, s := range c.servers { t.Logf("Shutdown %v\n", s) s.Shutdown() s.WaitForShutdown() time.Sleep(20 * time.Second) t.Logf("Restarting %v\n", s) s = c.restartServer(s) c.waitOnServerHealthz(s) } // Let run for a bit longer. time.Sleep(10 * time.Second) // Stop pubs. pubActive.Store(false) // Let settle. time.Sleep(10 * time.Second) close(qch) time.Sleep(20 * time.Second) nc, js = jsClientConnect(t, c.randomServer()) defer nc.Close() minAckFloor := func(stream string) (uint64, string) { var maf uint64 = math.MaxUint64 var consumer string for i := 0; i < numConsumersPer; i++ { cname := fmt.Sprintf("C%d", i) ci, err := js.ConsumerInfo(stream, cname) require_NoError(t, err) if ci.AckFloor.Stream < maf { maf = ci.AckFloor.Stream consumer = cname } } return maf, consumer } checkStreamAcks := func(stream string) { mm.Lock() defer mm.Unlock() if sam := ackMap[stream]; sam != nil { for seq := 1; ; seq++ { acks := sam[uint64(seq)] if acks == nil { if sam[uint64(seq+1)] != nil { t.Logf("Missing an ack on stream %q for sequence %d\n", stream, seq) } else { break } } if len(acks) > 1 { t.Logf("Multiple acks for %d which is not expected: %+v", seq, acks) } } } } // Now check all streams such that their first sequence is equal to the minimum of all consumers. for i := 0; i < numStreams; i++ { stream := fmt.Sprintf("A-%d", i) si, err := js.StreamInfo(stream) require_NoError(t, err) if maf, consumer := minAckFloor(stream); maf > si.State.FirstSeq { t.Logf("\nBAD STATE DETECTED FOR %q, CHECKING OTHER SERVERS! ACK %d vs %+v LEADER %v, CL FOR %q %v\n", stream, maf, si.State, c.streamLeader(globalAccountName, stream), consumer, c.consumerLeader(globalAccountName, stream, consumer)) t.Logf("TEST ACKS %+v\n", ackMap) checkStreamAcks(stream) for _, s := range c.servers { mset, err := s.GlobalAccount().lookupStream(stream) require_NoError(t, err) state := mset.state() t.Logf("Server %v Stream STATE %+v\n", s, state) var smv StoreMsg if sm, err := mset.store.LoadMsg(state.FirstSeq, &smv); err == nil { t.Logf("Subject for msg %d is %q", state.FirstSeq, sm.subj) } else { t.Logf("Could not retrieve msg for %d: %v", state.FirstSeq, err) } if len(mset.preAcks) > 0 { t.Logf("%v preAcks %+v\n", s, mset.preAcks) } for _, o := range mset.consumers { ostate, err := o.store.State() require_NoError(t, err) t.Logf("Consumer STATE for %q is %+v\n", o.name, ostate) } } t.Fatalf("BAD STATE: ACKFLOOR > FIRST %d vs %d\n", maf, si.State.FirstSeq) } } } func TestNoRaceFileStoreNumPending(t *testing.T) { // No need for all permutations here. storeDir := t.TempDir() fcfg := FileStoreConfig{ StoreDir: storeDir, BlockSize: 2 * 1024, // Create many blocks on purpose. } fs, err := newFileStore(fcfg, StreamConfig{Name: "zzz", Subjects: []string{"*.*.*.*"}, Storage: FileStorage}) require_NoError(t, err) defer fs.Stop() tokens := []string{"foo", "bar", "baz"} genSubj := func() string { return fmt.Sprintf("%s.%s.%s.%s", tokens[rand.Intn(len(tokens))], tokens[rand.Intn(len(tokens))], tokens[rand.Intn(len(tokens))], tokens[rand.Intn(len(tokens))], ) } for i := 0; i < 50_000; i++ { subj := genSubj() _, _, err := fs.StoreMsg(subj, nil, []byte("Hello World")) require_NoError(t, err) } state := fs.State() // Scan one by one for sanity check against other calculations. sanityCheck := func(sseq uint64, filter string) SimpleState { t.Helper() var ss SimpleState var smv StoreMsg // For here we know 0 is invalid, set to 1. if sseq == 0 { sseq = 1 } for seq := sseq; seq <= state.LastSeq; seq++ { sm, err := fs.LoadMsg(seq, &smv) if err != nil { t.Logf("Encountered error %v loading sequence: %d", err, seq) continue } if subjectIsSubsetMatch(sm.subj, filter) { ss.Msgs++ ss.Last = seq if ss.First == 0 || seq < ss.First { ss.First = seq } } } return ss } check := func(sseq uint64, filter string) { t.Helper() np, lvs := fs.NumPending(sseq, filter, false) ss := fs.FilteredState(sseq, filter) sss := sanityCheck(sseq, filter) if lvs != state.LastSeq { t.Fatalf("Expected NumPending to return valid through last of %d but got %d", state.LastSeq, lvs) } if ss.Msgs != np { t.Fatalf("NumPending of %d did not match ss.Msgs of %d", np, ss.Msgs) } if ss != sss { t.Fatalf("Failed sanity check, expected %+v got %+v", sss, ss) } } sanityCheckLastOnly := func(sseq uint64, filter string) SimpleState { t.Helper() var ss SimpleState var smv StoreMsg // For here we know 0 is invalid, set to 1. if sseq == 0 { sseq = 1 } seen := make(map[string]bool) for seq := state.LastSeq; seq >= sseq; seq-- { sm, err := fs.LoadMsg(seq, &smv) if err != nil { t.Logf("Encountered error %v loading sequence: %d", err, seq) continue } if !seen[sm.subj] && subjectIsSubsetMatch(sm.subj, filter) { ss.Msgs++ if ss.Last == 0 { ss.Last = seq } if ss.First == 0 || seq < ss.First { ss.First = seq } seen[sm.subj] = true } } return ss } checkLastOnly := func(sseq uint64, filter string) { t.Helper() np, lvs := fs.NumPending(sseq, filter, true) ss := sanityCheckLastOnly(sseq, filter) if lvs != state.LastSeq { t.Fatalf("Expected NumPending to return valid through last of %d but got %d", state.LastSeq, lvs) } if ss.Msgs != np { t.Fatalf("NumPending of %d did not match ss.Msgs of %d", np, ss.Msgs) } } startSeqs := []uint64{0, 1, 2, 200, 444, 555, 2222, 8888, 12_345, 28_222, 33_456, 44_400, 49_999} checkSubs := []string{"foo.>", "*.bar.>", "foo.bar.*.baz", "*.bar.>", "*.foo.bar.*", "foo.foo.bar.baz"} for _, filter := range checkSubs { for _, start := range startSeqs { check(start, filter) checkLastOnly(start, filter) } } } func TestNoRaceJetStreamClusterUnbalancedInterestMultipleConsumers(t *testing.T) { c, np := createStretchUnbalancedCluster(t) defer c.shutdown() defer np.stop() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() // Now create the stream. _, err := js.AddStream(&nats.StreamConfig{ Name: "EVENTS", Subjects: []string{"EV.>"}, Replicas: 3, Retention: nats.InterestPolicy, }) require_NoError(t, err) // Make sure it's leader is on S2. sl := c.servers[1] checkFor(t, 20*time.Second, 200*time.Millisecond, func() error { c.waitOnStreamLeader(globalAccountName, "EVENTS") if s := c.streamLeader(globalAccountName, "EVENTS"); s != sl { s.JetStreamStepdownStream(globalAccountName, "EVENTS") return fmt.Errorf("Server %s is not stream leader yet", sl) } return nil }) // Create a fast ack consumer. _, err = js.Subscribe("EV.NEW", func(m *nats.Msg) { m.Ack() }, nats.Durable("C"), nats.ManualAck()) require_NoError(t, err) // Make sure the consumer leader is on S3. cl := c.servers[2] checkFor(t, 20*time.Second, 200*time.Millisecond, func() error { c.waitOnConsumerLeader(globalAccountName, "EVENTS", "C") if s := c.consumerLeader(globalAccountName, "EVENTS", "C"); s != cl { s.JetStreamStepdownConsumer(globalAccountName, "EVENTS", "C") return fmt.Errorf("Server %s is not consumer leader yet", cl) } return nil }) // Connect a client directly to the stream leader. nc, js = jsClientConnect(t, sl) defer nc.Close() // Now create a pull subscriber. sub, err := js.PullSubscribe("EV.NEW", "D", nats.ManualAck()) require_NoError(t, err) // Make sure this consumer leader is on S1. cl = c.servers[0] checkFor(t, 20*time.Second, 200*time.Millisecond, func() error { c.waitOnConsumerLeader(globalAccountName, "EVENTS", "D") if s := c.consumerLeader(globalAccountName, "EVENTS", "D"); s != cl { s.JetStreamStepdownConsumer(globalAccountName, "EVENTS", "D") return fmt.Errorf("Server %s is not consumer leader yet", cl) } return nil }) numToSend := 1000 for i := 0; i < numToSend; i++ { _, err := js.PublishAsync("EV.NEW", nil) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(20 * time.Second): t.Fatalf("Did not receive completion signal") } // Now make sure we can pull messages since we have not acked. // The bug is that the acks arrive on S1 faster then the messages but we want to // make sure we do not remove prematurely. msgs, err := sub.Fetch(100, nats.MaxWait(time.Second)) require_NoError(t, err) require_True(t, len(msgs) == 100) for _, m := range msgs { m.AckSync() } ci, err := js.ConsumerInfo("EVENTS", "D") require_NoError(t, err) require_True(t, ci.NumPending == uint64(numToSend-100)) require_True(t, ci.NumAckPending == 0) require_True(t, ci.Delivered.Stream == 100) require_True(t, ci.AckFloor.Stream == 100) // Check stream state on all servers. for _, s := range c.servers { mset, err := s.GlobalAccount().lookupStream("EVENTS") require_NoError(t, err) state := mset.state() require_True(t, state.Msgs == 900) require_True(t, state.FirstSeq == 101) require_True(t, state.LastSeq == 1000) require_True(t, state.Consumers == 2) } msgs, err = sub.Fetch(900, nats.MaxWait(time.Second)) require_NoError(t, err) require_True(t, len(msgs) == 900) for _, m := range msgs { m.AckSync() } // Let acks propagate. time.Sleep(250 * time.Millisecond) // Check final stream state on all servers. for _, s := range c.servers { mset, err := s.GlobalAccount().lookupStream("EVENTS") require_NoError(t, err) state := mset.state() require_True(t, state.Msgs == 0) require_True(t, state.FirstSeq == 1001) require_True(t, state.LastSeq == 1000) require_True(t, state.Consumers == 2) // Now check preAcks mset.mu.RLock() numPreAcks := len(mset.preAcks) mset.mu.RUnlock() require_True(t, numPreAcks == 0) } } func TestNoRaceJetStreamClusterUnbalancedInterestMultipleFilteredConsumers(t *testing.T) { c, np := createStretchUnbalancedCluster(t) defer c.shutdown() defer np.stop() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() // Now create the stream. _, err := js.AddStream(&nats.StreamConfig{ Name: "EVENTS", Subjects: []string{"EV.>"}, Replicas: 3, Retention: nats.InterestPolicy, }) require_NoError(t, err) // Make sure it's leader is on S2. sl := c.servers[1] checkFor(t, 20*time.Second, 200*time.Millisecond, func() error { c.waitOnStreamLeader(globalAccountName, "EVENTS") if s := c.streamLeader(globalAccountName, "EVENTS"); s != sl { s.JetStreamStepdownStream(globalAccountName, "EVENTS") return fmt.Errorf("Server %s is not stream leader yet", sl) } return nil }) // Create a fast ack consumer. _, err = js.Subscribe("EV.NEW", func(m *nats.Msg) { m.Ack() }, nats.Durable("C"), nats.ManualAck()) require_NoError(t, err) // Make sure the consumer leader is on S3. cl := c.servers[2] checkFor(t, 20*time.Second, 200*time.Millisecond, func() error { c.waitOnConsumerLeader(globalAccountName, "EVENTS", "C") if s := c.consumerLeader(globalAccountName, "EVENTS", "C"); s != cl { s.JetStreamStepdownConsumer(globalAccountName, "EVENTS", "C") return fmt.Errorf("Server %s is not consumer leader yet", cl) } return nil }) // Connect a client directly to the stream leader. nc, js = jsClientConnect(t, sl) defer nc.Close() // Now create another fast ack consumer. _, err = js.Subscribe("EV.UPDATED", func(m *nats.Msg) { m.Ack() }, nats.Durable("D"), nats.ManualAck()) require_NoError(t, err) // Make sure this consumer leader is on S1. cl = c.servers[0] checkFor(t, 20*time.Second, 200*time.Millisecond, func() error { c.waitOnConsumerLeader(globalAccountName, "EVENTS", "D") if s := c.consumerLeader(globalAccountName, "EVENTS", "D"); s != cl { s.JetStreamStepdownConsumer(globalAccountName, "EVENTS", "D") return fmt.Errorf("Server %s is not consumer leader yet", cl) } return nil }) numToSend := 500 for i := 0; i < numToSend; i++ { _, err := js.PublishAsync("EV.NEW", nil) require_NoError(t, err) _, err = js.PublishAsync("EV.UPDATED", nil) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(20 * time.Second): t.Fatalf("Did not receive completion signal") } // Let acks propagate. time.Sleep(250 * time.Millisecond) ci, err := js.ConsumerInfo("EVENTS", "D") require_NoError(t, err) require_True(t, ci.NumPending == 0) require_True(t, ci.NumAckPending == 0) require_True(t, ci.Delivered.Consumer == 500) require_True(t, ci.Delivered.Stream == 1000) require_True(t, ci.AckFloor.Consumer == 500) require_True(t, ci.AckFloor.Stream == 1000) // Check final stream state on all servers. for _, s := range c.servers { mset, err := s.GlobalAccount().lookupStream("EVENTS") require_NoError(t, err) state := mset.state() require_True(t, state.Msgs == 0) require_True(t, state.FirstSeq == 1001) require_True(t, state.LastSeq == 1000) require_True(t, state.Consumers == 2) // Now check preAcks mset.mu.RLock() numPreAcks := len(mset.preAcks) mset.mu.RUnlock() require_True(t, numPreAcks == 0) } } func TestNoRaceParallelStreamAndConsumerCreation(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() // stream config. scfg := &StreamConfig{ Name: "TEST", Subjects: []string{"foo", "bar"}, MaxMsgs: 10, Storage: FileStorage, Replicas: 1, } // Will do these direct against the low level API to really make // sure parallel creation ok. np := 1000 startCh := make(chan bool) errCh := make(chan error, np) wg := sync.WaitGroup{} wg.Add(np) var streams sync.Map for i := 0; i < np; i++ { go func() { defer wg.Done() // Make them all fire at once. <-startCh if mset, err := s.GlobalAccount().addStream(scfg); err != nil { t.Logf("Stream create got an error: %v", err) errCh <- err } else { streams.Store(mset, true) } }() } time.Sleep(100 * time.Millisecond) close(startCh) wg.Wait() // Check for no errors. if len(errCh) > 0 { t.Fatalf("Expected no errors, got %d", len(errCh)) } // Now make sure we really only created one stream. var numStreams int streams.Range(func(k, v any) bool { numStreams++ return true }) if numStreams > 1 { t.Fatalf("Expected only one stream to be really created, got %d out of %d attempts", numStreams, np) } // Also make sure we cleanup the inflight entries for streams. gacc := s.GlobalAccount() _, jsa, err := gacc.checkForJetStream() require_NoError(t, err) var numEntries int jsa.inflight.Range(func(k, v any) bool { numEntries++ return true }) if numEntries > 0 { t.Fatalf("Expected no inflight entries to be left over, got %d", numEntries) } // Now do consumers. mset, err := gacc.lookupStream("TEST") require_NoError(t, err) cfg := &ConsumerConfig{ DeliverSubject: "to", Name: "DLC", AckPolicy: AckExplicit, } startCh = make(chan bool) errCh = make(chan error, np) wg.Add(np) var consumers sync.Map for i := 0; i < np; i++ { go func() { defer wg.Done() // Make them all fire at once. <-startCh if _, err = mset.addConsumer(cfg); err != nil { t.Logf("Consumer create got an error: %v", err) errCh <- err } else { consumers.Store(mset, true) } }() } time.Sleep(100 * time.Millisecond) close(startCh) wg.Wait() // Check for no errors. if len(errCh) > 0 { t.Fatalf("Expected no errors, got %d", len(errCh)) } // Now make sure we really only created one stream. var numConsumers int consumers.Range(func(k, v any) bool { numConsumers++ return true }) if numConsumers > 1 { t.Fatalf("Expected only one consumer to be really created, got %d out of %d attempts", numConsumers, np) } } func TestNoRaceRoutePool(t *testing.T) { var dur1 time.Duration var dur2 time.Duration total := 1_000_000 for _, test := range []struct { name string poolSize int }{ {"no pooling", 0}, {"pooling", 5}, } { t.Run(test.name, func(t *testing.T) { tmpl := ` port: -1 accounts { A { users: [{user: "A", password: "A"}] } B { users: [{user: "B", password: "B"}] } C { users: [{user: "C", password: "C"}] } D { users: [{user: "D", password: "D"}] } E { users: [{user: "E", password: "E"}] } } cluster { port: -1 name: "local" %s pool_size: %d } ` conf1 := createConfFile(t, []byte(fmt.Sprintf(tmpl, _EMPTY_, test.poolSize))) s1, o1 := RunServerWithConfig(conf1) defer s1.Shutdown() conf2 := createConfFile(t, []byte(fmt.Sprintf(tmpl, fmt.Sprintf("routes: [\"nats://127.0.0.1:%d\"]", o1.Cluster.Port), test.poolSize))) s2, _ := RunServerWithConfig(conf2) defer s2.Shutdown() checkClusterFormed(t, s1, s2) wg := sync.WaitGroup{} wg.Add(5) sendAndRecv := func(acc string) (*nats.Conn, *nats.Conn) { t.Helper() s2nc := natsConnect(t, s2.ClientURL(), nats.UserInfo(acc, acc)) count := 0 natsSub(t, s2nc, "foo", func(_ *nats.Msg) { if count++; count == total { wg.Done() } }) natsFlush(t, s2nc) s1nc := natsConnect(t, s1.ClientURL(), nats.UserInfo(acc, acc)) checkSubInterest(t, s1, acc, "foo", time.Second) return s2nc, s1nc } var rcv = [5]*nats.Conn{} var snd = [5]*nats.Conn{} accs := []string{"A", "B", "C", "D", "E"} for i := 0; i < 5; i++ { rcv[i], snd[i] = sendAndRecv(accs[i]) defer rcv[i].Close() defer snd[i].Close() } payload := []byte("some message") start := time.Now() for i := 0; i < 5; i++ { go func(idx int) { for i := 0; i < total; i++ { snd[idx].Publish("foo", payload) } }(i) } wg.Wait() dur := time.Since(start) if test.poolSize == 0 { dur1 = dur } else { dur2 = dur } }) } perf1 := float64(total*5) / dur1.Seconds() t.Logf("No pooling: %.0f msgs/sec", perf1) perf2 := float64(total*5) / dur2.Seconds() t.Logf("Pooling : %.0f msgs/sec", perf2) t.Logf("Gain : %.2fx", perf2/perf1) } func TestNoRaceRoutePerAccount(t *testing.T) { var dur1 time.Duration var dur2 time.Duration accounts := make([]string, 5) for i := 0; i < 5; i++ { akp, _ := nkeys.CreateAccount() pub, _ := akp.PublicKey() accounts[i] = pub } routeAccs := fmt.Sprintf("accounts: [\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"]", accounts[0], accounts[1], accounts[2], accounts[3], accounts[4]) total := 1_000_000 for _, test := range []struct { name string dedicated bool }{ {"route for all accounts", false}, {"route per account", true}, } { t.Run(test.name, func(t *testing.T) { tmpl := ` port: -1 accounts { %s { users: [{user: "0", password: "0"}] } %s { users: [{user: "1", password: "1"}] } %s { users: [{user: "2", password: "2"}] } %s { users: [{user: "3", password: "3"}] } %s { users: [{user: "4", password: "4"}] } } cluster { port: -1 name: "local" %s %s } ` var racc string if test.dedicated { racc = routeAccs } else { racc = _EMPTY_ } conf1 := createConfFile(t, []byte(fmt.Sprintf(tmpl, accounts[0], accounts[1], accounts[2], accounts[3], accounts[4], _EMPTY_, racc))) s1, o1 := RunServerWithConfig(conf1) defer s1.Shutdown() conf2 := createConfFile(t, []byte(fmt.Sprintf(tmpl, accounts[0], accounts[1], accounts[2], accounts[3], accounts[4], fmt.Sprintf("routes: [\"nats://127.0.0.1:%d\"]", o1.Cluster.Port), racc))) s2, _ := RunServerWithConfig(conf2) defer s2.Shutdown() checkClusterFormed(t, s1, s2) wg := sync.WaitGroup{} wg.Add(5) sendAndRecv := func(acc string, user string) (*nats.Conn, *nats.Conn) { t.Helper() s2nc := natsConnect(t, s2.ClientURL(), nats.UserInfo(user, user)) count := 0 natsSub(t, s2nc, "foo", func(_ *nats.Msg) { if count++; count == total { wg.Done() } }) natsFlush(t, s2nc) s1nc := natsConnect(t, s1.ClientURL(), nats.UserInfo(user, user)) checkSubInterest(t, s1, acc, "foo", time.Second) return s2nc, s1nc } var rcv = [5]*nats.Conn{} var snd = [5]*nats.Conn{} users := []string{"0", "1", "2", "3", "4"} for i := 0; i < 5; i++ { rcv[i], snd[i] = sendAndRecv(accounts[i], users[i]) defer rcv[i].Close() defer snd[i].Close() } payload := []byte("some message") start := time.Now() for i := 0; i < 5; i++ { go func(idx int) { for i := 0; i < total; i++ { snd[idx].Publish("foo", payload) } }(i) } wg.Wait() dur := time.Since(start) if !test.dedicated { dur1 = dur } else { dur2 = dur } }) } perf1 := float64(total*5) / dur1.Seconds() t.Logf("Route for all accounts: %.0f msgs/sec", perf1) perf2 := float64(total*5) / dur2.Seconds() t.Logf("Route per account : %.0f msgs/sec", perf2) t.Logf("Gain : %.2fx", perf2/perf1) } // This test, which checks that messages are not duplicated when pooling or // per-account routes are reloaded, would cause a DATA RACE that is not // specific to the changes for pooling/per_account. For this reason, this // test is located in the norace_test.go file. func TestNoRaceRoutePoolAndPerAccountConfigReload(t *testing.T) { for _, test := range []struct { name string poolSizeBefore string poolSizeAfter string accountsBefore string accountsAfter string }{ {"from no pool to pool", _EMPTY_, "pool_size: 2", _EMPTY_, _EMPTY_}, {"increase pool size", "pool_size: 2", "pool_size: 5", _EMPTY_, _EMPTY_}, {"decrease pool size", "pool_size: 5", "pool_size: 2", _EMPTY_, _EMPTY_}, {"from pool to no pool", "pool_size: 5", _EMPTY_, _EMPTY_, _EMPTY_}, {"from no account to account", _EMPTY_, _EMPTY_, _EMPTY_, "accounts: [\"A\"]"}, {"add account", _EMPTY_, _EMPTY_, "accounts: [\"B\"]", "accounts: [\"A\",\"B\"]"}, {"remove account", _EMPTY_, _EMPTY_, "accounts: [\"A\",\"B\"]", "accounts: [\"B\"]"}, {"from account to no account", _EMPTY_, _EMPTY_, "accounts: [\"A\"]", _EMPTY_}, {"increase pool size and add account", "pool_size: 2", "pool_size: 3", "accounts: [\"B\"]", "accounts: [\"B\",\"A\"]"}, {"decrease pool size and remove account", "pool_size: 3", "pool_size: 2", "accounts: [\"A\",\"B\"]", "accounts: [\"B\"]"}, } { t.Run(test.name, func(t *testing.T) { tmplA := ` port: -1 server_name: "A" accounts { A { users: [{user: a, password: pwd}] } B { users: [{user: b, password: pwd}] } } cluster: { port: -1 name: "local" %s %s } ` confA := createConfFile(t, []byte(fmt.Sprintf(tmplA, test.poolSizeBefore, test.accountsBefore))) srva, optsA := RunServerWithConfig(confA) defer srva.Shutdown() tmplB := ` port: -1 server_name: "B" accounts { A { users: [{user: a, password: pwd}] } B { users: [{user: b, password: pwd}] } } cluster: { port: -1 name: "local" %s %s routes: ["nats://127.0.0.1:%d"] } ` confB := createConfFile(t, []byte(fmt.Sprintf(tmplB, test.poolSizeBefore, test.accountsBefore, optsA.Cluster.Port))) srvb, _ := RunServerWithConfig(confB) defer srvb.Shutdown() checkClusterFormed(t, srva, srvb) ncA := natsConnect(t, srva.ClientURL(), nats.UserInfo("a", "pwd")) defer ncA.Close() sub := natsSubSync(t, ncA, "foo") sub.SetPendingLimits(-1, -1) checkSubInterest(t, srvb, "A", "foo", time.Second) ncB := natsConnect(t, srvb.ClientURL(), nats.UserInfo("a", "pwd")) defer ncB.Close() wg := sync.WaitGroup{} wg.Add(1) ch := make(chan struct{}) go func() { defer wg.Done() for i := 0; ; i++ { ncB.Publish("foo", []byte(fmt.Sprintf("%d", i))) select { case <-ch: return default: } if i%300 == 0 { time.Sleep(time.Duration(rand.Intn(5)) * time.Millisecond) } } }() var l *captureErrorLogger if test.accountsBefore != _EMPTY_ && test.accountsAfter == _EMPTY_ { l = &captureErrorLogger{errCh: make(chan string, 100)} srva.SetLogger(l, false, false) } time.Sleep(250 * time.Millisecond) reloadUpdateConfig(t, srva, confA, fmt.Sprintf(tmplA, test.poolSizeAfter, test.accountsAfter)) time.Sleep(125 * time.Millisecond) reloadUpdateConfig(t, srvb, confB, fmt.Sprintf(tmplB, test.poolSizeAfter, test.accountsAfter, optsA.Cluster.Port)) checkClusterFormed(t, srva, srvb) checkSubInterest(t, srvb, "A", "foo", time.Second) if l != nil { // Errors regarding "No route for account" should stop var ok bool for numErrs := 0; !ok && numErrs < 10; { select { case e := <-l.errCh: if strings.Contains(e, "No route for account") { numErrs++ } case <-time.After(DEFAULT_ROUTE_RECONNECT + 250*time.Millisecond): ok = true } } if !ok { t.Fatalf("Still report of no route for account") } } close(ch) wg.Wait() for prev := -1; ; { msg, err := sub.NextMsg(50 * time.Millisecond) if err != nil { break } cur, _ := strconv.Atoi(string(msg.Data)) if cur <= prev { t.Fatalf("Previous was %d, got %d", prev, cur) } prev = cur } }) } } // This test ensures that outbound queues don't cause a run on // memory when sending something to lots of clients. func TestNoRaceClientOutboundQueueMemory(t *testing.T) { opts := DefaultOptions() s := RunServer(opts) defer s.Shutdown() var before runtime.MemStats var after runtime.MemStats var err error clients := make([]*nats.Conn, 50000) wait := &sync.WaitGroup{} wait.Add(len(clients)) for i := 0; i < len(clients); i++ { clients[i], err = nats.Connect(fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port), nats.InProcessServer(s)) if err != nil { t.Fatalf("Error on connect: %v", err) } defer clients[i].Close() clients[i].Subscribe("test", func(m *nats.Msg) { wait.Done() }) } runtime.GC() runtime.ReadMemStats(&before) nc, err := nats.Connect(fmt.Sprintf("nats://%s:%d", opts.Host, opts.Port), nats.InProcessServer(s)) if err != nil { t.Fatalf("Error on connect: %v", err) } defer nc.Close() var m [48000]byte if err = nc.Publish("test", m[:]); err != nil { t.Fatal(err) } wait.Wait() runtime.GC() runtime.ReadMemStats(&after) hb, ha := float64(before.HeapAlloc), float64(after.HeapAlloc) ms := float64(len(m)) diff := float64(ha) - float64(hb) inc := (diff / float64(hb)) * 100 if inc > 10 { t.Logf("Message size: %.1fKB\n", ms/1024) t.Logf("Subscribed clients: %d\n", len(clients)) t.Logf("Heap allocs before: %.1fMB\n", hb/1024/1024) t.Logf("Heap allocs after: %.1fMB\n", ha/1024/1024) t.Logf("Heap allocs delta: %.1f%%\n", inc) t.Fatalf("memory increase was %.1f%% (should be <= 10%%)", inc) } } func TestNoRaceJetStreamClusterLeafnodeConnectPerf(t *testing.T) { // Uncomment to run. Needs to be on a big machine. Do not want as part of Travis tests atm. skip(t) tmpl := strings.Replace(jsClusterAccountsTempl, "store_dir:", "domain: cloud, store_dir:", 1) c := createJetStreamCluster(t, tmpl, "CLOUD", _EMPTY_, 3, 18033, true) defer c.shutdown() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "STATE", Subjects: []string{"STATE.GLOBAL.CELL1.*.>"}, Replicas: 3, }) require_NoError(t, err) tmpl = strings.Replace(jsClusterTemplWithSingleFleetLeafNode, "store_dir:", "domain: vehicle, store_dir:", 1) var vinSerial int genVIN := func() string { vinSerial++ return fmt.Sprintf("7PDSGAALXNN%06d", vinSerial) } numVehicles := 500 for i := 0; i < numVehicles; i++ { start := time.Now() vin := genVIN() ln := c.createLeafNodeWithTemplateNoSystemWithProto(vin, tmpl, "ws") nc, js := jsClientConnect(t, ln) _, err := js.AddStream(&nats.StreamConfig{ Name: "VEHICLE", Subjects: []string{"STATE.GLOBAL.LOCAL.>"}, Sources: []*nats.StreamSource{{ Name: "STATE", FilterSubject: fmt.Sprintf("STATE.GLOBAL.CELL1.%s.>", vin), External: &nats.ExternalStream{ APIPrefix: "$JS.cloud.API", DeliverPrefix: fmt.Sprintf("DELIVER.STATE.GLOBAL.CELL1.%s", vin), }, }}, }) require_NoError(t, err) // Create the sourced stream. checkLeafNodeConnectedCount(t, ln, 1) if elapsed := time.Since(start); elapsed > 2*time.Second { t.Fatalf("Took too long to create leafnode %d connection: %v", i+1, elapsed) } nc.Close() } } func TestNoRaceJetStreamClusterDifferentRTTInterestBasedStreamPreAck(t *testing.T) { tmpl := ` listen: 127.0.0.1:-1 server_name: %s jetstream: {max_mem_store: 256MB, max_file_store: 2GB, store_dir: '%s'} cluster { name: "F3" listen: 127.0.0.1:%d routes = [%s] } accounts { $SYS { users = [ { user: "admin", pass: "s3cr3t!" } ] } } ` // Route Ports // "S1": 14622, // "S2": 15622, // "S3": 16622, // S2 (stream leader) will have a slow path to S1 (via proxy) and S3 (consumer leader) will have a fast path. // Do these in order, S1, S2 (proxy) then S3. c := &cluster{t: t, servers: make([]*Server, 3), opts: make([]*Options, 3), name: "F3"} // S1 conf := fmt.Sprintf(tmpl, "S1", t.TempDir(), 14622, "route://127.0.0.1:15622, route://127.0.0.1:16622") c.servers[0], c.opts[0] = RunServerWithConfig(createConfFile(t, []byte(conf))) // S2 // Create the proxy first. Connect this to S1. Make it slow, e.g. 5ms RTT. np := createNetProxy(1*time.Millisecond, 1024*1024*1024, 1024*1024*1024, "route://127.0.0.1:14622", true) routes := fmt.Sprintf("%s, route://127.0.0.1:16622", np.routeURL()) conf = fmt.Sprintf(tmpl, "S2", t.TempDir(), 15622, routes) c.servers[1], c.opts[1] = RunServerWithConfig(createConfFile(t, []byte(conf))) // S3 conf = fmt.Sprintf(tmpl, "S3", t.TempDir(), 16622, "route://127.0.0.1:14622, route://127.0.0.1:15622") c.servers[2], c.opts[2] = RunServerWithConfig(createConfFile(t, []byte(conf))) c.checkClusterFormed() c.waitOnClusterReady() defer c.shutdown() defer np.stop() nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() // Now create the stream. _, err := js.AddStream(&nats.StreamConfig{ Name: "EVENTS", Subjects: []string{"EV.>"}, Replicas: 3, Retention: nats.InterestPolicy, }) require_NoError(t, err) // Make sure it's leader is on S2. sl := c.servers[1] checkFor(t, 20*time.Second, 200*time.Millisecond, func() error { c.waitOnStreamLeader(globalAccountName, "EVENTS") if s := c.streamLeader(globalAccountName, "EVENTS"); s != sl { s.JetStreamStepdownStream(globalAccountName, "EVENTS") return fmt.Errorf("Server %s is not stream leader yet", sl) } return nil }) // Now create the consumer. _, err = js.AddConsumer("EVENTS", &nats.ConsumerConfig{ Durable: "C", AckPolicy: nats.AckExplicitPolicy, DeliverSubject: "dx", }) require_NoError(t, err) // Make sure the consumer leader is on S3. cl := c.servers[2] checkFor(t, 20*time.Second, 200*time.Millisecond, func() error { c.waitOnConsumerLeader(globalAccountName, "EVENTS", "C") if s := c.consumerLeader(globalAccountName, "EVENTS", "C"); s != cl { s.JetStreamStepdownConsumer(globalAccountName, "EVENTS", "C") return fmt.Errorf("Server %s is not consumer leader yet", sl) } return nil }) // Create the real consumer on the consumer leader to make it efficient. nc, js = jsClientConnect(t, cl) defer nc.Close() _, err = js.Subscribe(_EMPTY_, func(msg *nats.Msg) { msg.Ack() }, nats.BindStream("EVENTS"), nats.Durable("C"), nats.ManualAck()) require_NoError(t, err) for i := 0; i < 1_000; i++ { _, err := js.PublishAsync("EVENTS.PAID", []byte("ok")) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } slow := c.servers[0] mset, err := slow.GlobalAccount().lookupStream("EVENTS") require_NoError(t, err) // Make sure preAck is non-nil, so we know the logic has kicked in. mset.mu.RLock() preAcks := mset.preAcks mset.mu.RUnlock() require_NotNil(t, preAcks) checkFor(t, 5*time.Second, 200*time.Millisecond, func() error { state := mset.state() if state.Msgs == 0 { mset.mu.RLock() lp := len(mset.preAcks) mset.mu.RUnlock() if lp == 0 { return nil } else { t.Fatalf("Expected no preAcks with no msgs, but got %d", lp) } } return fmt.Errorf("Still have %d msgs left", state.Msgs) }) } func TestNoRaceCheckAckFloorWithVeryLargeFirstSeqAndNewConsumers(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, _ := jsClientConnect(t, s) defer nc.Close() // Make sure to time bound here for the acksync call below. js, err := nc.JetStream(nats.MaxWait(200 * time.Millisecond)) require_NoError(t, err) _, err = js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"wq-req"}, Retention: nats.WorkQueuePolicy, }) require_NoError(t, err) largeFirstSeq := uint64(1_200_000_000) err = js.PurgeStream("TEST", &nats.StreamPurgeRequest{Sequence: largeFirstSeq}) require_NoError(t, err) si, err := js.StreamInfo("TEST") require_NoError(t, err) require_True(t, si.State.FirstSeq == largeFirstSeq) // Add a simple request to the stream. sendStreamMsg(t, nc, "wq-req", "HELP") sub, err := js.PullSubscribe("wq-req", "dlc") require_NoError(t, err) msgs, err := sub.Fetch(1) require_NoError(t, err) require_True(t, len(msgs) == 1) // The bug is around the checkAckFloor walking the sequences from current ackfloor // to the first sequence of the stream. We time bound the max wait with the js context // to 200ms. Since checkAckFloor is spinning and holding up processing of acks this will fail. // We will short circuit new consumers to fix this one. require_NoError(t, msgs[0].AckSync()) // Now do again so we move past the new consumer with no ack floor situation. err = js.PurgeStream("TEST", &nats.StreamPurgeRequest{Sequence: 2 * largeFirstSeq}) require_NoError(t, err) si, err = js.StreamInfo("TEST") require_NoError(t, err) require_True(t, si.State.FirstSeq == 2*largeFirstSeq) sendStreamMsg(t, nc, "wq-req", "MORE HELP") // We check this one directly for this use case. mset, err := s.GlobalAccount().lookupStream("TEST") require_NoError(t, err) o := mset.lookupConsumer("dlc") require_True(t, o != nil) // Purge will move the stream floor by default, so force into the situation where it is back to largeFirstSeq. // This will not trigger the new consumer logic, but will trigger a walk of the sequence space. // Fix will be to walk the lesser of the two linear spaces. o.mu.Lock() o.asflr = largeFirstSeq o.mu.Unlock() done := make(chan bool) go func() { o.checkAckFloor() done <- true }() select { case <-done: return case <-time.After(time.Second): t.Fatalf("Check ack floor taking too long!") } } func TestNoRaceReplicatedMirrorWithLargeStartingSequenceOverLeafnode(t *testing.T) { // Cluster B tmpl := strings.Replace(jsClusterTempl, "store_dir:", "domain: B, store_dir:", 1) c := createJetStreamCluster(t, tmpl, "B", _EMPTY_, 3, 22020, true) defer c.shutdown() // Cluster A // Domain is "A' lc := c.createLeafNodesWithStartPortAndDomain("A", 3, 22110, "A") defer lc.shutdown() lc.waitOnClusterReady() // Create a stream on B (HUB/CLOUD) and set its starting sequence very high. nc, js := jsClientConnect(t, c.randomServer()) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"foo"}, Replicas: 3, }) require_NoError(t, err) err = js.PurgeStream("TEST", &nats.StreamPurgeRequest{Sequence: 1_000_000_000}) require_NoError(t, err) // Send in a small amount of messages. for i := 0; i < 1000; i++ { sendStreamMsg(t, nc, "foo", "Hello") } si, err := js.StreamInfo("TEST") require_NoError(t, err) require_True(t, si.State.FirstSeq == 1_000_000_000) // Now try to create a replicated mirror on the leaf cluster. lnc, ljs := jsClientConnect(t, lc.randomServer()) defer lnc.Close() _, err = ljs.AddStream(&nats.StreamConfig{ Name: "TEST", Mirror: &nats.StreamSource{ Name: "TEST", Domain: "B", }, }) require_NoError(t, err) // Make sure we sync quickly. checkFor(t, time.Second, 200*time.Millisecond, func() error { si, err = ljs.StreamInfo("TEST") require_NoError(t, err) if si.State.Msgs == 1000 && si.State.FirstSeq == 1_000_000_000 { return nil } return fmt.Errorf("Mirror state not correct: %+v", si.State) }) } func TestNoRaceBinaryStreamSnapshotEncodingBasic(t *testing.T) { s := RunBasicJetStreamServer(t) defer s.Shutdown() nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"*"}, MaxMsgsPerSubject: 1, }) require_NoError(t, err) // Set first key sendStreamMsg(t, nc, "key:1", "hello") // Set Second key but keep updating it, causing a laggard pattern. value := bytes.Repeat([]byte("Z"), 8*1024) for i := 0; i <= 1000; i++ { _, err := js.PublishAsync("key:2", value) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } // Now do more of swiss cheese style. for i := 3; i <= 1000; i++ { key := fmt.Sprintf("key:%d", i) _, err := js.PublishAsync(key, value) require_NoError(t, err) // Send it twice to create hole right behind it, like swiss cheese. _, err = js.PublishAsync(key, value) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } // Make for round numbers for stream state. sendStreamMsg(t, nc, "key:2", "hello") sendStreamMsg(t, nc, "key:2", "world") si, err := js.StreamInfo("TEST") require_NoError(t, err) require_True(t, si.State.FirstSeq == 1) require_True(t, si.State.LastSeq == 3000) require_True(t, si.State.Msgs == 1000) require_True(t, si.State.NumDeleted == 2000) mset, err := s.GlobalAccount().lookupStream("TEST") require_NoError(t, err) snap, err := mset.store.EncodedStreamState(0) require_NoError(t, err) // Now decode the snapshot. ss, err := DecodeStreamState(snap) require_NoError(t, err) require_Equal(t, ss.FirstSeq, 1) require_Equal(t, ss.LastSeq, 3000) require_Equal(t, ss.Msgs, 1000) require_Equal(t, ss.Deleted.NumDeleted(), 2000) } func TestNoRaceFilestoreBinaryStreamSnapshotEncodingLargeGaps(t *testing.T) { storeDir := t.TempDir() fcfg := FileStoreConfig{ StoreDir: storeDir, BlockSize: 512, // Small on purpose to create alot of blks. } fs, err := newFileStore(fcfg, StreamConfig{Name: "zzz", Subjects: []string{"zzz"}, Storage: FileStorage}) require_NoError(t, err) defer fs.Stop() subj, msg := "zzz", bytes.Repeat([]byte("X"), 128) numMsgs := 20_000 fs.StoreMsg(subj, nil, msg) for i := 2; i < numMsgs; i++ { seq, _, err := fs.StoreMsg(subj, nil, nil) require_NoError(t, err) fs.RemoveMsg(seq) } fs.StoreMsg(subj, nil, msg) snap, err := fs.EncodedStreamState(0) require_NoError(t, err) require_True(t, len(snap) < 512) // Now decode the snapshot. ss, err := DecodeStreamState(snap) require_NoError(t, err) require_True(t, ss.FirstSeq == 1) require_True(t, ss.LastSeq == 20_000) require_True(t, ss.Msgs == 2) require_True(t, len(ss.Deleted) <= 2) require_True(t, ss.Deleted.NumDeleted() == 19_998) } func TestNoRaceJetStreamClusterStreamSnapshotCatchup(t *testing.T) { c := createJetStreamClusterExplicit(t, "R3S", 3) defer c.shutdown() s := c.randomServer() // Client based API nc, js := jsClientConnect(t, s) defer nc.Close() _, err := js.AddStream(&nats.StreamConfig{ Name: "TEST", Subjects: []string{"*"}, MaxMsgsPerSubject: 1, Replicas: 3, }) require_NoError(t, err) msg := []byte("Hello World") _, err = js.Publish("foo", msg) require_NoError(t, err) for i := 1; i < 1000; i++ { _, err := js.PublishAsync("bar", msg) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(5 * time.Second): t.Fatalf("Did not receive completion signal") } sr := c.randomNonStreamLeader(globalAccountName, "TEST") sr.Shutdown() // Now create larger gap. for i := 0; i < 50_000; i++ { _, err := js.PublishAsync("bar", msg) require_NoError(t, err) } select { case <-js.PublishAsyncComplete(): case <-time.After(10 * time.Second): t.Fatalf("Did not receive completion signal") } sl := c.streamLeader(globalAccountName, "TEST") sl.JetStreamSnapshotStream(globalAccountName, "TEST") sr = c.restartServer(sr) c.checkClusterFormed() c.waitOnServerCurrent(sr) c.waitOnStreamCurrent(sr, globalAccountName, "TEST") mset, err := sr.GlobalAccount().lookupStream("TEST") require_NoError(t, err) var state StreamState mset.store.FastState(&state) require_True(t, state.Msgs == 2) require_True(t, state.FirstSeq == 1) require_True(t, state.LastSeq == 51_000) require_True(t, state.NumDeleted == 51_000-2) sr.Shutdown() _, err = js.Publish("baz", msg) require_NoError(t, err) sl.JetStreamSnapshotStream(globalAccountName, "TEST") sr = c.restartServer(sr) c.checkClusterFormed() c.waitOnServerCurrent(sr) c.waitOnStreamCurrent(sr, globalAccountName, "TEST") mset, err = sr.GlobalAccount().lookupStream("TEST") require_NoError(t, err) mset.store.FastState(&state) require_True(t, state.Msgs == 3) require_True(t, state.FirstSeq == 1) require_True(t, state.LastSeq == 51_001) require_True(t, state.NumDeleted == 51_001-3) } func TestNoRaceStoreStreamEncoderDecoder(t *testing.T) { cfg := &StreamConfig{ Name: "zzz", Subjects: []string{"*"}, MaxMsgsPer: 1, Storage: MemoryStorage, } ms, err := newMemStore(cfg) require_NoError(t, err) fs, err := newFileStore( FileStoreConfig{StoreDir: t.TempDir()}, StreamConfig{Name: "zzz", Subjects: []string{"*"}, MaxMsgsPer: 1, Storage: FileStorage}, ) require_NoError(t, err) defer fs.Stop() const seed = 2222222 msg := bytes.Repeat([]byte("ABC"), 33) // ~100bytes maxEncodeTime := 2 * time.Second maxEncodeSize := 700 * 1024 test := func(t *testing.T, gs StreamStore) { t.Parallel() prand := rand.New(rand.NewSource(seed)) tick := time.NewTicker(time.Second) defer tick.Stop() done := time.NewTimer(10 * time.Second) for running := true; running; { select { case <-tick.C: var state StreamState gs.FastState(&state) if state.NumDeleted == 0 { continue } start := time.Now() snap, err := gs.EncodedStreamState(0) require_NoError(t, err) elapsed := time.Since(start) // Should take <1ms without race but if CI/CD is slow we will give it a bit of room. if elapsed > maxEncodeTime { t.Logf("Encode took longer then expected: %v", elapsed) } if len(snap) > maxEncodeSize { t.Fatalf("Expected snapshot size < %v got %v", friendlyBytes(maxEncodeSize), friendlyBytes(len(snap))) } ss, err := DecodeStreamState(snap) require_True(t, len(ss.Deleted) > 0) require_NoError(t, err) case <-done.C: running = false default: key := strconv.Itoa(prand.Intn(256_000)) gs.StoreMsg(key, nil, msg) } } } for _, gs := range []StreamStore{ms, fs} { switch gs.(type) { case *memStore: t.Run("MemStore", func(t *testing.T) { test(t, gs) }) case *fileStore: t.Run("FileStore", func(t *testing.T) { test(t, gs) }) } } }