Browse Source

Merge pull request #6 from tendermint/develop

Develop
pull/1842/head
Ethan Buchman 8 years ago
committed by GitHub
parent
commit
e289af53b6
5 changed files with 52 additions and 232 deletions
  1. +12
    -153
      os.go
  2. +0
    -64
      os_test.go
  3. +14
    -15
      service.go
  4. +24
    -0
      service_test.go
  5. +2
    -0
      throttle_timer.go

+ 12
- 153
os.go View File

@ -7,19 +7,12 @@ import (
"os"
"os/signal"
"strings"
"sync"
"syscall"
"time"
)
var (
GoPath = os.Getenv("GOPATH")
)
func init() {
initAFSIGHUPWatcher()
}
func TrapSignal(cb func()) {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
@ -112,159 +105,25 @@ func WriteFileAtomic(filePath string, newBytes []byte, mode os.FileMode) error {
//--------------------------------------------------------------------------------
/* AutoFile usage
// Create/Append to ./autofile_test
af, err := OpenAutoFile("autofile_test")
if err != nil {
panic(err)
}
// Stream of writes.
// During this time, the file may be moved e.g. by logRotate.
for i := 0; i < 60; i++ {
af.Write([]byte(Fmt("LOOP(%v)", i)))
time.Sleep(time.Second)
}
// Close the AutoFile
err = af.Close()
if err != nil {
panic(err)
}
*/
const autoFileOpenDuration = 1000 * time.Millisecond
// Automatically closes and re-opens file for writing.
// This is useful for using a log file with the logrotate tool.
type AutoFile struct {
ID string
Path string
ticker *time.Ticker
mtx sync.Mutex
file *os.File
}
func OpenAutoFile(path string) (af *AutoFile, err error) {
af = &AutoFile{
ID: RandStr(12) + ":" + path,
Path: path,
ticker: time.NewTicker(autoFileOpenDuration),
}
if err = af.openFile(); err != nil {
return
}
go af.processTicks()
autoFileWatchers.addAutoFile(af)
return
}
func (af *AutoFile) Close() error {
af.ticker.Stop()
err := af.closeFile()
autoFileWatchers.removeAutoFile(af)
return err
}
func (af *AutoFile) processTicks() {
for {
_, ok := <-af.ticker.C
if !ok {
return // Done.
}
af.closeFile()
}
}
func (af *AutoFile) closeFile() (err error) {
af.mtx.Lock()
defer af.mtx.Unlock()
file := af.file
if file == nil {
return nil
}
af.file = nil
return file.Close()
}
func (af *AutoFile) Write(b []byte) (n int, err error) {
af.mtx.Lock()
defer af.mtx.Unlock()
if af.file == nil {
if err = af.openFile(); err != nil {
return
}
}
return af.file.Write(b)
}
func (af *AutoFile) openFile() error {
file, err := os.OpenFile(af.Path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
func Tempfile(prefix string) (*os.File, string) {
file, err := ioutil.TempFile("", prefix)
if err != nil {
return err
}
af.file = file
return nil
}
//--------------------------------------------------------------------------------
var autoFileWatchers *afSIGHUPWatcher
func initAFSIGHUPWatcher() {
autoFileWatchers = newAFSIGHUPWatcher()
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP)
go func() {
for _ = range c {
autoFileWatchers.closeAll()
}
}()
}
type afSIGHUPWatcher struct {
mtx sync.Mutex
autoFiles map[string]*AutoFile
}
func newAFSIGHUPWatcher() *afSIGHUPWatcher {
return &afSIGHUPWatcher{
autoFiles: make(map[string]*AutoFile, 10),
PanicCrisis(err)
}
return file, file.Name()
}
func (afw *afSIGHUPWatcher) addAutoFile(af *AutoFile) {
afw.mtx.Lock()
afw.autoFiles[af.ID] = af
afw.mtx.Unlock()
}
func (afw *afSIGHUPWatcher) removeAutoFile(af *AutoFile) {
afw.mtx.Lock()
delete(afw.autoFiles, af.ID)
afw.mtx.Unlock()
}
func (afw *afSIGHUPWatcher) closeAll() {
afw.mtx.Lock()
for _, af := range afw.autoFiles {
af.closeFile()
func Tempdir(prefix string) (*os.File, string) {
tempDir := os.TempDir() + "/" + prefix + RandStr(12)
err := EnsureDir(tempDir, 0700)
if err != nil {
panic(Fmt("Error creating temp dir: %v", err))
}
afw.mtx.Unlock()
}
//--------------------------------------------------------------------------------
func Tempfile(prefix string) (*os.File, string) {
file, err := ioutil.TempFile("", prefix)
dir, err := os.Open(tempDir)
if err != nil {
PanicCrisis(err)
panic(Fmt("Error opening temp dir: %v", err))
}
return file, file.Name()
return dir, tempDir
}
//--------------------------------------------------------------------------------


+ 0
- 64
os_test.go View File

@ -1,64 +0,0 @@
package common
import (
"os"
"syscall"
"testing"
)
func TestSIGHUP(t *testing.T) {
// First, create an AutoFile writing to a tempfile dir
file, name := Tempfile("sighup_test")
err := file.Close()
if err != nil {
t.Fatalf("Error creating tempfile: %v", err)
}
// Here is the actual AutoFile
af, err := OpenAutoFile(name)
if err != nil {
t.Fatalf("Error creating autofile: %v", err)
}
// Write to the file.
_, err = af.Write([]byte("Line 1\n"))
if err != nil {
t.Fatalf("Error writing to autofile: %v", err)
}
_, err = af.Write([]byte("Line 2\n"))
if err != nil {
t.Fatalf("Error writing to autofile: %v", err)
}
// Send SIGHUP to self.
syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
// Move the file over
err = os.Rename(name, name+"_old")
if err != nil {
t.Fatalf("Error moving autofile: %v", err)
}
// Write more to the file.
_, err = af.Write([]byte("Line 3\n"))
if err != nil {
t.Fatalf("Error writing to autofile: %v", err)
}
_, err = af.Write([]byte("Line 4\n"))
if err != nil {
t.Fatalf("Error writing to autofile: %v", err)
}
err = af.Close()
if err != nil {
t.Fatalf("Error closing autofile")
}
// Both files should exist
if body := MustReadFile(name + "_old"); string(body) != "Line 1\nLine 2\n" {
t.Errorf("Unexpected body %s", body)
}
if body := MustReadFile(name); string(body) != "Line 3\nLine 4\n" {
t.Errorf("Unexpected body %s", body)
}
}

+ 14
- 15
service.go View File

@ -65,6 +65,7 @@ type BaseService struct {
name string
started uint32 // atomic
stopped uint32 // atomic
Quit chan struct{}
// The "subclass" of BaseService
impl Service
@ -74,6 +75,7 @@ func NewBaseService(log log15.Logger, name string, impl Service) *BaseService {
return &BaseService{
log: log,
name: name,
Quit: make(chan struct{}),
impl: impl,
}
}
@ -102,6 +104,8 @@ func (bs *BaseService) Start() (bool, error) {
}
// Implements Service
// NOTE: Do not put anything in here,
// that way users don't need to call BaseService.OnStart()
func (bs *BaseService) OnStart() error { return nil }
// Implements Service
@ -111,6 +115,7 @@ func (bs *BaseService) Stop() bool {
bs.log.Info(Fmt("Stopping %v", bs.name), "impl", bs.impl)
}
bs.impl.OnStop()
close(bs.Quit)
return true
} else {
if bs.log != nil {
@ -121,6 +126,8 @@ func (bs *BaseService) Stop() bool {
}
// Implements Service
// NOTE: Do not put anything in here,
// that way users don't need to call BaseService.OnStop()
func (bs *BaseService) OnStop() {}
// Implements Service
@ -151,6 +158,10 @@ func (bs *BaseService) IsRunning() bool {
return atomic.LoadUint32(&bs.started) == 1 && atomic.LoadUint32(&bs.stopped) == 0
}
func (bs *BaseService) Wait() {
<-bs.Quit
}
// Implements Servce
func (bs *BaseService) String() string {
return bs.name
@ -160,25 +171,13 @@ func (bs *BaseService) String() string {
type QuitService struct {
BaseService
Quit chan struct{}
}
func NewQuitService(log log15.Logger, name string, impl Service) *QuitService {
if log != nil {
log.Warn("QuitService is deprecated, use BaseService instead")
}
return &QuitService{
BaseService: *NewBaseService(log, name, impl),
Quit: nil,
}
}
// NOTE: when overriding OnStart, must call .QuitService.OnStart().
func (qs *QuitService) OnStart() error {
qs.Quit = make(chan struct{})
return nil
}
// NOTE: when overriding OnStop, must call .QuitService.OnStop().
func (qs *QuitService) OnStop() {
if qs.Quit != nil {
close(qs.Quit)
}
}

+ 24
- 0
service_test.go View File

@ -0,0 +1,24 @@
package common
import (
"testing"
)
func TestBaseServiceWait(t *testing.T) {
type TestService struct {
BaseService
}
ts := &TestService{}
ts.BaseService = *NewBaseService(nil, "TestService", ts)
ts.Start()
go func() {
ts.Stop()
}()
for i := 0; i < 10; i++ {
ts.Wait()
}
}

+ 2
- 0
throttle_timer.go View File

@ -26,7 +26,9 @@ func NewThrottleTimer(name string, dur time.Duration) *ThrottleTimer {
var ch = make(chan struct{})
var quit = make(chan struct{})
var t = &ThrottleTimer{Name: name, Ch: ch, dur: dur, quit: quit}
t.mtx.Lock()
t.timer = time.AfterFunc(dur, t.fireRoutine)
t.mtx.Unlock()
t.timer.Stop()
return t
}


Loading…
Cancel
Save