Skip to content

Commit

Permalink
WIP: Fixed typos & added benchmark tests
Browse files Browse the repository at this point in the history
  • Loading branch information
afek854 committed Sep 8, 2024
1 parent e74c136 commit 2019ba4
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 10 deletions.
8 changes: 4 additions & 4 deletions pkg/registry/file/dynamicpathdetector/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (ua *PathAnalyzer) createDynamicNode(node *SegmentNode) *SegmentNode {

// Copy all existing children to the new dynamic node
for _, child := range node.Children {
shallowChildrensCopy(child, dynamicNode)
shallowChildrenCopy(child, dynamicNode)
}

// Replace all children with the new dynamic node
Expand All @@ -100,7 +100,7 @@ func (ua *PathAnalyzer) createDynamicNode(node *SegmentNode) *SegmentNode {
}

func (ua *PathAnalyzer) updateNodeStats(node *SegmentNode) {
if node.Count > theshold && !node.IsNextDynamic() {
if node.Count > threshold && !node.IsNextDynamic() {

dynamicChild := &SegmentNode{
SegmentName: dynamicIdentifier,
Expand All @@ -110,7 +110,7 @@ func (ua *PathAnalyzer) updateNodeStats(node *SegmentNode) {

// Copy all descendants
for _, child := range node.Children {
shallowChildrensCopy(child, dynamicChild)
shallowChildrenCopy(child, dynamicChild)
}

node.Children = map[string]*SegmentNode{
Expand All @@ -119,7 +119,7 @@ func (ua *PathAnalyzer) updateNodeStats(node *SegmentNode) {
}
}

func shallowChildrensCopy(src, dst *SegmentNode) {
func shallowChildrenCopy(src, dst *SegmentNode) {
for segmentName := range src.Children {
if !KeyInMap(dst.Children, segmentName) {
dst.Children[segmentName] = src.Children[segmentName]
Expand Down
114 changes: 114 additions & 0 deletions pkg/registry/file/dynamicpathdetector/analyzer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package dynamicpathdetector

import (
"fmt"
"math/rand"
"strings"
"testing"
)

func BenchmarkAnalyzePath(b *testing.B) {
analyzer := NewPathAnalyzer()
paths := generateMixedPaths(10000, 0) // 0 means use default mixed lengths

identifier := "test"

// Ensure we analyze at least 10,000 paths
minIterations := 10000
if b.N < minIterations {
b.N = minIterations
}

b.ResetTimer()
for i := 0; i < b.N; i++ {
path := paths[i%len(paths)]
_, err := analyzer.AnalyzePath(path, identifier)
if err != nil {
b.Fatalf("Error analyzing path: %v", err)
}
}
}

func BenchmarkAnalyzePathWithDifferentLengths(b *testing.B) {
pathLengths := []int{1, 3, 5, 10, 20, 50, 100}

for _, length := range pathLengths {
b.Run(fmt.Sprintf("PathLength-%d", length), func(b *testing.B) {
analyzer := NewPathAnalyzer()
paths := generateMixedPaths(10000, length)
identifier := "test"

// Ensure we analyze at least 10,000 paths
minIterations := 10000
if b.N < minIterations {
b.N = minIterations
}

b.ResetTimer()
for i := 0; i < b.N; i++ {
path := paths[i%len(paths)]
_, err := analyzer.AnalyzePath(path, identifier)
if err != nil {
b.Fatalf("Error analyzing path: %v", err)
}
}

})
}
}

func generateMixedPaths(count int, fixedLength int) []string {
paths := make([]string, count)
staticSegments := []string{"users", "profile", "settings", "api", "v1", "posts", "organizations", "departments", "employees", "projects", "tasks", "categories", "subcategories", "items", "articles"}

for i := 0; i < count; i++ {
if fixedLength > 0 {
segments := make([]string, fixedLength)
for j := 0; j < fixedLength; j++ {
if rand.Float32() < 0.2 { // 20% chance of dynamic segment
prefix := staticSegments[rand.Intn(len(staticSegments))]
// Generate a value > 100 to ensure it's considered dynamic
dynamicValue := rand.Intn(10000) + 101
segments[j] = fmt.Sprintf("%s_%d", prefix, dynamicValue)
} else { // 80% chance of static segment
segments[j] = staticSegments[rand.Intn(len(staticSegments))]
}
}
paths[i] = "/" + strings.Join(segments, "/")
} else {
// Use the original mixed path generation logic for variable length paths
switch rand.Intn(6) {
case 0:
paths[i] = "/users/profile/settings"
case 1:
paths[i] = fmt.Sprintf("/users/%d/profile", i%200)
case 2:
paths[i] = fmt.Sprintf("/api/v1/users/%d/posts/%d", i%200, i%150)
case 3:
paths[i] = fmt.Sprintf("/organizations/%d/departments/%d/employees/%d/projects/%d/tasks/%d",
i%100, i%50, i%1000, i%30, i%200)
case 4:
repeatedSegment := fmt.Sprintf("%d", i%150)
paths[i] = fmt.Sprintf("/categories/%s/subcategories/%s/items/%s",
repeatedSegment, repeatedSegment, repeatedSegment)
case 5:
paths[i] = fmt.Sprintf("/articles/%d/%s-%s-%s",
i%100,
generateRandomString(5),
generateRandomString(7),
generateRandomString(5))
}
}
}
return paths
}

// Helper function to generate random strings
func generateRandomString(length int) string {
const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
result := make([]byte, length)
for i := range result {
result[i] = charset[rand.Intn(len(charset))]
}
return string(result)
}
7 changes: 1 addition & 6 deletions pkg/registry/file/dynamicpathdetector/types.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
package dynamicpathdetector

import (
"sync"
)

const dynamicIdentifier string = "<dynamic>"

const theshold = 100
const threshold = 100

type SegmentNode struct {
SegmentName string
Count int
Children map[string]*SegmentNode
mutex sync.RWMutex
}

type PathAnalyzer struct {
Expand Down

0 comments on commit 2019ba4

Please sign in to comment.