Skip to content

Commit f659ee3

Browse files
authored
Go: Optimize trap.Writer by buffering gzip writes
The TRAP writer already buffers writes before emitting to file, but running gzip compression is also fairly costly (especially if you only do it a couple of bytes at a time). Thus, this injects another buffer that collects the emitted tuples in string form, and only triggers gzip compression once the buffer is full. In my local testing, this buffering was actually more beneficial than the one between gzip and file (likely because the gzip writer already emits data in chunks), but that one is still beneficial.
1 parent e3ebf1c commit f659ee3

File tree

1 file changed

+21
-13
lines changed

1 file changed

+21
-13
lines changed

go/extractor/trap/trapwriter.go

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import (
1919
// A Writer provides methods for writing data to a TRAP file
2020
type Writer struct {
2121
zip *gzip.Writer
22-
w *bufio.Writer
22+
wzip *bufio.Writer
23+
wfile *bufio.Writer
2324
file *os.File
2425
Labeler *Labeler
2526
path string
@@ -54,11 +55,13 @@ func NewWriter(path string, pkg *packages.Package) (*Writer, error) {
5455
if err != nil {
5556
return nil, err
5657
}
57-
bufioWriter := bufio.NewWriter(tmpFile)
58-
zipWriter := gzip.NewWriter(bufioWriter)
58+
bufioFileWriter := bufio.NewWriter(tmpFile)
59+
zipWriter := gzip.NewWriter(bufioFileWriter)
60+
bufioZipWriter := bufio.NewWriter(zipWriter)
5961
tw := &Writer{
6062
zipWriter,
61-
bufioWriter,
63+
bufioZipWriter,
64+
bufioFileWriter,
6265
tmpFile,
6366
nil,
6467
path,
@@ -88,13 +91,18 @@ func trapFolder() (string, error) {
8891

8992
// Close the underlying file writer
9093
func (tw *Writer) Close() error {
91-
err := tw.zip.Close()
94+
err := tw.wzip.Flush()
95+
if err != nil {
96+
// throw away file close error
97+
tw.file.Close()
98+
}
99+
err = tw.zip.Close()
92100
if err != nil {
93101
// return zip-close error, but ignore file-close error
94102
tw.file.Close()
95103
return err
96104
}
97-
err = tw.w.Flush()
105+
err = tw.wfile.Flush()
98106
if err != nil {
99107
// throw away close error because write errors are likely to be more important
100108
tw.file.Close()
@@ -145,24 +153,24 @@ func capStringLength(s string) string {
145153

146154
// Emit writes out a tuple of values for the given `table`
147155
func (tw *Writer) Emit(table string, values []interface{}) error {
148-
fmt.Fprintf(tw.zip, "%s(", table)
156+
fmt.Fprintf(tw.wzip, "%s(", table)
149157
for i, value := range values {
150158
if i > 0 {
151-
fmt.Fprint(tw.zip, ", ")
159+
fmt.Fprint(tw.wzip, ", ")
152160
}
153161
switch value := value.(type) {
154162
case Label:
155-
fmt.Fprint(tw.zip, value.id)
163+
fmt.Fprint(tw.wzip, value.id)
156164
case string:
157-
fmt.Fprintf(tw.zip, "\"%s\"", escapeString(capStringLength(value)))
165+
fmt.Fprintf(tw.wzip, "\"%s\"", escapeString(capStringLength(value)))
158166
case int:
159-
fmt.Fprintf(tw.zip, "%d", value)
167+
fmt.Fprintf(tw.wzip, "%d", value)
160168
case float64:
161-
fmt.Fprintf(tw.zip, "%e", value)
169+
fmt.Fprintf(tw.wzip, "%e", value)
162170
default:
163171
return errors.New("Cannot emit value")
164172
}
165173
}
166-
fmt.Fprintf(tw.zip, ")\n")
174+
fmt.Fprintf(tw.wzip, ")\n")
167175
return nil
168176
}

0 commit comments

Comments
 (0)