Skip to content

Commit 0a635ec

Browse files
authored
minimize duplicative JSON parsing while handling entries (#2880)
* minmize duplicative JSON parsing Signed-off-by: Bob Callaway <bcallaway@google.com> * add license headers Signed-off-by: Bob Callaway <bcallaway@google.com> --------- Signed-off-by: Bob Callaway <bcallaway@google.com>
1 parent 75d61c1 commit 0a635ec

9 files changed

Lines changed: 900 additions & 83 deletions

File tree

Makefile

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ all: rekor-cli rekor-server ## Build all binaries (rekor-cli and rekor-server)
1919

2020
include Makefile.swagger
2121

22-
OPENAPIDEPS = openapi.yaml $(shell find pkg/types -iname "*.json")
22+
SWAGGER_TEMPLATE_DIR := hack/swagger-templates
23+
OPENAPIDEPS = openapi.yaml $(shell find pkg/types -iname "*.json") $(shell find $(SWAGGER_TEMPLATE_DIR) -iname "*.gotmpl")
2324
SRCS = $(shell find cmd -iname "*.go") $(shell find pkg -iname "*.go"|grep -v pkg/generated) pkg/generated/restapi/configure_rekor_server.go $(SWAGGER_GEN)
2425
TOOLS_DIR := hack/tools
2526
TOOLS_BIN_DIR := $(abspath $(TOOLS_DIR)/bin)
@@ -65,10 +66,10 @@ SERVER_LDFLAGS=$(REKOR_LDFLAGS)
6566

6667
Makefile.swagger: $(SWAGGER) $(OPENAPIDEPS) ## Generate Swagger code and Makefile
6768
$(SWAGGER) validate openapi.yaml
68-
$(SWAGGER) generate client -f openapi.yaml -q -r COPYRIGHT.txt -t pkg/generated --additional-initialism=TUF --additional-initialism=DSSE
69-
$(SWAGGER) generate server -f openapi.yaml -q -r COPYRIGHT.txt -t pkg/generated --exclude-main -A rekor_server --flag-strategy=pflag --default-produces application/json --additional-initialism=TUF --additional-initialism=DSSE
69+
$(SWAGGER) generate client -f openapi.yaml -q -r COPYRIGHT.txt -t pkg/generated -T $(SWAGGER_TEMPLATE_DIR) --allow-template-override --additional-initialism=TUF --additional-initialism=DSSE
70+
$(SWAGGER) generate server -f openapi.yaml -q -r COPYRIGHT.txt -t pkg/generated -T $(SWAGGER_TEMPLATE_DIR) --allow-template-override --exclude-main -A rekor_server --flag-strategy=pflag --default-produces application/json --additional-initialism=TUF --additional-initialism=DSSE
7071
@echo "# This file is generated after swagger runs as part of the build; do not edit!" > Makefile.swagger
71-
@echo "SWAGGER_GEN=`find pkg/generated/client pkg/generated/models pkg/generated/restapi -iname '*.go' | grep -v 'configure_rekor_server' | sort -d | tr '\n' ' ' | sed 's/ $$//'`" >> Makefile.swagger;
72+
@echo "SWAGGER_GEN=`find pkg/generated/client pkg/generated/models pkg/generated/restapi -iname '*.go' ! -iname '*_test.go' | grep -v 'configure_rekor_server' | sort -d | tr '\n' ' ' | sed 's/ $$//'`" >> Makefile.swagger;
7273

7374
lint: ## Run golangci-lint checks
7475
$(GOBIN)/golangci-lint run -v ./...
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
{{ define "polymorphicSerializer" }}
2+
// Unmarshal{{ pascalize .Name }}Slice unmarshals polymorphic slices of {{ pascalize .Name }}
3+
func Unmarshal{{ pascalize .Name }}Slice(reader io.Reader, consumer runtime.Consumer) ([]{{ pascalize .Name }}, error) {
4+
var elements []json.RawMessage
5+
if err := consumer.Consume(reader, &elements); err != nil {
6+
return nil, err
7+
}
8+
9+
var result []{{ pascalize .Name }}
10+
for _, element := range elements {
11+
obj, err := unmarshal{{ pascalize .Name }}(element, consumer)
12+
if err != nil {
13+
return nil, err
14+
}
15+
result = append(result, obj)
16+
}
17+
return result, nil
18+
}
19+
20+
// Unmarshal{{ pascalize .Name }} unmarshals polymorphic {{ pascalize .Name }}
21+
func Unmarshal{{ pascalize .Name }}(reader io.Reader, {{ if eq (pascalize .Name) "ProposedEntry" }}_{{ else }}consumer{{ end }} runtime.Consumer) ({{ pascalize .Name }}, error) {
22+
{{- if eq (pascalize .Name) "ProposedEntry" }}
23+
return fastUnmarshalTargeted{{ pascalize .Name }}Reader(reader)
24+
{{- else }}
25+
// we need to read this twice, so first into a buffer
26+
data, err := io.ReadAll(reader)
27+
if err != nil {
28+
return nil, err
29+
}
30+
return unmarshal{{ pascalize .Name }}(data, consumer)
31+
{{ end }}
32+
}
33+
34+
{{ if eq (pascalize .Name) "ProposedEntry" }}
35+
type targeted{{ pascalize .Name }} struct {
36+
{{ pascalize .DiscriminatorField }} string `json:{{ printf "%q" .DiscriminatorField }}`
37+
APIVersion *string `json:"apiVersion"`
38+
Spec any `json:"spec"`
39+
}
40+
41+
func fastUnmarshalTargeted{{ pascalize .Name }}Reader(reader io.Reader) ({{ pascalize .Name }}, error) {
42+
var parsed targeted{{ pascalize .Name }}
43+
dec := json.NewDecoder(reader)
44+
dec.UseNumber()
45+
46+
if err := dec.Decode(&parsed); err != nil {
47+
return nil, err
48+
}
49+
50+
if err := validate.RequiredString({{ printf "%q" .DiscriminatorField }}, "body", parsed.{{ pascalize .DiscriminatorField }}); err != nil {
51+
return nil, err
52+
}
53+
54+
switch parsed.{{ pascalize .DiscriminatorField }} {
55+
{{- range $k, $v := .Discriminates }}
56+
case {{ printf "%q" $k }}:
57+
{{- if eq (upper (pascalize $.Name)) (upper $v) }}
58+
return &{{ camelize $.Name }}{kindField: parsed.{{ pascalize $.DiscriminatorField }}}, nil
59+
{{- else }}
60+
return &{{ $v }}{APIVersion: parsed.APIVersion, Spec: parsed.Spec}, nil
61+
{{- end }}
62+
{{- end }}
63+
default:
64+
return nil, errors.New(422, "invalid {{ .DiscriminatorField }} value: %q", parsed.{{ pascalize .DiscriminatorField }})
65+
}
66+
}
67+
68+
func fastUnmarshalTargeted{{ pascalize .Name }}(data []byte) ({{ pascalize .Name }}, error) {
69+
return fastUnmarshalTargeted{{ pascalize .Name }}Reader(bytes.NewReader(data))
70+
}
71+
{{ end }}
72+
73+
func unmarshal{{ pascalize .Name }}(data []byte, {{ if eq (pascalize .Name) "ProposedEntry" }}_{{ else }}consumer{{ end }} runtime.Consumer) ({{ pascalize .Name }}, error) {
74+
{{- if eq (pascalize .Name) "ProposedEntry" }}
75+
return fastUnmarshalTargeted{{ pascalize .Name }}(data)
76+
{{- end }}
77+
78+
{{- if ne (pascalize .Name) "ProposedEntry" }}
79+
buf := bytes.NewBuffer(data)
80+
{{ if .Discriminates }} buf2 := bytes.NewBuffer(data) {{ end }}
81+
82+
// the first time this is read is to fetch the value of the {{ .DiscriminatorField }} property.
83+
var getType struct { {{ pascalize .DiscriminatorField }} string `json:{{ printf "%q" .DiscriminatorField }}` }
84+
if err := consumer.Consume(buf, &getType); err != nil {
85+
return nil, err
86+
}
87+
88+
if err := validate.RequiredString({{ printf "%q" .DiscriminatorField }}, "body", getType.{{ pascalize .DiscriminatorField }}); err != nil {
89+
return nil, err
90+
}
91+
92+
// The value of {{ .DiscriminatorField }} is used to determine which type to create and unmarshal the data into
93+
switch getType.{{ pascalize .DiscriminatorField }} {
94+
{{- range $k, $v := .Discriminates }}
95+
case {{ printf "%q" $k }}:
96+
var result {{ if eq (upper (pascalize $.Name)) (upper $v) }}{{ camelize $.Name }}{{ else }}{{ $v }}{{ end }}
97+
if err := consumer.Consume(buf2, &result); err != nil {
98+
return nil, err
99+
}
100+
return &result, nil
101+
{{- end }}
102+
}
103+
return nil, errors.New(422, "invalid {{ .DiscriminatorField }} value: %q", getType.{{ pascalize .DiscriminatorField }})
104+
{{- end }}
105+
}
106+
{{- end }}
107+
108+
{{ define "baseTypeSerializer" }}
109+
// Unmarshal{{ pascalize .Name }} unmarshals polymorphic {{ pascalize .Name }}
110+
func Unmarshal{{ pascalize .Name }}(reader io.Reader, consumer runtime.Consumer) ({{ pascalize .Name }}, error) {
111+
return Unmarshal{{ pascalize .GoType }}(reader, consumer)
112+
}
113+
114+
// Unmarshal{{ pascalize .Name }}Slice unmarshals polymorphic slices of {{ pascalize .Name }}
115+
func Unmarshal{{ pascalize .Name }}Slice(reader io.Reader, consumer runtime.Consumer) ([]{{ pascalize .Name }}, error) {
116+
return Unmarshal{{ pascalize .GoType }}Slice(reader, consumer)
117+
}
118+
{{- end }}

pkg/generated/models/proposed_entry.go

Lines changed: 37 additions & 79 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/generated/models/proposed_entry_benchmark_test.go

Lines changed: 93 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)