Skip to content

Commit

Permalink
up: optimize some memory alloc logic
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed May 24, 2021
1 parent 7c70e80 commit 4ff59e9
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 16 deletions.
204 changes: 204 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# Make does not offer a recursive wildcard function, so here's one:
# from https://github.com/jenkins-x-plugins/jx-gitops/blob/main/Makefile
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))

SHELL := /bin/bash
NAME := rux
BUILD_TARGET = build
MAIN_SRC_FILE=cmd/main.go
GO := GO111MODULE=on go
GO_NOMOD :=GO111MODULE=off go
REV := $(shell git rev-parse --short HEAD 2> /dev/null || echo 'unknown')
ORG := gookit
ORG_REPO := $(ORG)/$(NAME)
RELEASE_ORG_REPO := $(ORG_REPO)
ROOT_PACKAGE := github.com/$(ORG_REPO)
GO_VERSION := $(shell $(GO) version | sed -e 's/^[^0-9.]*\([0-9.]*\).*/\1/')
GO_DEPENDENCIES := $(call rwildcard,pkg/,*.go) $(call rwildcard,cmd/,*.go)

BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2> /dev/null || echo 'unknown')
BUILD_DATE := $(shell date +%Y%m%d-%H:%M:%S)
CGO_ENABLED = 0

REPORTS_DIR=$(BUILD_TARGET)/reports

GOTEST := $(GO) test

# set dev version unless VERSION is explicitly set via environment
VERSION ?= $(shell echo "$$(git for-each-ref refs/tags/ --count=1 --sort=-version:refname --format='%(refname:short)' 2>/dev/null)-dev+$(REV)" | sed 's/^v//')

# Build flags for setting build-specific configuration at build time - defaults to empty
#BUILD_TIME_CONFIG_FLAGS ?= ""

# Full build flags used when building binaries. Not used for test compilation/execution.
BUILDFLAGS := -ldflags \
" -X $(ROOT_PACKAGE)/pkg/cmd/version.Version=$(VERSION)\
-X github.com/jenkins-x-plugins/jx-gitops/pkg/cmd/version.Version=$(VERSION)\
-X $(ROOT_PACKAGE)/pkg/cmd/version.Revision='$(REV)'\
-X $(ROOT_PACKAGE)/pkg/cmd/version.Branch='$(BRANCH)'\
-X $(ROOT_PACKAGE)/pkg/cmd/version.BuildDate='$(BUILD_DATE)'\
-X $(ROOT_PACKAGE)/pkg/cmd/version.GoVersion='$(GO_VERSION)'\
$(BUILD_TIME_CONFIG_FLAGS)"

# Some tests expect default values for version.*, so just use the config package values there.
TEST_BUILDFLAGS := -ldflags "$(BUILD_TIME_CONFIG_FLAGS)"

ifdef DEBUG
BUILDFLAGS := -gcflags "all=-N -l" $(BUILDFLAGS)
endif

ifdef PARALLEL_BUILDS
BUILDFLAGS += -p $(PARALLEL_BUILDS)
GOTEST += -p $(PARALLEL_BUILDS)
else
# -p 4 seems to work well for people
GOTEST += -p 4
endif

ifdef DISABLE_TEST_CACHING
GOTEST += -count=1
endif

TEST_PACKAGE ?= ./...
COVER_OUT:=$(REPORTS_DIR)/cover.out
COVERFLAGS=-coverprofile=$(COVER_OUT) --covermode=count --coverpkg=./...

.PHONY: list
list: ## List all make targets
@$(MAKE) -pRrn : -f $(MAKEFILE_LIST) 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | sort

.PHONY: help
.DEFAULT_GOAL := help
help:
@grep -h -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'

full: check ## Build and run the tests
check: build test ## Build and run the tests
get-test-deps: ## Install test dependencies
$(GO_NOMOD) get github.com/axw/gocov/gocov
$(GO_NOMOD) get -u gopkg.in/matm/v1/gocov-html

print-version: ## Print version
@echo $(VERSION)

build: $(GO_DEPENDENCIES) clean ## Build jx-labs binary for current OS
go mod download
CGO_ENABLED=$(CGO_ENABLED) $(GO) $(BUILD_TARGET) $(BUILDFLAGS) -o build/$(NAME) $(MAIN_SRC_FILE)

label: $(GO_DEPENDENCIES)
CGO_ENABLED=$(CGO_ENABLED) $(GO) $(BUILD_TARGET) $(BUILDFLAGS) -o build/jx-label fns/label/main.go

build-all: $(GO_DEPENDENCIES) build make-reports-dir ## Build all files - runtime, all tests etc.
CGO_ENABLED=$(CGO_ENABLED) $(GOTEST) -run=nope -tags=integration -failfast -short ./... $(BUILDFLAGS)

tidy-deps: ## Cleans up dependencies
$(GO) mod tidy
# mod tidy only takes compile dependencies into account, let's make sure we capture tooling dependencies as well
@$(MAKE) install-generate-deps

pprof-cli: ## generate pprof file and start an web-ui
go run ./_examples/pprof-cli.go
#go tool pprof rux_prof_data.prof
go tool pprof -http=:8080 rux_prof_data.prof

.PHONY: make-reports-dir
make-reports-dir:
mkdir -p $(REPORTS_DIR)

test: ## Run tests with the "unit" build tag
KUBECONFIG=/cluster/connections/not/allowed CGO_ENABLED=$(CGO_ENABLED) $(GOTEST) --tags=unit -failfast -short ./... $(TEST_BUILDFLAGS)

test-coverage : make-reports-dir ## Run tests and coverage for all tests with the "unit" build tag
CGO_ENABLED=$(CGO_ENABLED) $(GOTEST) --tags=unit $(COVERFLAGS) -failfast -short ./... $(TEST_BUILDFLAGS)

test-report: make-reports-dir get-test-deps test-coverage ## Create the test report
@gocov convert $(COVER_OUT) | gocov report

test-report-html: make-reports-dir get-test-deps test-coverage ## Create the test report in HTML format
@gocov convert $(COVER_OUT) | gocov-html > $(REPORTS_DIR)/cover.html && open $(REPORTS_DIR)/cover.html

install: $(GO_DEPENDENCIES) ## Install the binary
GOBIN=${GOPATH}/bin $(GO) install $(BUILDFLAGS) $(MAIN_SRC_FILE)

linux: ## Build for Linux
CGO_ENABLED=$(CGO_ENABLED) GOOS=linux GOARCH=amd64 $(GO) $(BUILD_TARGET) $(BUILDFLAGS) -o build/linux/$(NAME) $(MAIN_SRC_FILE)
chmod +x build/linux/$(NAME)

arm: ## Build for ARM
CGO_ENABLED=$(CGO_ENABLED) GOOS=linux GOARCH=arm $(GO) $(BUILD_TARGET) $(BUILDFLAGS) -o build/arm/$(NAME) $(MAIN_SRC_FILE)
chmod +x build/arm/$(NAME)

win: ## Build for Windows
CGO_ENABLED=$(CGO_ENABLED) GOOS=windows GOARCH=amd64 $(GO) $(BUILD_TARGET) $(BUILDFLAGS) -o build/win/$(NAME)-windows-amd64.exe $(MAIN_SRC_FILE)

darwin: ## Build for OSX
CGO_ENABLED=$(CGO_ENABLED) GOOS=darwin GOARCH=amd64 $(GO) $(BUILD_TARGET) $(BUILDFLAGS) -o build/darwin/$(NAME) $(MAIN_SRC_FILE)
chmod +x build/darwin/$(NAME)

.PHONY: release
release: clean linux test

release-all: release linux win darwin

promoter:
cd promote && go build main.go

.PHONY: goreleaser
goreleaser:
step-go-releaser --organisation=$(ORG) --revision=$(REV) --branch=$(BRANCH) --build-date=$(BUILD_DATE) --go-version=$(GO_VERSION) --root-package=$(ROOT_PACKAGE) --version=$(VERSION) --timeout 200m

.PHONY: clean
clean: ## Clean the generated artifacts
rm -rf build release dist

get-fmt-deps: ## Install test dependencies
$(GO_NOMOD) get golang.org/x/tools/cmd/goimports

.PHONY: fmt
fmt: importfmt ## Format the code
$(eval FORMATTED = $(shell $(GO) fmt ./...))
@if [ "$(FORMATTED)" == "" ]; \
then \
echo "All Go files properly formatted"; \
else \
echo "Fixed formatting for: $(FORMATTED)"; \
fi

.PHONY: importfmt
importfmt: get-fmt-deps
@echo "Formatting the imports..."
goimports -w $(GO_DEPENDENCIES)

.PHONY: lint
lint: ## Lint the code
./hack/gofmt.sh
./hack/linter.sh
./hack/generate.sh

.PHONY: all
all: fmt build test lint generate-refdocs

install-refdocs:
$(GO) get github.com/jenkins-x/gen-crd-api-reference-docs

generate-refdocs: install-refdocs
gen-crd-api-reference-docs -config "hack/configdocs/config.json" \
-template-dir hack/configdocs/templates \
-api-dir "./pkg/apis/gitops/v1alpha1" \
-out-file docs/config.md

generate-scheduler-refdocs: install-refdocs
gen-crd-api-reference-docs -config "hack/configdocs/config.json" \
-template-dir hack/configdocs/templates \
-api-dir "./pkg/apis/scheduler/v1alpha1" \
-out-file docs/scheduler-config.md

bin/docs:
go build $(LDFLAGS) -v -o bin/docs cmd/docs/*.go

.PHONY: docs
docs: bin/docs generate-refdocs generate-scheduler-refdocs ## update docs
@echo "Generating docs"
@./bin/docs --target=./docs/cmd
@./bin/docs --target=./docs/man/man1 --kind=man
@rm -f ./bin/docs
4 changes: 3 additions & 1 deletion _examples/pprof-cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ func main() {
defer pprof.StopCPUProfile()

for i := 0; i < times; i++ {
r.Match("get", "/")
// r.QuickMatch("GET", "/")
r.QuickMatch("GET", "/user/23")
// r.Match("get", "/")
// r.Match("get", "/users/23")
// fmt.Println(ret)
}
Expand Down
2 changes: 1 addition & 1 deletion dispatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func (r *Router) handleHTTPRequest(ctx *Context) {
}

// matching route
route, params, allowed := r.Match(ctx.Req.Method, path)
route, params, allowed := r.QuickMatch(ctx.Req.Method, path)

var handlers HandlersChain
if route != nil { // found route
Expand Down
14 changes: 12 additions & 2 deletions parse_match.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,18 @@ func (r *Router) parseParamRoute(route *Route) (first string) {
// ps - route path Params, when has path vars.
// alm - allowed request methods
func (r *Router) Match(method, path string) (route *Route, ps Params, alm []string) {
return r.QuickMatch(strings.ToUpper(method), path)
}

// QuickMatch match route by given request METHOD and URI path
// ps - route path Params, when has path vars.
// alm - allowed request methods
func (r *Router) QuickMatch(method, path string) (route *Route, ps Params, alm []string) {
if r.interceptAll != "" {
path = r.interceptAll
}

path = r.formatPath(path)
method = strings.ToUpper(method)

// do match route
if route, ps = r.match(method, path); route != nil {
Expand Down Expand Up @@ -139,6 +145,11 @@ func (r *Router) Match(method, path string) (route *Route, ps Params, alm []stri
func (r *Router) match(method, path string) (rt *Route, ps Params) {
// find in stable routes
key := method + path
// var b strings.Builder
// b.Grow(len(method)+len(path)+1)
// b.WriteString(method)
// b.WriteString(path)
// key := b.String()
if route, ok := r.stableRoutes[key]; ok {
// return r.newMatchResult(route, nil)
return route, nil
Expand Down Expand Up @@ -212,6 +223,5 @@ func (r *Router) findAllowedMethods(method, path string) (allowed []string) {
allowed = append(allowed, m)
}
}

return
}
4 changes: 2 additions & 2 deletions route.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,8 @@ func (r *Route) matchRegex(path string) (ps Params, ok bool) {

// Notice: vs[0] is full path.
for i, val := range vs[1:] {
n := r.matches[i]
ps[n] = val
// n := r.matches[i]
ps[r.matches[i]] = val
}
return
}
Expand Down
13 changes: 6 additions & 7 deletions route_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type cacheNode struct {
type cachedRoutes struct {
size int
list *list.List
lock *sync.Mutex
lock *sync.RWMutex
hashMap map[string]*list.Element
}

Expand All @@ -28,16 +28,15 @@ func NewCachedRoutes(size int) *cachedRoutes {
return &cachedRoutes{
size: size,
list: list.New(),
lock: new(sync.Mutex),
lock: new(sync.RWMutex),
hashMap: make(map[string]*list.Element),
}
}

// Len cache len
func (c *cachedRoutes) Len() int {
c.lock.Lock()
defer c.lock.Unlock()

c.lock.RLock()
defer c.lock.RUnlock()
return c.list.Len()
}

Expand Down Expand Up @@ -76,8 +75,8 @@ func (c *cachedRoutes) Set(k string, v *Route) bool {

// Get cached Route by key
func (c *cachedRoutes) Get(k string) (*Route, bool) {
c.lock.Lock()
defer c.lock.Unlock()
c.lock.RLock()
defer c.lock.RUnlock()

if element, ok := c.hashMap[k]; ok {
c.list.MoveToFront(element)
Expand Down
19 changes: 16 additions & 3 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -465,17 +465,30 @@ func (r *Router) String() string {
}

func (r *Router) formatPath(path string) string {
if path == "" || path == "/" {
return "/"
}

path = strings.TrimSpace(path)
if !r.strictLastSlash {
// clear last '/'
if !r.strictLastSlash && path[len(path)-1] == '/' {
path = strings.TrimRight(path, "/")
}

if path == "" || path == "/" {
return "/"
}

// fix: "//home" -> "home"
return "/" + strings.TrimLeft(path, "/")
// fix: "home" -> "/home"
if path[0] != '/' {
return "/" + path
}

// fix: "//home" -> "/home"
if path[1] == '/' {
return path[1:]
}
return path
}

func (r *Router) appendRoute(route *Route) {
Expand Down

0 comments on commit 4ff59e9

Please sign in to comment.