func createRandomTestSpans(amount int) common.SpanSlice { rnd := rand.New(rand.NewSource(2)) allSpans := make(common.SpanSlice, amount) allSpans[0] = test.NewRandomSpan(rnd, allSpans[0:0]) for i := 1; i < amount; i++ { allSpans[i] = test.NewRandomSpan(rnd, allSpans[1:i]) } allSpans[1].SpanData.Parents = []common.SpanId{common.SpanId(allSpans[0].Id)} return allSpans }
func BenchmarkDatastoreWrites(b *testing.B) { htraceBld := &MiniHTracedBuilder{Name: "BenchmarkDatastoreWrites", WrittenSpans: make(chan *common.Span, b.N)} ht, err := htraceBld.Build() if err != nil { panic(err) } defer ht.Close() rnd := rand.New(rand.NewSource(1)) allSpans := make([]*common.Span, b.N) // Write many random spans. for n := 0; n < b.N; n++ { span := test.NewRandomSpan(rnd, allSpans[0:n]) ht.Store.WriteSpan(span) allSpans[n] = span } // Wait for all the spans to be written. for n := 0; n < b.N; n++ { <-ht.Store.WrittenSpans } spansWritten := ht.Store.GetStatistics().NumSpansWritten if spansWritten < uint64(b.N) { b.Fatal("incorrect statistics: expected %d spans to be written, but only got %d", b.N, spansWritten) } }
func TestReapingOldSpans(t *testing.T) { const NUM_TEST_SPANS = 20 testSpans := make([]*common.Span, NUM_TEST_SPANS) rnd := rand.New(rand.NewSource(2)) now := common.TimeToUnixMs(time.Now().UTC()) for i := range testSpans { testSpans[i] = test.NewRandomSpan(rnd, testSpans[0:i]) testSpans[i].Begin = now - int64(NUM_TEST_SPANS-1-i) testSpans[i].Description = fmt.Sprintf("Span%02d", i) } htraceBld := &MiniHTracedBuilder{Name: "TestReapingOldSpans", Cnf: map[string]string{ conf.HTRACE_SPAN_EXPIRY_MS: fmt.Sprintf("%d", 60*60*1000), conf.HTRACE_REAPER_HEARTBEAT_PERIOD_MS: "1", conf.HTRACE_DATASTORE_HEARTBEAT_PERIOD_MS: "1", }, WrittenSpans: common.NewSemaphore(0), DataDirs: make([]string, 2), } ht, err := htraceBld.Build() if err != nil { t.Fatalf("failed to create mini htraced cluster: %s\n", err.Error()) } ing := ht.Store.NewSpanIngestor(ht.Store.lg, "127.0.0.1", "") for spanIdx := range testSpans { ing.IngestSpan(testSpans[spanIdx]) } ing.Close(time.Now()) // Wait the spans to be created ht.Store.WrittenSpans.Waits(NUM_TEST_SPANS) // Set a reaper date that will remove all the spans except final one. ht.Store.rpr.SetReaperDate(now) common.WaitFor(5*time.Minute, time.Millisecond, func() bool { for i := 0; i < NUM_TEST_SPANS-1; i++ { span := ht.Store.FindSpan(testSpans[i].Id) if span != nil { ht.Store.lg.Debugf("Waiting for %s to be removed...\n", testSpans[i].Description) return false } } span := ht.Store.FindSpan(testSpans[NUM_TEST_SPANS-1].Id) if span == nil { ht.Store.lg.Debugf("Did not expect %s to be removed\n", testSpans[NUM_TEST_SPANS-1].Description) return false } return true }) defer ht.Close() }
func BenchmarkDatastoreWrites(b *testing.B) { htraceBld := &MiniHTracedBuilder{Name: "BenchmarkDatastoreWrites", Cnf: map[string]string{ conf.HTRACE_DATASTORE_HEARTBEAT_PERIOD_MS: "30000", conf.HTRACE_LOG_LEVEL: "INFO", }, WrittenSpans: common.NewSemaphore(0), } ht, err := htraceBld.Build() if err != nil { b.Fatalf("Error creating MiniHTraced: %s\n", err.Error()) } ht.Store.lg.Infof("BenchmarkDatastoreWrites: b.N = %d\n", b.N) defer func() { if r := recover(); r != nil { ht.Store.lg.Infof("panic: %s\n", r.(error)) } ht.Close() }() rnd := rand.New(rand.NewSource(time.Now().UnixNano())) allSpans := make([]*common.Span, b.N) for n := range allSpans { allSpans[n] = test.NewRandomSpan(rnd, allSpans[0:n]) } // Reset the timer to avoid including the time required to create new // random spans in the benchmark total. b.ResetTimer() // Write many random spans. ing := ht.Store.NewSpanIngestor(ht.Store.lg, "127.0.0.1", "") for n := 0; n < b.N; n++ { ing.IngestSpan(allSpans[n]) } ing.Close(time.Now()) // Wait for all the spans to be written. ht.Store.WrittenSpans.Waits(int64(b.N)) assertNumWrittenEquals(b, ht.Store.msink, b.N) }
func doWriteSpans(name string, N int, maxSpansPerRpc uint32, b *testing.B) { htraceBld := &MiniHTracedBuilder{Name: "doWriteSpans", Cnf: map[string]string{ conf.HTRACE_LOG_LEVEL: "INFO", conf.HTRACE_NUM_HRPC_HANDLERS: "20", }, WrittenSpans: common.NewSemaphore(int64(1 - N)), } ht, err := htraceBld.Build() if err != nil { panic(err) } defer ht.Close() rnd := rand.New(rand.NewSource(1)) allSpans := make([]*common.Span, N) for n := 0; n < N; n++ { allSpans[n] = test.NewRandomSpan(rnd, allSpans[0:n]) } // Determine how many calls to WriteSpans we should make. Each writeSpans // message should be small enough so that it doesn't exceed the max RPC // body length limit. TODO: a production-quality golang client would do // this internally rather than needing us to do it here in the unit test. bodyLen := (4 * common.MAX_HRPC_BODY_LENGTH) / 5 reqs := make([][]*common.Span, 0, 4) curReq := -1 curReqLen := bodyLen var curReqSpans uint32 mh := new(codec.MsgpackHandle) mh.WriteExt = true var mbuf [8192]byte buf := mbuf[:0] enc := codec.NewEncoderBytes(&buf, mh) for n := 0; n < N; n++ { span := allSpans[n] if (curReqSpans >= maxSpansPerRpc) || (curReqLen >= bodyLen) { reqs = append(reqs, make([]*common.Span, 0, 16)) curReqLen = 0 curReq++ curReqSpans = 0 } buf = mbuf[:0] enc.ResetBytes(&buf) err := enc.Encode(span) if err != nil { panic(fmt.Sprintf("Error encoding span %s: %s\n", span.String(), err.Error())) } bufLen := len(buf) if bufLen > (bodyLen / 5) { panic(fmt.Sprintf("Span too long at %d bytes\n", bufLen)) } curReqLen += bufLen reqs[curReq] = append(reqs[curReq], span) curReqSpans++ } ht.Store.lg.Infof("num spans: %d. num WriteSpansReq calls: %d\n", N, len(reqs)) var hcl *htrace.Client hcl, err = htrace.NewClient(ht.ClientConf(), nil) if err != nil { panic(fmt.Sprintf("failed to create client: %s", err.Error())) } defer hcl.Close() // Reset the timer to avoid including the time required to create new // random spans in the benchmark total. if b != nil { b.ResetTimer() } // Write many random spans. for reqIdx := range reqs { go func(i int) { err = hcl.WriteSpans(reqs[i]) if err != nil { panic(fmt.Sprintf("failed to send WriteSpans request %d: %s", i, err.Error())) } }(reqIdx) } // Wait for all the spans to be written. ht.Store.WrittenSpans.Wait() }