mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00

The TestFilePipelineFailLockFile case maybe test the line 77 in the alloc function. But the LockFile will not throw an error when the file lock is hold. And TestFilePipelineFailPreallocate and TestFilePipelineFailLockFile are exactly the same except for the comments. Signed-off-by: SimFG <1142838399@qq.com>
107 lines
2.5 KiB
Go
107 lines
2.5 KiB
Go
// Copyright 2016 The etcd Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package wal
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"go.etcd.io/etcd/client/pkg/v3/fileutil"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// filePipeline pipelines allocating disk space
|
|
type filePipeline struct {
|
|
lg *zap.Logger
|
|
|
|
// dir to put files
|
|
dir string
|
|
// size of files to make, in bytes
|
|
size int64
|
|
// count number of files generated
|
|
count int
|
|
|
|
filec chan *fileutil.LockedFile
|
|
errc chan error
|
|
donec chan struct{}
|
|
}
|
|
|
|
func newFilePipeline(lg *zap.Logger, dir string, fileSize int64) *filePipeline {
|
|
if lg == nil {
|
|
lg = zap.NewNop()
|
|
}
|
|
fp := &filePipeline{
|
|
lg: lg,
|
|
dir: dir,
|
|
size: fileSize,
|
|
filec: make(chan *fileutil.LockedFile),
|
|
errc: make(chan error, 1),
|
|
donec: make(chan struct{}),
|
|
}
|
|
go fp.run()
|
|
return fp
|
|
}
|
|
|
|
// Open returns a fresh file for writing. Rename the file before calling
|
|
// Open again or there will be file collisions.
|
|
// it will 'block' if the tmp file lock is already taken.
|
|
func (fp *filePipeline) Open() (f *fileutil.LockedFile, err error) {
|
|
select {
|
|
case f = <-fp.filec:
|
|
case err = <-fp.errc:
|
|
}
|
|
return f, err
|
|
}
|
|
|
|
func (fp *filePipeline) Close() error {
|
|
close(fp.donec)
|
|
return <-fp.errc
|
|
}
|
|
|
|
func (fp *filePipeline) alloc() (f *fileutil.LockedFile, err error) {
|
|
// count % 2 so this file isn't the same as the one last published
|
|
fpath := filepath.Join(fp.dir, fmt.Sprintf("%d.tmp", fp.count%2))
|
|
if f, err = fileutil.LockFile(fpath, os.O_CREATE|os.O_WRONLY, fileutil.PrivateFileMode); err != nil {
|
|
return nil, err
|
|
}
|
|
if err = fileutil.Preallocate(f.File, fp.size, true); err != nil {
|
|
fp.lg.Error("failed to preallocate space when creating a new WAL", zap.Int64("size", fp.size), zap.Error(err))
|
|
f.Close()
|
|
return nil, err
|
|
}
|
|
fp.count++
|
|
return f, nil
|
|
}
|
|
|
|
func (fp *filePipeline) run() {
|
|
defer close(fp.errc)
|
|
for {
|
|
f, err := fp.alloc()
|
|
if err != nil {
|
|
fp.errc <- err
|
|
return
|
|
}
|
|
select {
|
|
case fp.filec <- f:
|
|
case <-fp.donec:
|
|
os.Remove(f.Name())
|
|
f.Close()
|
|
return
|
|
}
|
|
}
|
|
}
|