github.com/TeaOSLab/EdgeNode@v1.3.8/internal/utils/fs/locker.go (about)

     1  // Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
     2  
     3  package fsutils
     4  
     5  import (
     6  	"os"
     7  	"syscall"
     8  	"time"
     9  )
    10  
    11  type Locker struct {
    12  	path string
    13  	fp   *os.File
    14  }
    15  
    16  func NewLocker(path string) *Locker {
    17  	return &Locker{
    18  		path: path + ".lock",
    19  	}
    20  }
    21  
    22  func (this *Locker) TryLock() (ok bool, err error) {
    23  	if this.fp == nil {
    24  		fp, err := os.OpenFile(this.path, os.O_CREATE|os.O_WRONLY, 0666)
    25  		if err != nil {
    26  			return false, err
    27  		}
    28  		this.fp = fp
    29  	}
    30  	return this.tryLock()
    31  }
    32  
    33  func (this *Locker) Lock() error {
    34  	if this.fp == nil {
    35  		fp, err := os.OpenFile(this.path, os.O_CREATE|os.O_WRONLY, 0666)
    36  		if err != nil {
    37  			return err
    38  		}
    39  		this.fp = fp
    40  	}
    41  
    42  	for {
    43  		b, err := this.tryLock()
    44  		if err != nil {
    45  			_ = this.fp.Close()
    46  			return err
    47  		}
    48  		if b {
    49  			return nil
    50  		}
    51  		time.Sleep(100 * time.Millisecond)
    52  	}
    53  }
    54  
    55  func (this *Locker) Release() error {
    56  	err := this.fp.Close()
    57  	if err != nil {
    58  		return err
    59  	}
    60  	this.fp = nil
    61  	return nil
    62  }
    63  
    64  func (this *Locker) tryLock() (ok bool, err error) {
    65  	err = syscall.Flock(int(this.fp.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
    66  	if err == nil {
    67  		return true, nil
    68  	}
    69  
    70  	errno, isErrNo := err.(syscall.Errno)
    71  	if !isErrNo {
    72  		return
    73  	}
    74  
    75  	if !errno.Temporary() {
    76  		return
    77  	}
    78  
    79  	err = nil // 不提示错误
    80  
    81  	return
    82  }