From 841224372ba24d15af3ec2d5fea88e614c4ae967 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 5 Jun 2019 21:58:27 +0800 Subject: [PATCH] update comment for gmlock --- g/net/ghttp/ghttp_response_view.go | 5 ++- g/net/ghttp/ghttp_server_session.go | 6 +-- g/os/gcfg/gcfg.go | 8 ++-- g/os/gmlock/gmlock.go | 36 ++++++++++++---- g/os/gmlock/gmlock_locker.go | 65 ++++++++++++++++++++++------- g/os/gmlock/gmlock_mutex.go | 38 ++++++++++------- g/os/gview/gview_doparse.go | 18 ++++++-- geg/other/test.go | 9 +--- 8 files changed, 130 insertions(+), 55 deletions(-) diff --git a/g/net/ghttp/ghttp_response_view.go b/g/net/ghttp/ghttp_response_view.go index 62ec7dd17..93d7a35b4 100644 --- a/g/net/ghttp/ghttp_response_view.go +++ b/g/net/ghttp/ghttp_response_view.go @@ -52,7 +52,10 @@ func (r *Response) buildInVars(params...map[string]interface{}) map[string]inter } else { vars = make(map[string]interface{}) } - vars["Config"] = gins.Config().GetMap("") + // 当配置文件不存在时就不赋值该模板变量,不然会报错 + if c := gins.Config(); c.FilePath() != "" { + vars["Config"] = c.GetMap("") + } vars["Cookie"] = r.request.Cookie.Map() vars["Session"] = r.request.Session.Map() vars["Get"] = r.request.GetQueryMap() diff --git a/g/net/ghttp/ghttp_server_session.go b/g/net/ghttp/ghttp_server_session.go index 58e588be6..706b18e76 100644 --- a/g/net/ghttp/ghttp_server_session.go +++ b/g/net/ghttp/ghttp_server_session.go @@ -20,10 +20,10 @@ import ( // SESSION对象 type Session struct { - id string // SessionId + id string // SessionId data *gmap.StrAnyMap // Session数据 - server *Server // 所属Server - request *Request // 关联的请求 + server *Server // 所属Server + request *Request // 关联的请求 } // 生成一个唯一的SessionId字符串,长度18位。 diff --git a/g/os/gcfg/gcfg.go b/g/os/gcfg/gcfg.go index 1233a3702..057216f16 100644 --- a/g/os/gcfg/gcfg.go +++ b/g/os/gcfg/gcfg.go @@ -55,20 +55,20 @@ func New(file...string) *Config { // Customized dir path from env/cmd. if envPath := cmdenv.Get("gf.gcfg.path").String(); envPath != "" { if gfile.Exists(envPath) { - c.SetPath(envPath) + _ = c.SetPath(envPath) } else { glog.Errorf("Configuration directory path does not exist: %s", envPath) } } else { // Dir path of working dir. - c.SetPath(gfile.Pwd()) + _ = c.SetPath(gfile.Pwd()) // Dir path of binary. if selfPath := gfile.SelfDir(); selfPath != "" && gfile.Exists(selfPath) { - c.AddPath(selfPath) + _ = c.AddPath(selfPath) } // Dir path of main package. if mainPath := gfile.MainPkgPath(); mainPath != "" && gfile.Exists(mainPath) { - c.AddPath(mainPath) + _ = c.AddPath(mainPath) } } return c diff --git a/g/os/gmlock/gmlock.go b/g/os/gmlock/gmlock.go index 8bfcbbd6e..a31aee8b8 100644 --- a/g/os/gmlock/gmlock.go +++ b/g/os/gmlock/gmlock.go @@ -13,42 +13,62 @@ var ( locker = New() ) -// 内存写锁,如果锁成功返回true,失败则返回false;过期时间单位为秒,默认为0表示不过期 +// TryLock tries locking the with write lock, +// it returns true if success, or if there's a write/read lock the , +// it returns false. The parameter specifies the max duration it locks. func TryLock(key string, expire...time.Duration) bool { return locker.TryLock(key, expire...) } -// 内存写锁,锁成功返回true,失败时阻塞,当失败时表示有其他写锁存在;过期时间单位为秒,默认为0表示不过期 +// Lock locks the with write lock. +// If there's a write/read lock the , +// it will blocks until the lock is released. +// The parameter specifies the max duration it locks. func Lock(key string, expire...time.Duration) { locker.Lock(key, expire...) } -// 解除基于内存锁的写锁 +// Unlock unlocks the write lock of the . func Unlock(key string) { locker.Unlock(key) } -// 内存读锁,如果锁成功返回true,失败则返回false; 过期时间单位为秒,默认为0表示不过期 +// TryRLock tries locking the with read lock. +// It returns true if success, or if there's a write lock on , it returns false. func TryRLock(key string) bool { return locker.TryRLock(key) } -// 内存写锁,锁成功返回true,失败时阻塞,当失败时表示有写锁存在; 过期时间单位为秒,默认为0表示不过期 +// RLock locks the with read lock. +// If there's a write lock on , +// it will blocks until the write lock is released. func RLock(key string) { locker.RLock(key) } -// 解除基于内存锁的读锁 +// RUnlock unlocks the read lock of the . func RUnlock(key string) { locker.RUnlock(key) } -// 通过闭包的方式写锁执行回调方法,执行完毕后释放写锁 +// LockFunc locks the with write lock and callback function . +// If there's a write/read lock the , +// it will blocks until the lock is released. +// +// It releases the lock after is executed. +// +// The parameter specifies the max duration it locks. func LockFunc(key string, f func(), expire...time.Duration) { locker.LockFunc(key, f, expire...) } -// 通过闭包的方式读锁执行回调方法,执行完毕后释放读锁 +// RLockFunc locks the with read lock and callback function . +// If there's a write lock the , +// it will blocks until the lock is released. +// +// It releases the lock after is executed. +// +// The parameter specifies the max duration it locks. func RLockFunc(key string, f func()) { locker.RLockFunc(key, f) } \ No newline at end of file diff --git a/g/os/gmlock/gmlock_locker.go b/g/os/gmlock/gmlock_locker.go index 133a15053..bd653eb13 100644 --- a/g/os/gmlock/gmlock_locker.go +++ b/g/os/gmlock/gmlock_locker.go @@ -12,67 +12,89 @@ import ( "time" ) -// 内存锁管理对象 +// Memory locker. type Locker struct { m *gmap.StrAnyMap } -// 创建一把内存锁, 底层使用的是Mutex +// New creates and returns a new memory locker. +// A memory locker can lock/unlock with dynamic string key. func New() *Locker { return &Locker{ m : gmap.NewStrAnyMap(), } } -// 内存写锁,如果锁成功返回true,失败则返回false; 过期时间默认为0表示不过期 +// TryLock tries locking the with write lock, +// it returns true if success, or if there's a write/read lock the , +// it returns false. The parameter specifies the max duration it locks. func (l *Locker) TryLock(key string, expire...time.Duration) bool { return l.doLock(key, l.getExpire(expire...), true) } -// 内存写锁,锁成功返回true,失败时阻塞,当失败时表示有其他写锁存在;过期时间默认为0表示不过期 +// Lock locks the with write lock. +// If there's a write/read lock the , +// it will blocks until the lock is released. +// The parameter specifies the max duration it locks. func (l *Locker) Lock(key string, expire...time.Duration) { l.doLock(key, l.getExpire(expire...), false) } -// 解除基于内存锁的写锁 +// Unlock unlocks the write lock of the . func (l *Locker) Unlock(key string) { if v := l.m.Get(key); v != nil { v.(*Mutex).Unlock() } } -// 内存读锁,如果锁成功返回true,失败则返回false; 过期时间单位为秒,默认为0表示不过期 +// TryRLock tries locking the with read lock. +// It returns true if success, or if there's a write lock on , it returns false. func (l *Locker) TryRLock(key string) bool { return l.doRLock(key, true) } -// 内存写锁,锁成功返回true,失败时阻塞,当失败时表示有写锁存在; 过期时间单位为秒,默认为0表示不过期 +// RLock locks the with read lock. +// If there's a write lock on , +// it will blocks until the write lock is released. func (l *Locker) RLock(key string) { l.doRLock(key, false) } -// 解除基于内存锁的读锁 +// RUnlock unlocks the read lock of the . func (l *Locker) RUnlock(key string) { if v := l.m.Get(key); v != nil { v.(*Mutex).RUnlock() } } -// 通过闭包的方式写锁执行回调方法,执行完毕后释放写锁 +// LockFunc locks the with write lock and callback function . +// If there's a write/read lock the , +// it will blocks until the lock is released. +// +// It releases the lock after is executed. +// +// The parameter specifies the max duration it locks. func (l *Locker) LockFunc(key string, f func(), expire...time.Duration) { l.Lock(key, expire...) defer l.Unlock(key) f() } -// 通过闭包的方式读锁执行回调方法,执行完毕后释放读锁 +// RLockFunc locks the with read lock and callback function . +// If there's a write lock the , +// it will blocks until the lock is released. +// +// It releases the lock after is executed. +// +// The parameter specifies the max duration it locks. func (l *Locker) RLockFunc(key string, f func()) { l.RLock(key) defer l.RUnlock(key) f() } -// 获得过期时间,没有设置时默认为0不过期 +// getExpire returns the duration object passed. +// If is not passed, it returns a default duration object. func (l *Locker) getExpire(expire...time.Duration) time.Duration { e := time.Duration(0) if len(expire) > 0 { @@ -81,7 +103,14 @@ func (l *Locker) getExpire(expire...time.Duration) time.Duration { return e } -// 内存写锁,当try==true时,如果锁成功返回true,失败则返回false;try==false时,成功时立即返回,否则阻塞等待 +// doLock locks writing on . +// It returns true if success, or else returns false. +// +// The parameter is true, +// it returns false immediately if it fails getting the write lock. +// If is false, it blocks until it gets the write lock. +// +// The parameter specifies the max duration it locks. func (l *Locker) doLock(key string, expire time.Duration, try bool) bool { mu := l.getOrNewMutex(key) ok := true @@ -102,7 +131,12 @@ func (l *Locker) doLock(key string, expire time.Duration, try bool) bool { return ok } -// 内存读锁,当try==true时,如果锁成功返回true,失败则返回false;try==false时,成功时立即返回,否则阻塞等待 +// doRLock locks reading on . +// It returns true if success, or else returns false. +// +// The parameter is true, +// it returns false immediately if it fails getting the read lock. +// If is false, it blocks until it gets the read lock. func (l *Locker) doRLock(key string, try bool) bool { mu := l.getOrNewMutex(key) ok := true @@ -114,8 +148,9 @@ func (l *Locker) doRLock(key string, try bool) bool { return ok } -// 根据指定key查询或者创建新的Mutex -func (l *Locker) getOrNewMutex(key string) (*Mutex) { +// getOrNewMutex returns the mutex of given if it exists, +// or else creates and returns a new one. +func (l *Locker) getOrNewMutex(key string) *Mutex { return l.m.GetOrSetFuncLock(key, func() interface{} { return NewMutex() }).(*Mutex) diff --git a/g/os/gmlock/gmlock_mutex.go b/g/os/gmlock/gmlock_mutex.go index 8bc7aaadb..fc4d992a2 100644 --- a/g/os/gmlock/gmlock_mutex.go +++ b/g/os/gmlock/gmlock_mutex.go @@ -11,15 +11,15 @@ import ( "sync" ) -// 互斥锁对象 +// The mutex. type Mutex struct { mu sync.RWMutex - wid *gtype.Int64 // 当前Lock产生的唯一id(主要用于计时Unlock的校验) - rcount *gtype.Int // RLock次数 - wcount *gtype.Int // Lock次数 + wid *gtype.Int64 // Unique id for this mutex. + rcount *gtype.Int // RLock count. + wcount *gtype.Int // Lock count. } -// 创建一把内存锁使用的底层RWMutex +// NewMutex creates and returns a new mutex. func NewMutex() *Mutex { return &Mutex{ wid : gtype.NewInt64(), @@ -28,46 +28,55 @@ func NewMutex() *Mutex { } } +// Lock locks mutex for writing. +// If the lock is already locked for reading or writing, +// Lock blocks until the lock is available. func (l *Mutex) Lock() { l.wcount.Add(1) l.mu.Lock() l.wid.Add(1) } -// 安全的Unlock +// Unlock unlocks the write lock. +// It is safe to be called multiple times. func (l *Mutex) Unlock() { if l.wcount.Val() > 0 { if l.wcount.Add(-1) >= 0 { l.mu.Unlock() } else { - // 标准库这里会panic l.wcount.Add(1) } } } +// RLock locks mutex for reading. func (l *Mutex) RLock() { l.rcount.Add(1) l.mu.RLock() } -// 安全的RUnlock +// RUnlock undoes a single RLock call; +// it does not affect other simultaneous readers. +// It is a run-time error if rw is not locked for reading +// on entry to RUnlock. +// It is safe to be called multiple times. func (l *Mutex) RUnlock() { if l.rcount.Val() > 0 { if l.rcount.Add(-1) >= 0 { l.mu.RUnlock() } else { - // 标准库这里会panic l.rcount.Add(1) } } } -// 不阻塞Lock +// TryLock tries locking the mutex with write lock, +// it returns true if success, or if there's a write/read lock the mutex, +// it returns false. func (l *Mutex) TryLock() bool { - // 初步读写次数检查, 但无法保证原子性 + // The first check, but it cannot ensure the atomicity. if l.wcount.Val() == 0 && l.rcount.Val() == 0 { - // 第二次检查, 保证原子操作 + // The second check, it can ensure the atomicity. if l.wcount.Add(1) == 1 { l.mu.Lock() l.wid.Add(1) @@ -79,9 +88,10 @@ func (l *Mutex) TryLock() bool { return false } -// 不阻塞RLock +// TryRLock tries locking the mutex with read lock. +// It returns true if success, or if there's a write lock on mutex, it returns false. func (l *Mutex) TryRLock() bool { - // 只要不存在写锁 + // There must be no write lock on mutex. if l.wcount.Val() == 0 { l.rcount.Add(1) l.mu.RLock() diff --git a/g/os/gview/gview_doparse.go b/g/os/gview/gview_doparse.go index 2dc12e0e9..1ae3d750e 100644 --- a/g/os/gview/gview_doparse.go +++ b/g/os/gview/gview_doparse.go @@ -21,6 +21,11 @@ import ( "text/template" ) +const ( + // Template name for content parsing. + gCONTENT_TEMPLATE_NAME = "template content" +) + var ( // Templates cache map for template folder. templates = gmap.NewStrAnyMap() @@ -103,7 +108,8 @@ func (view *View) Parse(file string, params...Params) (parsed string, err error) if err != nil { return "", err } - gmlock.LockFunc("gview-template-parsing:" + folder, func() { + // Using memory lock to ensure concurrent safety for template parsing. + gmlock.LockFunc("gview-parsing:" + folder, func() { tpl, err = tpl.Parse(gfcache.GetContents(path)) }) if err != nil { @@ -149,8 +155,14 @@ func (view *View) Parse(file string, params...Params) (parsed string, err error) func (view *View) ParseContent(content string, params...Params) (string, error) { view.mu.RLock() defer view.mu.RUnlock() - tpl := template.New("template content").Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap) - tpl, err := tpl.Parse(content) + err := (error)(nil) + tpl := templates.GetOrSetFuncLock(gCONTENT_TEMPLATE_NAME, func() interface {} { + return template.New(gCONTENT_TEMPLATE_NAME).Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap) + }).(*template.Template) + // Using memory lock to ensure concurrent safety for content parsing. + gmlock.LockFunc("gview-parsing:content", func() { + tpl, err = tpl.Parse(content) + }) if err != nil { return "", err } diff --git a/geg/other/test.go b/geg/other/test.go index cd63d8660..729ac6946 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -3,20 +3,15 @@ package main import ( "github.com/gogf/gf/g" "github.com/gogf/gf/g/net/ghttp" - "github.com/gogf/gf/g/os/gcache" ) func main() { 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, + r.Response.WriteTplContent(rs, g.Map{ + "Contentb": 1, }) }) s.SetPort(8199)