github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/timeutil/pgdate/zone_cache.go (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package pgdate 12 13 import ( 14 "fmt" 15 "time" 16 17 "github.com/cockroachdb/cockroach/pkg/util/syncutil" 18 ) 19 20 // zoneCache stores the results of resolving time.Location instances. 21 // 22 // time.LoadLocation does not perform caching internally and requires 23 // many disk accesses to locate the named zoneinfo file. 24 // 25 // We also save time.FixedZone calls to avoid needing to regenerate 26 // the string representation. 27 type zoneCache struct { 28 mu struct { 29 syncutil.Mutex 30 named map[string]*zoneCacheEntry 31 fixed map[int]*time.Location 32 } 33 } 34 35 var zoneCacheInstance = zoneCache{} 36 37 func init() { 38 zoneCacheInstance.mu.named = make(map[string]*zoneCacheEntry) 39 zoneCacheInstance.mu.fixed = make(map[int]*time.Location) 40 } 41 42 type zoneCacheEntry struct { 43 loc *time.Location 44 // We don't expect the tzinfo database to change frequently, relative 45 // to restarts of the server. Errors are unlikely to ever resolve. 46 err error 47 } 48 49 // LoadLocation wraps time.LoadLocation which does not perform 50 // caching internally and which requires many disk accesses to 51 // locate the named zoneinfo file. 52 func (z *zoneCache) LoadLocation(zone string) (*time.Location, error) { 53 z.mu.Lock() 54 entry, ok := z.mu.named[zone] 55 z.mu.Unlock() 56 57 if !ok { 58 loc, err := time.LoadLocation(zone) 59 60 entry = &zoneCacheEntry{loc: loc, err: err} 61 z.mu.Lock() 62 z.mu.named[zone] = entry 63 z.mu.Unlock() 64 } 65 return entry.loc, entry.err 66 } 67 68 // FixedZone wraps time.FixedZone. 69 func (z *zoneCache) FixedZone(hours, minutes, seconds int) *time.Location { 70 offset := (hours*60+minutes)*60 + seconds 71 z.mu.Lock() 72 ret, ok := z.mu.fixed[offset] 73 z.mu.Unlock() 74 75 if !ok { 76 if minutes < 0 { 77 minutes *= -1 78 } 79 if seconds < 0 { 80 seconds *= -1 81 } 82 // Need a field width of 3 for the leading digit because we're 83 // forcing the sign to be printed and it counts as part of the field. 84 ret = time.FixedZone(fmt.Sprintf("%+03d%02d%02d", hours, minutes, seconds), offset) 85 z.mu.Lock() 86 z.mu.fixed[offset] = ret 87 z.mu.Unlock() 88 } 89 90 return ret 91 }