mirror of https://github.com/ledisdb/ledisdb.git
parent
1ca74b404a
commit
8ec2730235
13
README.md
13
README.md
|
@ -167,18 +167,9 @@ See [Clients](https://github.com/siddontang/ledisdb/wiki/Clients) to find or con
|
||||||
+ `pcall` and `xpcall` are not supported in lua, you can see the readme in [golua](https://github.com/aarzilli/golua).
|
+ `pcall` and `xpcall` are not supported in lua, you can see the readme in [golua](https://github.com/aarzilli/golua).
|
||||||
|
|
||||||
|
|
||||||
## Thanks
|
## Requirement
|
||||||
|
|
||||||
Gmail: cenqichao@gmail.com
|
|
||||||
|
|
||||||
Gmail: chendahui007@gmail.com
|
|
||||||
|
|
||||||
Gmail: cppgohan@gmail.com
|
|
||||||
|
|
||||||
Gmail: tiaotiaoyly@gmail.com
|
|
||||||
|
|
||||||
Gmail: wyk4true@gmail.com
|
|
||||||
|
|
||||||
|
+ go version >= 1.3
|
||||||
|
|
||||||
## Feedback
|
## Feedback
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,7 @@ path = ""
|
||||||
|
|
||||||
# If sync is true, the new log must be sent to some slaves, and then commit.
|
# If sync is true, the new log must be sent to some slaves, and then commit.
|
||||||
# It will reduce performance but have better high availability.
|
# It will reduce performance but have better high availability.
|
||||||
sync = true
|
sync = false
|
||||||
|
|
||||||
# If sync is true, wait at last wait_sync_time milliseconds for slave syncing this log
|
# If sync is true, wait at last wait_sync_time milliseconds for slave syncing this log
|
||||||
wait_sync_time = 500
|
wait_sync_time = 500
|
||||||
|
|
|
@ -111,7 +111,7 @@ path = ""
|
||||||
|
|
||||||
# If sync is true, the new log must be sent to some slaves, and then commit.
|
# If sync is true, the new log must be sent to some slaves, and then commit.
|
||||||
# It will reduce performance but have better high availability.
|
# It will reduce performance but have better high availability.
|
||||||
sync = true
|
sync = false
|
||||||
|
|
||||||
# If sync is true, wait at last wait_sync_time milliseconds for slave syncing this log
|
# If sync is true, wait at last wait_sync_time milliseconds for slave syncing this log
|
||||||
wait_sync_time = 500
|
wait_sync_time = 500
|
||||||
|
|
|
@ -100,12 +100,13 @@ type commitDataGetter interface {
|
||||||
|
|
||||||
func (l *Ledis) handleCommit(g commitDataGetter, c commiter) error {
|
func (l *Ledis) handleCommit(g commitDataGetter, c commiter) error {
|
||||||
l.commitLock.Lock()
|
l.commitLock.Lock()
|
||||||
defer l.commitLock.Unlock()
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if l.r != nil {
|
if l.r != nil {
|
||||||
var rl *rpl.Log
|
var rl *rpl.Log
|
||||||
if rl, err = l.r.Log(g.Data()); err != nil {
|
if rl, err = l.r.Log(g.Data()); err != nil {
|
||||||
|
l.commitLock.Unlock()
|
||||||
|
|
||||||
log.Fatal("write wal error %s", err.Error())
|
log.Fatal("write wal error %s", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -113,19 +114,25 @@ func (l *Ledis) handleCommit(g commitDataGetter, c commiter) error {
|
||||||
l.propagate(rl)
|
l.propagate(rl)
|
||||||
|
|
||||||
if err = c.Commit(); err != nil {
|
if err = c.Commit(); err != nil {
|
||||||
|
l.commitLock.Unlock()
|
||||||
|
|
||||||
log.Fatal("commit error %s", err.Error())
|
log.Fatal("commit error %s", err.Error())
|
||||||
l.noticeReplication()
|
l.noticeReplication()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = l.r.UpdateCommitID(rl.ID); err != nil {
|
if err = l.r.UpdateCommitID(rl.ID); err != nil {
|
||||||
|
l.commitLock.Unlock()
|
||||||
|
|
||||||
log.Fatal("update commit id error %s", err.Error())
|
log.Fatal("update commit id error %s", err.Error())
|
||||||
l.noticeReplication()
|
l.noticeReplication()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
|
||||||
} else {
|
} else {
|
||||||
return c.Commit()
|
err = c.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l.commitLock.Unlock()
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,8 +163,12 @@ func (s *FileStore) LastID() (uint64, error) {
|
||||||
|
|
||||||
func (s *FileStore) StoreLog(l *Log) error {
|
func (s *FileStore) StoreLog(l *Log) error {
|
||||||
s.wm.Lock()
|
s.wm.Lock()
|
||||||
defer s.wm.Unlock()
|
err := s.storeLog(l)
|
||||||
|
s.wm.Unlock()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FileStore) storeLog(l *Log) error {
|
||||||
err := s.w.StoreLog(l)
|
err := s.w.StoreLog(l)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -172,23 +176,24 @@ func (s *FileStore) StoreLog(l *Log) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.rm.Lock()
|
|
||||||
|
|
||||||
var r *tableReader
|
var r *tableReader
|
||||||
if r, err = s.w.Flush(); err != nil {
|
r, err = s.w.Flush()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
log.Error("write table flush error %s, can not store now", err.Error())
|
log.Error("write table flush error %s, can not store now", err.Error())
|
||||||
|
|
||||||
s.w.Close()
|
s.w.Close()
|
||||||
|
|
||||||
s.rm.Unlock()
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.rm.Lock()
|
||||||
s.rs = append(s.rs, r)
|
s.rs = append(s.rs, r)
|
||||||
s.rm.Unlock()
|
s.rm.Unlock()
|
||||||
|
|
||||||
return s.w.StoreLog(l)
|
err = s.w.StoreLog(l)
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FileStore) PurgeExpired(n int64) error {
|
func (s *FileStore) PurgeExpired(n int64) error {
|
||||||
|
|
|
@ -546,13 +546,18 @@ func (t *tableWriter) Flush() (*tableReader, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tableWriter) StoreLog(l *Log) error {
|
func (t *tableWriter) StoreLog(l *Log) error {
|
||||||
|
t.Lock()
|
||||||
|
err := t.storeLog(l)
|
||||||
|
t.Unlock()
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tableWriter) storeLog(l *Log) error {
|
||||||
if l.ID == 0 {
|
if l.ID == 0 {
|
||||||
return ErrStoreLogID
|
return ErrStoreLogID
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Lock()
|
|
||||||
defer t.Unlock()
|
|
||||||
|
|
||||||
if t.closed {
|
if t.closed {
|
||||||
return fmt.Errorf("table writer is closed")
|
return fmt.Errorf("table writer is closed")
|
||||||
}
|
}
|
||||||
|
@ -588,9 +593,11 @@ func (t *tableWriter) StoreLog(l *Log) error {
|
||||||
|
|
||||||
offsetPos := t.offsetPos
|
offsetPos := t.offsetPos
|
||||||
|
|
||||||
if err := l.Encode(t.wb); err != nil {
|
if err = l.Encode(t.wb); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if err = t.wb.Flush(); err != nil {
|
}
|
||||||
|
|
||||||
|
if err = t.wb.Flush(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,12 +659,14 @@ func (t *tableWriter) GetLog(id uint64, l *Log) error {
|
||||||
|
|
||||||
func (t *tableWriter) Sync() error {
|
func (t *tableWriter) Sync() error {
|
||||||
t.Lock()
|
t.Lock()
|
||||||
defer t.Unlock()
|
|
||||||
|
|
||||||
|
var err error
|
||||||
if t.wf != nil {
|
if t.wf != nil {
|
||||||
return t.wf.Sync()
|
err = t.wf.Sync()
|
||||||
}
|
}
|
||||||
return nil
|
t.Unlock()
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tableWriter) getLog(l *Log, pos int64) error {
|
func (t *tableWriter) getLog(l *Log, pos int64) error {
|
||||||
|
|
49
rpl/log.go
49
rpl/log.go
|
@ -4,8 +4,11 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const LogHeadSize = 17
|
||||||
|
|
||||||
type Log struct {
|
type Log struct {
|
||||||
ID uint64
|
ID uint64
|
||||||
CreateTime uint32
|
CreateTime uint32
|
||||||
|
@ -15,7 +18,7 @@ type Log struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Log) HeadSize() int {
|
func (l *Log) HeadSize() int {
|
||||||
return 17
|
return LogHeadSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Log) Size() int {
|
func (l *Log) Size() int {
|
||||||
|
@ -23,7 +26,7 @@ func (l *Log) Size() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Log) Marshal() ([]byte, error) {
|
func (l *Log) Marshal() ([]byte, error) {
|
||||||
buf := bytes.NewBuffer(make([]byte, l.HeadSize()+len(l.Data)))
|
buf := bytes.NewBuffer(make([]byte, l.Size()))
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
|
|
||||||
if err := l.Encode(buf); err != nil {
|
if err := l.Encode(buf); err != nil {
|
||||||
|
@ -39,25 +42,32 @@ func (l *Log) Unmarshal(b []byte) error {
|
||||||
return l.Decode(buf)
|
return l.Decode(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var headPool = sync.Pool{
|
||||||
|
New: func() interface{} { return make([]byte, LogHeadSize) },
|
||||||
|
}
|
||||||
|
|
||||||
func (l *Log) Encode(w io.Writer) error {
|
func (l *Log) Encode(w io.Writer) error {
|
||||||
if err := binary.Write(w, binary.BigEndian, l.ID); err != nil {
|
b := headPool.Get().([]byte)
|
||||||
|
pos := 0
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint64(b[pos:], l.ID)
|
||||||
|
pos += 8
|
||||||
|
binary.BigEndian.PutUint32(b[pos:], uint32(l.CreateTime))
|
||||||
|
pos += 4
|
||||||
|
b[pos] = l.Compression
|
||||||
|
pos++
|
||||||
|
binary.BigEndian.PutUint32(b[pos:], uint32(len(l.Data)))
|
||||||
|
|
||||||
|
n, err := w.Write(b)
|
||||||
|
headPool.Put(b)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
} else if n != LogHeadSize {
|
||||||
|
return io.ErrShortWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := binary.Write(w, binary.BigEndian, l.CreateTime); err != nil {
|
if n, err = w.Write(l.Data); err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := w.Write([]byte{l.Compression}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
dataLen := uint32(len(l.Data))
|
|
||||||
if err := binary.Write(w, binary.BigEndian, dataLen); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if n, err := w.Write(l.Data); err != nil {
|
|
||||||
return err
|
return err
|
||||||
} else if n != len(l.Data) {
|
} else if n != len(l.Data) {
|
||||||
return io.ErrShortWrite
|
return io.ErrShortWrite
|
||||||
|
@ -86,9 +96,10 @@ func (l *Log) Decode(r io.Reader) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Log) DecodeHead(r io.Reader) (uint32, error) {
|
func (l *Log) DecodeHead(r io.Reader) (uint32, error) {
|
||||||
buf := make([]byte, l.HeadSize())
|
buf := headPool.Get().([]byte)
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, buf); err != nil {
|
if _, err := io.ReadFull(r, buf); err != nil {
|
||||||
|
headPool.Put(buf)
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,5 +115,7 @@ func (l *Log) DecodeHead(r io.Reader) (uint32, error) {
|
||||||
|
|
||||||
length := binary.BigEndian.Uint32(buf[pos:])
|
length := binary.BigEndian.Uint32(buf[pos:])
|
||||||
|
|
||||||
|
headPool.Put(buf)
|
||||||
|
|
||||||
return length, nil
|
return length, nil
|
||||||
}
|
}
|
||||||
|
|
28
rpl/rpl.go
28
rpl/rpl.go
|
@ -114,10 +114,10 @@ func (r *Replication) Log(data []byte) (*Log, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
r.m.Lock()
|
r.m.Lock()
|
||||||
defer r.m.Unlock()
|
|
||||||
|
|
||||||
lastID, err := r.s.LastID()
|
lastID, err := r.s.LastID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
r.m.Unlock()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +125,7 @@ func (r *Replication) Log(data []byte) (*Log, error) {
|
||||||
if lastID < commitId {
|
if lastID < commitId {
|
||||||
lastID = commitId
|
lastID = commitId
|
||||||
} else if lastID > commitId {
|
} else if lastID > commitId {
|
||||||
|
r.m.Unlock()
|
||||||
return nil, ErrCommitIDBehind
|
return nil, ErrCommitIDBehind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,9 +142,12 @@ func (r *Replication) Log(data []byte) (*Log, error) {
|
||||||
l.Data = data
|
l.Data = data
|
||||||
|
|
||||||
if err = r.s.StoreLog(l); err != nil {
|
if err = r.s.StoreLog(l); err != nil {
|
||||||
|
r.m.Unlock()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r.m.Unlock()
|
||||||
|
|
||||||
r.ncm.Lock()
|
r.ncm.Lock()
|
||||||
close(r.nc)
|
close(r.nc)
|
||||||
r.nc = make(chan struct{})
|
r.nc = make(chan struct{})
|
||||||
|
@ -161,22 +165,24 @@ func (r *Replication) WaitLog() <-chan struct{} {
|
||||||
|
|
||||||
func (r *Replication) StoreLog(log *Log) error {
|
func (r *Replication) StoreLog(log *Log) error {
|
||||||
r.m.Lock()
|
r.m.Lock()
|
||||||
defer r.m.Unlock()
|
err := r.s.StoreLog(log)
|
||||||
|
r.m.Unlock()
|
||||||
|
|
||||||
return r.s.StoreLog(log)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Replication) FirstLogID() (uint64, error) {
|
func (r *Replication) FirstLogID() (uint64, error) {
|
||||||
r.m.Lock()
|
r.m.Lock()
|
||||||
defer r.m.Unlock()
|
|
||||||
id, err := r.s.FirstID()
|
id, err := r.s.FirstID()
|
||||||
|
r.m.Unlock()
|
||||||
|
|
||||||
return id, err
|
return id, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Replication) LastLogID() (uint64, error) {
|
func (r *Replication) LastLogID() (uint64, error) {
|
||||||
r.m.Lock()
|
r.m.Lock()
|
||||||
defer r.m.Unlock()
|
|
||||||
id, err := r.s.LastID()
|
id, err := r.s.LastID()
|
||||||
|
r.m.Unlock()
|
||||||
return id, err
|
return id, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,9 +195,10 @@ func (r *Replication) LastCommitID() (uint64, error) {
|
||||||
|
|
||||||
func (r *Replication) UpdateCommitID(id uint64) error {
|
func (r *Replication) UpdateCommitID(id uint64) error {
|
||||||
r.m.Lock()
|
r.m.Lock()
|
||||||
defer r.m.Unlock()
|
err := r.updateCommitID(id, r.cfg.Replication.SyncLog == 2)
|
||||||
|
r.m.Unlock()
|
||||||
|
|
||||||
return r.updateCommitID(id, r.cfg.Replication.SyncLog == 2)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Replication) Stat() (*Stat, error) {
|
func (r *Replication) Stat() (*Stat, error) {
|
||||||
|
@ -231,14 +238,17 @@ func (r *Replication) updateCommitID(id uint64, force bool) error {
|
||||||
|
|
||||||
func (r *Replication) CommitIDBehind() (bool, error) {
|
func (r *Replication) CommitIDBehind() (bool, error) {
|
||||||
r.m.Lock()
|
r.m.Lock()
|
||||||
defer r.m.Unlock()
|
|
||||||
|
|
||||||
id, err := r.s.LastID()
|
id, err := r.s.LastID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
r.m.Unlock()
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return id > r.commitID, nil
|
behind := id > r.commitID
|
||||||
|
r.m.Unlock()
|
||||||
|
|
||||||
|
return behind, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Replication) GetLog(id uint64, log *Log) error {
|
func (r *Replication) GetLog(id uint64, log *Log) error {
|
||||||
|
|
Loading…
Reference in New Issue