Skip to content

Commit 8fec6dd

Browse files
committed
Use *Token instead of Token when parsing
This result in a 10% speedup when parsing a zone from disk.
1 parent 9b15d74 commit 8fec6dd

File tree

3 files changed

+46
-63
lines changed

3 files changed

+46
-63
lines changed

parse_test.go

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -282,35 +282,18 @@ func TestParseFailure(t *testing.T) {
282282
}
283283
}
284284

285-
/*
286-
// A bit useless, how to use b.N?. It always returns 0
287-
func BenchmarkZoneParsing(b *testing.B) {
288-
b.StopTimer()
289-
f, err := os.Open("t/miek.nl.signed_test")
290-
if err != nil {
291-
return
292-
}
293-
defer f.Close()
294-
b.StartTimer()
295-
for i := 0; i < b.N; i++ {
296-
to := ParseZone(f, "", "t/miek.nl.signed_test")
297-
for _ = range to {
298-
}
299-
}
300-
}
301-
*/
302-
303285
func TestZoneParsing(t *testing.T) {
304-
f, err := os.Open("t/miek.nl.signed_test")
286+
f, err := os.Open("test.db")
305287
if err != nil {
306288
return
307289
}
308290
defer f.Close()
309291
start := time.Now().UnixNano()
310-
to := ParseZone(f, "", "t/miek.nl.signed_test")
292+
to := ParseZone(f, "", "test.db")
311293
var i int
312294
for x := range to {
313-
t.Logf("%s\n", x.RR)
295+
x = x
296+
//t.Logf("%s\n", x.RR)
314297
i++
315298
}
316299
delta := time.Now().UnixNano() - start

zgenerate.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
// of $ after that are interpreted.
2323
// Any error are returned as a string value, the empty string signals
2424
// "no error".
25-
func generate(l lex, c chan lex, t chan Token, o string) string {
25+
func generate(l lex, c chan lex, t chan *Token, o string) string {
2626
step := 1
2727
if i := strings.IndexAny(l.token, "/"); i != -1 {
2828
if i+1 == len(l.token) {
@@ -126,7 +126,7 @@ BuildRR:
126126
if e != nil {
127127
return e.(*ParseError).err
128128
}
129-
t <- Token{RR: rx}
129+
t <- &Token{RR: rx}
130130
// Its more efficient to first built the rrlist and then parse it in
131131
// one go! But is this a problem?
132132
}

zscan.go

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ type lex struct {
9797
comment string // any comment text seen
9898
}
9999

100-
// Tokens are returned when a zone file is parsed.
100+
// *Tokens are returned when a zone file is parsed.
101101
type Token struct {
102102
RR // the scanned resource record when error is not nil
103103
Error *ParseError // when an error occured, this has the error specifics
@@ -124,7 +124,7 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
124124
return r.RR, nil
125125
}
126126

127-
// ParseZone reads a RFC 1035 style one from r. It returns Tokens on the
127+
// ParseZone reads a RFC 1035 style one from r. It returns *Tokens on the
128128
// returned channel, which consist out the parsed RR, a potential comment or an error.
129129
// If there is an error the RR is nil. The string file is only used
130130
// in error reporting. The string origin is used as the initial origin, as
@@ -147,17 +147,17 @@ func ReadRR(q io.Reader, filename string) (RR, error) {
147147
//
148148
// The text "; this is comment" is returned in Token.Comment . Comments inside the
149149
// RR are discarded. Comments on a line by themselves are discarded too.
150-
func ParseZone(r io.Reader, origin, file string) chan Token {
150+
func ParseZone(r io.Reader, origin, file string) chan *Token {
151151
return parseZoneHelper(r, origin, file, 10000)
152152
}
153153

154-
func parseZoneHelper(r io.Reader, origin, file string, chansize int) chan Token {
155-
t := make(chan Token, chansize)
154+
func parseZoneHelper(r io.Reader, origin, file string, chansize int) chan *Token {
155+
t := make(chan *Token, chansize)
156156
go parseZone(r, origin, file, t, 0)
157157
return t
158158
}
159159

160-
func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
160+
func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
161161
defer func() {
162162
if include == 0 {
163163
close(t)
@@ -182,7 +182,7 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
182182
}
183183
origin = Fqdn(origin)
184184
if _, ok := IsDomainName(origin); !ok {
185-
t <- Token{Error: &ParseError{f, "bad initial origin name", lex{}}}
185+
t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}}
186186
return
187187
}
188188

@@ -193,7 +193,7 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
193193
for l := range c {
194194
// Lexer spotted an error already
195195
if l.err == true {
196-
t <- Token{Error: &ParseError{f, l.token, l}}
196+
t <- &Token{Error: &ParseError{f, l.token, l}}
197197
return
198198

199199
}
@@ -218,7 +218,7 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
218218
}
219219
_, ok := IsDomainName(l.token)
220220
if !ok {
221-
t <- Token{Error: &ParseError{f, "bad owner name", l}}
221+
t <- &Token{Error: &ParseError{f, "bad owner name", l}}
222222
return
223223
}
224224
prevName = h.Name
@@ -244,7 +244,7 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
244244
// line except the RR type
245245
case _STRING: // First thing on the is the ttl
246246
if ttl, ok := stringToTtl(l.token); !ok {
247-
t <- Token{Error: &ParseError{f, "not a TTL", l}}
247+
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
248248
return
249249
} else {
250250
h.Ttl = ttl
@@ -254,18 +254,18 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
254254
st = _EXPECT_ANY_NOTTL_BL
255255

256256
default:
257-
t <- Token{Error: &ParseError{f, "syntax error at beginning", l}}
257+
t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
258258
return
259259
}
260260
case _EXPECT_DIRINCLUDE_BL:
261261
if l.value != _BLANK {
262-
t <- Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}}
262+
t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}}
263263
return
264264
}
265265
st = _EXPECT_DIRINCLUDE
266266
case _EXPECT_DIRINCLUDE:
267267
if l.value != _STRING {
268-
t <- Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}}
268+
t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}}
269269
return
270270
}
271271
neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
@@ -275,7 +275,7 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
275275
l := <-c
276276
if l.value == _STRING {
277277
if _, ok := IsDomainName(l.token); !ok {
278-
t <- Token{Error: &ParseError{f, "bad origin name", l}}
278+
t <- &Token{Error: &ParseError{f, "bad origin name", l}}
279279
return
280280
}
281281
// a new origin is specified.
@@ -292,59 +292,59 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
292292
case _NEWLINE, _EOF:
293293
// Ok
294294
default:
295-
t <- Token{Error: &ParseError{f, "garbage after $INCLUDE", l}}
295+
t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}}
296296
return
297297
}
298298
// Start with the new file
299299
r1, e1 := os.Open(l.token)
300300
if e1 != nil {
301-
t <- Token{Error: &ParseError{f, "failed to open `" + l.token + "'", l}}
301+
t <- &Token{Error: &ParseError{f, "failed to open `" + l.token + "'", l}}
302302
return
303303
}
304304
if include+1 > 7 {
305-
t <- Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
305+
t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
306306
return
307307
}
308308
parseZone(r1, l.token, neworigin, t, include+1)
309309
st = _EXPECT_OWNER_DIR
310310
case _EXPECT_DIRTTL_BL:
311311
if l.value != _BLANK {
312-
t <- Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
312+
t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
313313
return
314314
}
315315
st = _EXPECT_DIRTTL
316316
case _EXPECT_DIRTTL:
317317
if l.value != _STRING {
318-
t <- Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
318+
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
319319
return
320320
}
321321
if e, _ := slurpRemainder(c, f); e != nil {
322-
t <- Token{Error: e}
322+
t <- &Token{Error: e}
323323
return
324324
}
325325
if ttl, ok := stringToTtl(l.token); !ok {
326-
t <- Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
326+
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
327327
return
328328
} else {
329329
defttl = ttl
330330
}
331331
st = _EXPECT_OWNER_DIR
332332
case _EXPECT_DIRORIGIN_BL:
333333
if l.value != _BLANK {
334-
t <- Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}}
334+
t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}}
335335
return
336336
}
337337
st = _EXPECT_DIRORIGIN
338338
case _EXPECT_DIRORIGIN:
339339
if l.value != _STRING {
340-
t <- Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}}
340+
t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}}
341341
return
342342
}
343343
if e, _ := slurpRemainder(c, f); e != nil {
344-
t <- Token{Error: e}
344+
t <- &Token{Error: e}
345345
}
346346
if _, ok := IsDomainName(l.token); !ok {
347-
t <- Token{Error: &ParseError{f, "bad origin name", l}}
347+
t <- &Token{Error: &ParseError{f, "bad origin name", l}}
348348
return
349349
}
350350
if l.token[l.length-1] != '.' {
@@ -359,23 +359,23 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
359359
st = _EXPECT_OWNER_DIR
360360
case _EXPECT_DIRGENERATE_BL:
361361
if l.value != _BLANK {
362-
t <- Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}}
362+
t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}}
363363
return
364364
}
365365
st = _EXPECT_DIRGENERATE
366366
case _EXPECT_DIRGENERATE:
367367
if l.value != _STRING {
368-
t <- Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}}
368+
t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}}
369369
return
370370
}
371371
if e := generate(l, c, t, origin); e != "" {
372-
t <- Token{Error: &ParseError{f, e, l}}
372+
t <- &Token{Error: &ParseError{f, e, l}}
373373
return
374374
}
375375
st = _EXPECT_OWNER_DIR
376376
case _EXPECT_OWNER_BL:
377377
if l.value != _BLANK {
378-
t <- Token{Error: &ParseError{f, "no blank after owner", l}}
378+
t <- &Token{Error: &ParseError{f, "no blank after owner", l}}
379379
return
380380
}
381381
st = _EXPECT_ANY
@@ -389,26 +389,26 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
389389
st = _EXPECT_ANY_NOCLASS_BL
390390
case _STRING: // TTL is this case
391391
if ttl, ok := stringToTtl(l.token); !ok {
392-
t <- Token{Error: &ParseError{f, "not a TTL", l}}
392+
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
393393
return
394394
} else {
395395
h.Ttl = ttl
396396
// defttl = ttl // don't set the defttl here
397397
}
398398
st = _EXPECT_ANY_NOTTL_BL
399399
default:
400-
t <- Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
400+
t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
401401
return
402402
}
403403
case _EXPECT_ANY_NOCLASS_BL:
404404
if l.value != _BLANK {
405-
t <- Token{Error: &ParseError{f, "no blank before class", l}}
405+
t <- &Token{Error: &ParseError{f, "no blank before class", l}}
406406
return
407407
}
408408
st = _EXPECT_ANY_NOCLASS
409409
case _EXPECT_ANY_NOTTL_BL:
410410
if l.value != _BLANK {
411-
t <- Token{Error: &ParseError{f, "no blank before TTL", l}}
411+
t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
412412
return
413413
}
414414
st = _EXPECT_ANY_NOTTL
@@ -421,14 +421,14 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
421421
h.Rrtype = l.torc
422422
st = _EXPECT_RDATA
423423
default:
424-
t <- Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}}
424+
t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}}
425425
return
426426
}
427427
case _EXPECT_ANY_NOCLASS:
428428
switch l.value {
429429
case _STRING: // TTL
430430
if ttl, ok := stringToTtl(l.token); !ok {
431-
t <- Token{Error: &ParseError{f, "not a TTL", l}}
431+
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
432432
return
433433
} else {
434434
h.Ttl = ttl
@@ -439,18 +439,18 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
439439
h.Rrtype = l.torc
440440
st = _EXPECT_RDATA
441441
default:
442-
t <- Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}}
442+
t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}}
443443
return
444444
}
445445
case _EXPECT_RRTYPE_BL:
446446
if l.value != _BLANK {
447-
t <- Token{Error: &ParseError{f, "no blank before RR type", l}}
447+
t <- &Token{Error: &ParseError{f, "no blank before RR type", l}}
448448
return
449449
}
450450
st = _EXPECT_RRTYPE
451451
case _EXPECT_RRTYPE:
452452
if l.value != _RRTYPE {
453-
t <- Token{Error: &ParseError{f, "unknown RR type", l}}
453+
t <- &Token{Error: &ParseError{f, "unknown RR type", l}}
454454
return
455455
}
456456
h.Rrtype = l.torc
@@ -463,10 +463,10 @@ func parseZone(r io.Reader, origin, f string, t chan Token, include int) {
463463
if e.lex.token == "" && e.lex.value == 0 {
464464
e.lex = l // Uh, dirty
465465
}
466-
t <- Token{Error: e}
466+
t <- &Token{Error: e}
467467
return
468468
}
469-
t <- Token{RR: r, Comment: c1}
469+
t <- &Token{RR: r, Comment: c1}
470470
st = _EXPECT_OWNER_DIR
471471
}
472472
}

0 commit comments

Comments
 (0)