gf/g/os/gfpool/gfpool.go

171 lines
5.2 KiB
Go
Raw Normal View History

2018-09-17 18:43:59 +08:00
// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
// 文件指针池
package gfpool
import (
2018-10-31 19:00:28 +08:00
"fmt"
2018-09-17 18:43:59 +08:00
"gitee.com/johng/gf/g/container/gmap"
"gitee.com/johng/gf/g/container/gpool"
2018-10-31 19:00:28 +08:00
"gitee.com/johng/gf/g/container/gtype"
"gitee.com/johng/gf/third/github.com/fsnotify/fsnotify"
"os"
"sync"
2018-09-17 18:43:59 +08:00
)
// 文件指针池
type Pool struct {
2018-10-31 19:00:28 +08:00
pool *gpool.Pool // 底层对象池
inited *gtype.Bool // 是否初始化(在执行第一次File方法后初始化)
watcher *fsnotify.Watcher // 文件监控对象
closeChan chan struct{} // 关闭事件
expire int // 过期时间
2018-09-17 18:43:59 +08:00
}
// 文件指针池指针
type File struct {
os.File // 底层文件指针
mu sync.RWMutex // 互斥锁
pool *Pool // 所属池
flag int // 打开标志
perm os.FileMode // 打开权限
path string // 绝对路径
}
// 全局指针池expire < 0表示不过期expire = 0表示使用完立即回收expire > 0表示超时回收
var pools = gmap.NewStringInterfaceMap()
// 获得文件对象,并自动创建指针池(过期时间单位:毫秒)
2018-09-17 18:43:59 +08:00
func Open(path string, flag int, perm os.FileMode, expire...int) (*File, error) {
fpExpire := 0
if len(expire) > 0 {
fpExpire = expire[0]
}
2018-10-31 19:00:28 +08:00
pool := pools.GetOrSetFuncLock(fmt.Sprintf("%s&%d&%d&%d", path, flag, expire, perm), func() interface{} {
return New(path, flag, perm, fpExpire)
}).(*Pool)
2018-09-17 18:43:59 +08:00
return pool.File()
}
func OpenFile(path string, flag int, perm os.FileMode, expire...int) (*File, error) {
return Open(path, flag, perm, expire...)
}
// 创建一个文件指针池expire = 0表示不过期expire < 0表示使用完立即回收expire > 0表示超时回收默认值为0不过期
// 过期时间单位:毫秒
2018-09-17 18:43:59 +08:00
func New(path string, flag int, perm os.FileMode, expire...int) *Pool {
fpExpire := 0
if len(expire) > 0 {
fpExpire = expire[0]
}
2018-10-31 19:00:28 +08:00
p := &Pool {
expire : fpExpire,
inited : gtype.NewBool(),
closeChan : make(chan struct{}),
}
p.pool = newFilePool(p, path, flag, perm, fpExpire)
if watcher, err := fsnotify.NewWatcher(); err == nil {
p.watcher = watcher
} else {
return nil
}
return p
}
// 创建文件指针池
func newFilePool(p *Pool, path string, flag int, perm os.FileMode, expire int) *gpool.Pool {
pool := gpool.New(expire, func() (interface{}, error) {
2018-09-17 18:43:59 +08:00
file, err := os.OpenFile(path, flag, perm)
if err != nil {
return nil, err
}
return &File{
File : *file,
pool : p,
flag : flag,
perm : perm,
path : path,
}, nil
})
2018-10-31 19:00:28 +08:00
pool.SetExpireFunc(func(i interface{}) {
2018-09-17 18:43:59 +08:00
i.(*File).File.Close()
})
2018-10-31 19:00:28 +08:00
return pool
2018-09-17 18:43:59 +08:00
}
// 获得一个文件打开指针
func (p *Pool) File() (*File, error) {
if v, err := p.pool.Get(); err != nil {
return nil, err
} else {
f := v.(*File)
if f.flag & os.O_CREATE > 0 {
2018-10-31 19:00:28 +08:00
if _, err := os.Stat(f.path); os.IsNotExist(err) {
if file, err := os.OpenFile(f.path, f.flag, f.perm); err != nil {
return nil, err
} else {
f.File = *file
}
}
2018-09-17 18:43:59 +08:00
}
if f.flag & os.O_TRUNC > 0 {
2018-10-31 19:00:28 +08:00
if stat, err := f.Stat(); err == nil {
if stat.Size() > 0 {
if err := f.Truncate(0); err != nil {
return nil, err
}
}
}
2018-09-17 18:43:59 +08:00
}
2018-09-25 15:45:07 +08:00
if f.flag & os.O_APPEND > 0 {
2018-10-31 19:00:28 +08:00
if _, err := f.Seek(0, 2); err != nil {
return nil, err
}
2018-09-25 15:45:07 +08:00
} else {
2018-10-31 19:00:28 +08:00
f.Seek(0, 0)
}
if !p.inited.Set(true) {
if err := p.watcher.Add(f.path); err != nil {
p.inited.Set(false)
}
go func() {
for {
select {
// 关闭事件
case <- p.closeChan:
return
// 监听事件
case ev := <- p.watcher.Events:
// 如果文件被删除或者重命名,重建指针池
if ev.Op & fsnotify.Remove == fsnotify.Remove || ev.Op & fsnotify.Rename == fsnotify.Rename {
p.pool.Close()
p.pool = newFilePool(p, f.Name(), f.flag, f.perm, f.pool.expire)
p.watcher.Remove(ev.Name)
}
}
}
}()
2018-09-25 15:45:07 +08:00
}
2018-09-17 18:43:59 +08:00
return f, nil
}
}
// 关闭指针池(返回error是标准库io.ReadWriteCloser接口实现)
func (p *Pool) Close() error {
2018-10-31 19:00:28 +08:00
close(p.closeChan)
2018-09-17 18:43:59 +08:00
p.pool.Close()
return nil
}
// 获得底层文件指针(返回error是标准库io.ReadWriteCloser接口实现)
func (f *File) Close() error {
f.pool.pool.Put(f)
return nil
}