-
Notifications
You must be signed in to change notification settings - Fork 5.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
*: write system timezone into mysql.tidb in bootstrap stage. #7638
Changes from 16 commits
ec6a822
40f1caf
ad574a4
e76c224
a74739c
f0502c8
ed136b9
085dc79
8ba623f
13c7c1b
e962f82
26f65f7
d708186
ceedc34
2adc1e8
acc0262
709c32c
350d27d
c95e6c3
21e9e22
a84c028
c1658d8
a517a43
b5e39b6
84b6e8f
dae8a5a
5c373bf
2d0aca2
e624443
f3ad3bc
692d4d5
b32bdd2
49454d5
318c12b
cb5fd7d
ec66759
a3c3cc4
3976eda
d522982
dd2d0c9
29679ab
733331e
e9bb73b
1d8ddfa
bd24bee
2f8018a
7d6ae04
d315b25
5dc988b
1f99ca1
e4418cf
44996c2
bd1693e
fda4813
9986492
1acd491
65051bb
a37aeeb
e20dc07
74d394a
64a5b2e
e77ee43
1b53dff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,9 +15,7 @@ package mocktikv | |
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io" | ||
"sync" | ||
"time" | ||
|
||
"github.com/golang/protobuf/proto" | ||
|
@@ -37,6 +35,7 @@ import ( | |
"github.com/pingcap/tidb/types" | ||
"github.com/pingcap/tidb/util/codec" | ||
mockpkg "github.com/pingcap/tidb/util/mock" | ||
"github.com/pingcap/tidb/util/timeutil" | ||
"github.com/pingcap/tipb/go-tipb" | ||
"golang.org/x/net/context" | ||
"google.golang.org/grpc" | ||
|
@@ -45,50 +44,6 @@ import ( | |
|
||
var dummySlice = make([]byte, 0) | ||
|
||
// locCache is a simple map with lock. It stores all used timezone during the lifetime of tidb instance. | ||
// Talked with Golang team about whether they can have some forms of cache policy available for programmer, | ||
// they suggests that only programmers knows which one is best for their use case. | ||
// For detail, please refer to: https://github.com/golang/go/issues/26106 | ||
type locCache struct { | ||
sync.RWMutex | ||
// locMap stores locations used in past and can be retrieved by a timezone's name. | ||
locMap map[string]*time.Location | ||
} | ||
|
||
// init initializes `locCache`. | ||
func init() { | ||
LocCache = &locCache{} | ||
LocCache.locMap = make(map[string]*time.Location) | ||
} | ||
|
||
// LocCache is a simple cache policy to improve the performance of 'time.LoadLocation'. | ||
var LocCache *locCache | ||
|
||
// getLoc first trying to load location from a cache map. If nothing found in such map, then call | ||
// `time.LocadLocation` to get a timezone location. After trying both way, an error wil be returned | ||
// if valid Location is not found. | ||
func (lm *locCache) getLoc(name string) (*time.Location, error) { | ||
if name == "System" { | ||
name = "Local" | ||
} | ||
lm.RLock() | ||
if v, ok := lm.locMap[name]; ok { | ||
lm.RUnlock() | ||
return v, nil | ||
} | ||
|
||
if loc, err := time.LoadLocation(name); err == nil { | ||
lm.RUnlock() | ||
lm.Lock() | ||
lm.locMap[name] = loc | ||
lm.Unlock() | ||
return loc, nil | ||
} | ||
|
||
lm.RUnlock() | ||
return nil, fmt.Errorf("invalid name for timezone %s", name) | ||
} | ||
|
||
type dagContext struct { | ||
dagReq *tipb.DAGRequest | ||
keyRanges []*coprocessor.KeyRange | ||
|
@@ -169,8 +124,9 @@ func (h *rpcHandler) buildDAGExecutor(req *coprocessor.Request) (*dagContext, ex | |
// timezone offset in seconds east of UTC is used to constructed the timezone. | ||
func constructTimeZone(name string, offset int) (*time.Location, error) { | ||
if name != "" { | ||
return LocCache.getLoc(name) | ||
return timeutil.LoadLocation(name) | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove this empty line |
||
return time.FixedZone("", offset), nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When will the code run to this branch and what happen then ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. user runs There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But the time zone name is not "UTC" ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case, the name should be "empty". There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will TiKV handle that ? @breeswish |
||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright 2018 PingCAP, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package logutil | ||
|
||
import ( | ||
"github.com/opentracing/opentracing-go" | ||
"golang.org/x/net/context" | ||
) | ||
|
||
// HasSpan return true if context has an active span | ||
func HasSpan(ctx context.Context) bool { | ||
if sp := opentracing.SpanFromContext(ctx); sp != nil { | ||
return true | ||
} | ||
return false | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// Copyright 2017 PingCAP, Inc. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2018 |
||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package timeutil | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"sync" | ||
"syscall" | ||
"time" | ||
|
||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
// init initializes `locCache`. | ||
func init() { | ||
LocCache = &locCache{} | ||
LocCache.locMap = make(map[string]*time.Location) | ||
} | ||
|
||
// LocCache is a simple cache policy to improve the performance of 'time.LoadLocation'. | ||
var LocCache *locCache | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it necessary to expose this variable ? |
||
var localStr string | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. systemTZ |
||
var localOnce sync.Once | ||
var zoneSources = []string{ | ||
"/usr/share/zoneinfo/", | ||
"/usr/share/lib/zoneinfo/", | ||
"/usr/lib/locale/TZ/", | ||
} | ||
|
||
// locCache is a simple map with lock. It stores all used timezone during the lifetime of tidb instance. | ||
// Talked with Golang team about whether they can have some forms of cache policy available for programmer, | ||
// they suggests that only programmers knows which one is best for their use case. | ||
// For detail, please refer to: https://github.com/golang/go/issues/26106 | ||
type locCache struct { | ||
sync.RWMutex | ||
// locMap stores locations used in past and can be retrieved by a timezone's name. | ||
locMap map[string]*time.Location | ||
} | ||
|
||
func initLocalStr() { | ||
// consult $TZ to find the time zone to use. | ||
// no $TZ means use the system default /etc/localtime. | ||
// $TZ="" means use UTC. | ||
// $TZ="foo" means use /usr/share/zoneinfo/foo. | ||
zhexuany marked this conversation as resolved.
Show resolved
Hide resolved
|
||
tz, ok := syscall.Getenv("TZ") | ||
if ok && tz != "" { | ||
for _, source := range zoneSources { | ||
if _, err := os.Stat(source + tz); os.IsExist(err) { | ||
localStr = tz | ||
break | ||
} | ||
} | ||
// } else if tz == "" { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will remove it later. |
||
// localStr = "UTC" | ||
} else { | ||
path, err := filepath.EvalSymlinks("/etc/localtime") | ||
if err == nil { | ||
localStr, err = getTZNameFromFileName(path) | ||
if err == nil { | ||
return | ||
} | ||
log.Errorln(err) | ||
} | ||
log.Errorln(err) | ||
} | ||
localStr = "System" | ||
zhexuany marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// getTZNameFromFileName gets IANA timezone name from zoneinfo path. | ||
// TODO It will be refined later. This is just a quick fix. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/TODO/TODO: |
||
func getTZNameFromFileName(path string) (string, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inferTZNameFromFileName |
||
// phase1 only support read /etc/localtime which is a softlink to zoneinfo file | ||
substr := "zoneinfo" | ||
if strings.Contains(path, substr) { | ||
zhexuany marked this conversation as resolved.
Show resolved
Hide resolved
|
||
idx := strings.Index(path, substr) | ||
return string(path[idx+len(substr)+1:]), nil | ||
} | ||
return "", errors.New(fmt.Sprintf("path %s is not supported", path)) | ||
} | ||
|
||
// Local returns time.Local's IANA timezone name. | ||
func Local() *time.Location { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So this may be actually not a local location because it is loaded from system table? Maybe you can rename the function to reduce confusion. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is the confusion? Could you please be more explicit? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name is called local, but actually its result might be not local. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please refer to the comment. Local means tidb's cluster global timezone. |
||
localOnce.Do(initLocalStr) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not run |
||
loc, err := LoadLocation(localStr) | ||
if err != nil { | ||
return time.Local | ||
} | ||
return loc | ||
} | ||
|
||
// getLoc first trying to load location from a cache map. If nothing found in such map, then call | ||
// `time.LocadLocation` to get a timezone location. After trying both way, an error wil be returned | ||
zhexuany marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// if valid Location is not found. | ||
func (lm *locCache) getLoc(name string) (*time.Location, error) { | ||
if name == "System" { | ||
zhexuany marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Define a constant for "System". Should we consider case insensitive comparison? |
||
return time.Local, nil | ||
zhexuany marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
lm.RLock() | ||
if v, ok := lm.locMap[name]; ok { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be cleaner. lm.RLock()
v, ok := lm.locMap[name]
lm.RUlokc()
... |
||
lm.RUnlock() | ||
return v, nil | ||
} | ||
|
||
if loc, err := time.LoadLocation(name); err == nil { | ||
lm.RUnlock() | ||
lm.Lock() | ||
lm.locMap[name] = loc | ||
lm.Unlock() | ||
return loc, nil | ||
} | ||
|
||
lm.RUnlock() | ||
return nil, fmt.Errorf("invalid name for timezone %s", name) | ||
} | ||
|
||
// LoadLocation loads time.Location by IANA timezone time. | ||
func LoadLocation(name string) (*time.Location, error) { | ||
return LocCache.getLoc(name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the result of |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package timeutil | ||
zhexuany marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
import ( | ||
. "github.com/pingcap/check" | ||
) | ||
|
||
type testSuite struct{} | ||
|
||
func (s *testSuite) TestgetTZNameFromFileName(c *C) { | ||
tz, err := getTZNameFromFileName("/user/share/zoneinfo/Asia/Shanghai") | ||
c.Assert(err, IsNil) | ||
c.Assert(tz, Equals, "Asia/Shanghai") | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scCtx.GetSessionVars().Location()
callstimeutil.Local()
if timezone of session is nil.timeutil.Local()
tried to retrieve IANA timezone name fromTZ
and/etc/localtime
already.If it still returns a
time.Local
, then we have no choice but to push downtime.Local
totikv
.