Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright 2010 The Go Authors. All rights reserved. | 1 // Copyright 2010 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package textproto | 5 package textproto |
6 | 6 |
7 import ( | 7 import ( |
8 "bufio" | 8 "bufio" |
9 "bytes" | 9 "bytes" |
10 "io" | 10 "io" |
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
463 for endKey > 0 && kv[endKey-1] == ' ' { | 463 for endKey > 0 && kv[endKey-1] == ' ' { |
464 endKey-- | 464 endKey-- |
465 } | 465 } |
466 key := canonicalMIMEHeaderKey(kv[:endKey]) | 466 key := canonicalMIMEHeaderKey(kv[:endKey]) |
467 | 467 |
468 // Skip initial spaces in value. | 468 // Skip initial spaces in value. |
469 i++ // skip colon | 469 i++ // skip colon |
470 for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') { | 470 for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') { |
471 i++ | 471 i++ |
472 } | 472 } |
473 » » value := string(kv[i:]) | 473 » » value := theStringCache.get(kv[i:]) |
474 | 474 |
475 m[key] = append(m[key], value) | 475 m[key] = append(m[key], value) |
476 | 476 |
477 if err != nil { | 477 if err != nil { |
478 return m, err | 478 return m, err |
479 } | 479 } |
480 } | 480 } |
481 panic("unreachable") | 481 panic("unreachable") |
482 } | 482 } |
483 | 483 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
583 "Server", | 583 "Server", |
584 "Set-Cookie", | 584 "Set-Cookie", |
585 "Subject", | 585 "Subject", |
586 "To", | 586 "To", |
587 "User-Agent", | 587 "User-Agent", |
588 "Via", | 588 "Via", |
589 "X-Forwarded-For", | 589 "X-Forwarded-For", |
590 "X-Imforwards", | 590 "X-Imforwards", |
591 "X-Powered-By", | 591 "X-Powered-By", |
592 } | 592 } |
593 | |
594 // A stringCache is an array of strings where position X is | |
595 // occupied by the string of length X. Looks are very fast, | |
596 // because a lookup consists of at most one string compare. | |
597 // The miss count is used to decide when to evict an entry that | |
598 // is not pulling its weight, and should give its spot to a more | |
599 // common string of the same length. | |
600 type entry struct { | |
601 s string | |
602 miss int | |
603 } | |
604 | |
605 // maxCachableLen and maxMisses were chosen by looking at traces of | |
606 // headers arriving at a real-world webserver. | |
607 const maxCachableLen = 100 | |
608 const maxMisses = 9 | |
609 | |
610 type stringCache [maxCachableLen]entry | |
611 | |
612 var theStringCache stringCache | |
613 | |
614 func eq(x []byte, y string) bool { | |
615 if len(x) != len(y) { | |
616 return false | |
617 } | |
618 | |
619 for i, b := range x { | |
620 if y[i] != b { | |
621 return false | |
622 } | |
623 } | |
624 return true | |
625 } | |
626 | |
627 func (sc *stringCache) get(x []byte) string { | |
628 if len(x) >= len(sc) { | |
629 return string(x) | |
630 } | |
631 | |
632 // grab a private copy of the entry so another thread can't | |
633 // change it on us | |
634 it := sc[len(x)] | |
635 | |
636 // first use of this entry or this entry is missing too | |
637 // often: set it to string(x) | |
638 if it.s == "" || it.miss > maxMisses { | |
639 s := string(x) | |
640 // this write is racy, but we'll return the right answer | |
641 // even if we lose the race | |
642 sc[len(x)].s = s | |
dvyukov
2012/11/15 11:33:15
That will crash and corrupt memory.
Even an "inno
dvyukov
2012/11/15 11:44:16
You can do some shortcuts with sync/atomic package
| |
643 sc[len(x)].miss = 0 | |
644 return s | |
645 } | |
646 | |
647 // the write to miss below are racy, but it is approximate | |
648 // and we don't care if we lose the race. | |
649 if eq(x, it.s) { | |
650 sc[len(x)].miss = 0 | |
dvyukov
2012/11/15 11:53:05
You better not update it if it's already 0, it wil
| |
651 return it.s | |
652 } | |
653 sc[len(x)].miss++ | |
654 return string(x) | |
655 } | |
OLD | NEW |