fix issue in concurrent safety for gview.Parse; rename glog.*fln functions to glog.*f

This commit is contained in:
John
2019-06-05 20:22:57 +08:00
parent 6fecf8bb01
commit d1f0fa1a47
16 changed files with 85 additions and 43 deletions

View File

@ -136,7 +136,10 @@ func LoadContent(data interface{}, unsafe...bool) (*Json, error) {
var err error
var result interface{}
b := gconv.Bytes(data)
t := "json"
t := ""
if len(b) == 0 {
return New(nil, unsafe...), nil
}
// auto check data type
if json.Valid(b) {
t = "json"

View File

@ -219,13 +219,13 @@ func Redis(name...string) *gredis.Redis {
Pass : array[4],
})
} else {
glog.Errorfln(`invalid redis node configuration: "%s"`, line)
glog.Errorf(`invalid redis node configuration: "%s"`, line)
}
} else {
glog.Errorfln(`configuration for redis not found for group "%s"`, group)
glog.Errorf(`configuration for redis not found for group "%s"`, group)
}
} else {
glog.Errorfln(`incomplete configuration for redis: "redis" node not found in config file "%s"`, config.FilePath())
glog.Errorf(`incomplete configuration for redis: "redis" node not found in config file "%s"`, config.FilePath())
}
return nil
})

View File

@ -389,7 +389,7 @@ func (s *Server) Run() error {
// 阻塞等待服务执行完成
<- s.closeChan
glog.Printfln("%d: all servers shutdown", gproc.Pid())
glog.Printf("%d: all servers shutdown", gproc.Pid())
return nil
}
@ -400,7 +400,7 @@ func Wait() {
// 阻塞等待服务执行完成
<- allDoneChan
glog.Printfln("%d: all servers shutdown", gproc.Pid())
glog.Printf("%d: all servers shutdown", gproc.Pid())
}

View File

@ -129,7 +129,7 @@ func forkReloadProcess(newExeFilePath...string) error {
buffer, _ := gjson.Encode(sfm)
p.Env = append(p.Env, gADMIN_ACTION_RELOAD_ENVKEY + "=" + string(buffer))
if _, err := p.Start(); err != nil {
glog.Errorfln("%d: fork process failed, error:%s, %s", gproc.Pid(), err.Error(), string(buffer))
glog.Errorf("%d: fork process failed, error:%s, %s", gproc.Pid(), err.Error(), string(buffer))
return err
}
return nil
@ -147,7 +147,7 @@ func forkRestartProcess(newExeFilePath...string) error {
env = append(env, gADMIN_ACTION_RESTART_ENVKEY + "=1")
p := gproc.NewProcess(path, os.Args, env)
if _, err := p.Start(); err != nil {
glog.Errorfln("%d: fork process failed, error:%s", gproc.Pid(), err.Error())
glog.Errorf("%d: fork process failed, error:%s", gproc.Pid(), err.Error())
return err
}
return nil
@ -197,14 +197,14 @@ func restartWebServers(signal string, newExeFilePath...string) error {
}
} else {
if err := forkReloadProcess(newExeFilePath...); err != nil {
glog.Printfln("%d: server restarts failed", gproc.Pid())
glog.Printf("%d: server restarts failed", gproc.Pid())
serverProcessStatus.Set(gADMIN_ACTION_NONE)
return err
} else {
if len(signal) > 0 {
glog.Printfln("%d: server restarting by signal: %s", gproc.Pid(), signal)
glog.Printf("%d: server restarting by signal: %s", gproc.Pid(), signal)
} else {
glog.Printfln("%d: server restarting by web admin", gproc.Pid())
glog.Printf("%d: server restarting by web admin", gproc.Pid())
}
}
@ -216,12 +216,12 @@ func restartWebServers(signal string, newExeFilePath...string) error {
func shutdownWebServers(signal...string) {
serverProcessStatus.Set(gADMIN_ACTION_SHUTINGDOWN)
if len(signal) > 0 {
glog.Printfln("%d: server shutting down by signal: %s", gproc.Pid(), signal[0])
glog.Printf("%d: server shutting down by signal: %s", gproc.Pid(), signal[0])
// 在终端信号下,立即执行关闭操作
forceCloseWebServers()
allDoneChan <- struct{}{}
} else {
glog.Printfln("%d: server shutting down by api", gproc.Pid())
glog.Printf("%d: server shutting down by api", gproc.Pid())
// 非终端信号下异步1秒后再执行关闭
// 目的是让接口能够正确返回结果,否则接口会报错(因为web server关闭了)
gtimer.SetTimeout(time.Second, func() {

View File

@ -130,7 +130,7 @@ func (s *gracefulServer) doServe() error {
if s.fd != 0 {
action = "reloaded"
}
glog.Printfln("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.addr)
glog.Printf("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.addr)
s.status = SERVER_STATUS_RUNNING
err := s.httpServer.Serve(s.listener)
s.status = SERVER_STATUS_STOPPED
@ -173,7 +173,7 @@ func (s *gracefulServer) shutdown() {
return
}
if err := s.httpServer.Shutdown(context.Background()); err != nil {
glog.Errorfln("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.addr, err)
glog.Errorf("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.addr, err)
}
}
@ -183,7 +183,7 @@ func (s *gracefulServer) close() {
return
}
if err := s.httpServer.Close(); err != nil {
glog.Errorfln("%d: %s server [%s] closed error: %v", gproc.Pid(), s.getProto(), s.addr, err)
glog.Errorf("%d: %s server [%s] closed error: %v", gproc.Pid(), s.getProto(), s.addr, err)
}
}

View File

@ -84,7 +84,7 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... strin
caller := s.getHandlerRegisterCallerLine(handler)
if len(hook) == 0 {
if item, ok := s.routesMap[regkey]; ok {
glog.Errorfln(`duplicated route registry "%s", already registered at %s`, pattern, item[0].file)
glog.Errorf(`duplicated route registry "%s", already registered at %s`, pattern, item[0].file)
return
}
}

View File

@ -50,7 +50,7 @@ func (d *Domain) Group(prefix...string) *RouterGroup {
func (g *RouterGroup) Bind(items []GroupItem) {
for _, item := range items {
if len(item) < 3 {
glog.Fatalfln("invalid router item: %s", item)
glog.Fatalf("invalid router item: %s", item)
}
if strings.EqualFold(gconv.String(item[0]), "REST") {
g.bind("REST", gconv.String(item[0]) + ":" + gconv.String(item[1]), item[2])
@ -124,7 +124,7 @@ func (g *RouterGroup) bind(bindType string, pattern string, object interface{},
if len(g.prefix) > 0 {
domain, method, path, err := g.server.parsePattern(pattern)
if err != nil {
glog.Fatalfln("invalid pattern: %s", pattern)
glog.Fatalf("invalid pattern: %s", pattern)
}
if bindType == "HANDLER" {
pattern = g.server.serveHandlerKey(method, g.prefix + "/" + strings.TrimLeft(path, "/"), domain)
@ -196,7 +196,7 @@ func (g *RouterGroup) bind(bindType string, pattern string, object interface{},
g.domain.BindHookHandler(pattern, methods[0], h)
}
} else {
glog.Fatalfln("invalid hook handler for pattern:%s", pattern)
glog.Fatalf("invalid hook handler for pattern:%s", pattern)
}
}
}

View File

@ -50,11 +50,11 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) {
if _, ok := v.Method(i).Interface().(func()); !ok {
if len(methodMap) > 0 {
// 指定的方法名称注册,那么需要使用错误提示
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, mname, v.Method(i).Type().String())
} else {
// 否则只是Debug提示
glog.Debugfln(`ignore route method: %s.%s.%s defined as "%s", no match "func()"`,
glog.Debugf(`ignore route method: %s.%s.%s defined as "%s", no match "func()"`,
pkgPath, ctlName, mname, v.Method(i).Type().String())
}
continue
@ -108,7 +108,7 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, method string
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
if _, ok := fval.Interface().(func()); !ok {
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, mname, fval.Type().String())
return
}
@ -147,7 +147,7 @@ func (s *Server)BindControllerRest(pattern string, c Controller) {
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
if _, ok := v.Method(i).Interface().(func()); !ok {
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, mname, v.Method(i).Type().String())
return
}

View File

@ -57,11 +57,11 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) {
if !ok {
if len(methodMap) > 0 {
// 指定的方法名称注册,那么需要使用错误提示
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, mname, v.Method(i).Type().String())
} else {
// 否则只是Debug提示
glog.Debugfln(`ignore route method: %s.%s.%s defined as "%s", no match "func(*ghttp.Request)"`,
glog.Debugf(`ignore route method: %s.%s.%s defined as "%s", no match "func(*ghttp.Request)"`,
pkgPath, objName, mname, v.Method(i).Type().String())
}
continue
@ -127,7 +127,7 @@ func (s *Server)BindObjectMethod(pattern string, obj interface{}, method string)
}
faddr, ok := fval.Interface().(func(*Request))
if !ok {
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, mname, fval.Type().String())
return
}
@ -174,7 +174,7 @@ func (s *Server)BindObjectRest(pattern string, obj interface{}) {
}
faddr, ok := v.Method(i).Interface().(func(*Request))
if !ok {
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, mname, v.Method(i).Type().String())
continue
}

View File

@ -57,7 +57,7 @@ func New(file...string) *Config {
if gfile.Exists(envPath) {
c.SetPath(envPath)
} else {
glog.Errorfln("Configuration directory path does not exist: %s", envPath)
glog.Errorf("Configuration directory path does not exist: %s", envPath)
}
} else {
// Dir path of working dir.
@ -276,9 +276,9 @@ func (c *Config) getJson(file...string) *gjson.Json {
return j
} else {
if filePath != "" {
glog.Criticalfln(`[gcfg] Load config file "%s" failed: %s`, filePath, err.Error())
glog.Criticalf(`[gcfg] Load config file "%s" failed: %s`, filePath, err.Error())
} else {
glog.Criticalfln(`[gcfg] Load configuration failed: %s`, err.Error())
glog.Criticalf(`[gcfg] Load configuration failed: %s`, err.Error())
}
}
return nil

View File

@ -115,7 +115,7 @@ func (entry *Entry) check() {
return
case STATUS_CLOSED:
glog.Path(path).Level(level).Debugfln("[gcron] %s(%s) %s removed", entry.Name, entry.schedule.pattern, entry.jobName)
glog.Path(path).Level(level).Debugf("[gcron] %s(%s) %s removed", entry.Name, entry.schedule.pattern, entry.jobName)
entry.Close()
case STATUS_READY: fallthrough
@ -130,12 +130,12 @@ func (entry *Entry) check() {
if times < 2000000000 && times > 1000000000 {
entry.times.Set(gDEFAULT_TIMES)
}
glog.Path(path).Level(level).Debugfln("[gcron] %s(%s) %s start", entry.Name, entry.schedule.pattern, entry.jobName)
glog.Path(path).Level(level).Debugf("[gcron] %s(%s) %s start", entry.Name, entry.schedule.pattern, entry.jobName)
defer func() {
if err := recover(); err != nil {
glog.Path(path).Level(level).Errorfln("[gcron] %s(%s) %s end with error: %v", entry.Name, entry.schedule.pattern, entry.jobName, err)
glog.Path(path).Level(level).Errorf("[gcron] %s(%s) %s end with error: %v", entry.Name, entry.schedule.pattern, entry.jobName, err)
} else {
glog.Path(path).Level(level).Debugfln("[gcron] %s(%s) %s end", entry.Name, entry.schedule.pattern, entry.jobName)
glog.Path(path).Level(level).Debugf("[gcron] %s(%s) %s end", entry.Name, entry.schedule.pattern, entry.jobName)
}
if entry.entry.Status() == STATUS_CLOSED {
entry.Close()

View File

@ -5,8 +5,6 @@
// You can obtain one at https://github.com/gogf/gf.
// Package gmlock implements a thread-safe memory locker.
//
// 内存锁.
package gmlock
import "time"
@ -43,4 +41,14 @@ func RLock(key string) {
// 解除基于内存锁的读锁
func RUnlock(key string) {
locker.RUnlock(key)
}
// 通过闭包的方式写锁执行回调方法<f>,执行完毕后释放写锁
func LockFunc(key string, f func(), expire...time.Duration) {
locker.LockFunc(key, f, expire...)
}
// 通过闭包的方式读锁执行回调方法<f>,执行完毕后释放读锁
func RLockFunc(key string, f func()) {
locker.RLockFunc(key, f)
}

View File

@ -58,6 +58,20 @@ func (l *Locker) RUnlock(key string) {
}
}
// 通过闭包的方式写锁执行回调方法<f>,执行完毕后释放写锁
func (l *Locker) LockFunc(key string, f func(), expire...time.Duration) {
l.Lock(key, expire...)
defer l.Unlock(key)
f()
}
// 通过闭包的方式读锁执行回调方法<f>,执行完毕后释放读锁
func (l *Locker) RLockFunc(key string, f func()) {
l.RLock(key)
defer l.RUnlock(key)
f()
}
// 获得过期时间没有设置时默认为0不过期
func (l *Locker) getExpire(expire...time.Duration) time.Duration {
e := time.Duration(0)

View File

@ -69,7 +69,7 @@ func New(path...string) *View {
if gfile.Exists(envPath) {
view.SetPath(envPath)
} else {
glog.Errorfln("Template directory path does not exist: %s", envPath)
glog.Errorf("Template directory path does not exist: %s", envPath)
}
} else {
// Dir path of working dir.

View File

@ -15,6 +15,7 @@ import (
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/os/gfsnotify"
"github.com/gogf/gf/g/os/glog"
"github.com/gogf/gf/g/os/gmlock"
"github.com/gogf/gf/g/os/gspath"
"github.com/gogf/gf/g/text/gstr"
"text/template"
@ -40,7 +41,7 @@ func (view *View) getTemplate(path string, pattern string) (tpl *template.Templa
if tpl, err = tpl.ParseFiles(files...); err != nil {
return nil
}
gfsnotify.Add(path, func(event *gfsnotify.Event) {
_, _ = gfsnotify.Add(path, func(event *gfsnotify.Event) {
templates.Remove(path)
gfsnotify.Exit()
})
@ -102,7 +103,9 @@ func (view *View) Parse(file string, params...Params) (parsed string, err error)
if err != nil {
return "", err
}
tpl, err = tpl.Parse(gfcache.GetContents(path))
gmlock.LockFunc("gview-template-parsing:" + folder, func() {
tpl, err = tpl.Parse(gfcache.GetContents(path))
})
if err != nil {
return "", err
}

View File

@ -1,10 +1,24 @@
package main
import (
"fmt"
"github.com/gogf/gf/g/os/gtime"
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
"github.com/gogf/gf/g/os/gcache"
)
func main() {
fmt.Println(gtime.Second())
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
rs :="GF(Go Frame)是一款模块化、松耦合、生产级的Go应用开发框架。提供了常用的核心开发组件缓存、日志、文件、时间、队列、数组、集合、字符串、定时器、命令行、文件锁、内存锁、对象池、连接池、数据校验、数据编码、文件监控、定时任务、数据库ORM、TCP/UDP组件、进程管理/通信、 并发安全容器等等。并提供了Web服务开发的系列核心组件Router、Cookie、Session、路由注册、配置管理、模板引擎等等支持热重启、热更新、多域名、多端口、多服务、HTTPS、Rewrite等特性。"
Weijin_word := gcache.Get("weijin_word")
if Weijin_word == nil {
Weijin_word = gcache.GetOrSet("weijin_word", rs, 0)
}
//此行压测会提示map并发错误 webbench -c 8000 -t 60 http://IP 局域网两台机器测试
r.Response.WriteTpl("layout.html", g.Map{
"Contentb": Weijin_word,
})
})
s.SetPort(8199)
s.Run()
}