mirror of https://github.com/ledisdb/ledisdb.git
update snapshot
This commit is contained in:
parent
180091e10f
commit
36f015268f
|
@ -81,7 +81,7 @@ compression = true
|
||||||
[snapshot]
|
[snapshot]
|
||||||
# Path to store snapshot dump file
|
# Path to store snapshot dump file
|
||||||
# if not set, use data_dir/snapshot
|
# if not set, use data_dir/snapshot
|
||||||
# snapshot file name format is snap-2006-01-02T15:04:05.dump
|
# snapshot file name format is snap-2006-01-02T15:04:05.999999999.dmp
|
||||||
path = ""
|
path = ""
|
||||||
|
|
||||||
# Reserve newest max_num snapshot dump files
|
# Reserve newest max_num snapshot dump files
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
snapshotTimeFormat = "2006-01-02T15:04:05"
|
snapshotTimeFormat = "2006-01-02T15:04:05.999999999"
|
||||||
)
|
)
|
||||||
|
|
||||||
type snapshotStore struct {
|
type snapshotStore struct {
|
||||||
|
@ -91,28 +91,37 @@ func (s *snapshotStore) run() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-t.C:
|
case <-t.C:
|
||||||
s.purge()
|
s.Lock()
|
||||||
|
s.purge(false)
|
||||||
|
s.Unlock()
|
||||||
case <-s.quit:
|
case <-s.quit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *snapshotStore) purge() {
|
func (s *snapshotStore) purge(create bool) {
|
||||||
s.Lock()
|
|
||||||
var names []string
|
var names []string
|
||||||
num := s.cfg.Snapshot.MaxNum
|
maxNum := s.cfg.Snapshot.MaxNum
|
||||||
if len(s.names) > num {
|
num := len(s.names) - maxNum
|
||||||
names = s.names[0:num]
|
|
||||||
|
|
||||||
s.names = s.names[num:]
|
if create {
|
||||||
|
num++
|
||||||
|
if num > len(s.names) {
|
||||||
|
num = len(s.names)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Unlock()
|
if num > 0 {
|
||||||
|
names = s.names[0:num]
|
||||||
|
|
||||||
for _, n := range names {
|
n := copy(s.names, s.names[num:])
|
||||||
if err := os.Remove(s.snapshotPath(n)); err != nil {
|
s.names = s.names[0:n]
|
||||||
log.Error("purge snapshot %s error %s", n, err.Error())
|
}
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
if err := os.Remove(s.snapshotPath(name)); err != nil {
|
||||||
|
log.Error("purge snapshot %s error %s", name, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,10 +134,31 @@ type snapshotDumper interface {
|
||||||
Dump(w io.Writer) error
|
Dump(w io.Writer) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *snapshotStore) Create(d snapshotDumper) (*os.File, time.Time, error) {
|
type snapshot struct {
|
||||||
|
io.ReadCloser
|
||||||
|
|
||||||
|
f *os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *snapshot) Read(b []byte) (int, error) {
|
||||||
|
return st.f.Read(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *snapshot) Close() error {
|
||||||
|
return st.f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *snapshot) Size() int64 {
|
||||||
|
s, _ := st.f.Stat()
|
||||||
|
return s.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snapshotStore) Create(d snapshotDumper) (*snapshot, time.Time, error) {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
|
s.purge(true)
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
name := snapshotName(now)
|
name := snapshotName(now)
|
||||||
|
|
||||||
|
@ -147,14 +177,16 @@ func (s *snapshotStore) Create(d snapshotDumper) (*os.File, time.Time, error) {
|
||||||
return nil, time.Time{}, err
|
return nil, time.Time{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f.Sync()
|
||||||
|
|
||||||
s.names = append(s.names, name)
|
s.names = append(s.names, name)
|
||||||
|
|
||||||
f.Seek(0, os.SEEK_SET)
|
f.Seek(0, os.SEEK_SET)
|
||||||
|
|
||||||
return f, now, nil
|
return &snapshot{f: f}, now, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *snapshotStore) OpenLatest() (*os.File, time.Time, error) {
|
func (s *snapshotStore) OpenLatest() (*snapshot, time.Time, error) {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
defer s.Unlock()
|
defer s.Unlock()
|
||||||
|
|
||||||
|
@ -170,5 +202,5 @@ func (s *snapshotStore) OpenLatest() (*os.File, time.Time, error) {
|
||||||
return nil, time.Time{}, err
|
return nil, time.Time{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return f, t, err
|
return &snapshot{f: f}, t, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,40 @@ func TestSnapshot(t *testing.T) {
|
||||||
if b, _ := ioutil.ReadAll(f); string(b) != "hello world" {
|
if b, _ := ioutil.ReadAll(f); string(b) != "hello world" {
|
||||||
t.Fatal("invalid read snapshot")
|
t.Fatal("invalid read snapshot")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if len(s.names) != 1 {
|
if len(s.names) != 1 {
|
||||||
t.Fatal("mut one snapshot")
|
t.Fatal("must 1 snapshot")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if f, _, err := s.Create(d); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else {
|
||||||
|
defer f.Close()
|
||||||
|
if b, _ := ioutil.ReadAll(f); string(b) != "hello world" {
|
||||||
|
t.Fatal("invalid read snapshot")
|
||||||
|
}
|
||||||
|
if len(s.names) != 2 {
|
||||||
|
t.Fatal("must 2 snapshot")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if f, _, err := s.Create(d); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else {
|
||||||
|
defer f.Close()
|
||||||
|
if b, _ := ioutil.ReadAll(f); string(b) != "hello world" {
|
||||||
|
t.Fatal("invalid read snapshot")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.names) != 2 {
|
||||||
|
t.Fatal("must 2 snapshot")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs, _ := ioutil.ReadDir(cfg.Snapshot.Path)
|
||||||
|
if len(fs) != 2 {
|
||||||
|
t.Fatal("must 2 snapshot")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Close()
|
s.Close()
|
||||||
|
|
Loading…
Reference in New Issue