mirror of https://github.com/ledisdb/ledisdb.git
use go-log and adjust some param name
go-log now has a well document. it can be used directly. limit may cause confused, use count instead
This commit is contained in:
parent
94b3f335ec
commit
38f741ddb1
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
. ./dev.sh
|
. ./dev.sh
|
||||||
|
|
||||||
#nothing to do now
|
go get -u github.com/siddontang/go-log/log
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/siddontang/ledisdb/log"
|
"github.com/siddontang/go-log/log"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
|
@ -3,8 +3,8 @@ package ledis
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/siddontang/go-log/log"
|
||||||
"github.com/siddontang/ledisdb/leveldb"
|
"github.com/siddontang/ledisdb/leveldb"
|
||||||
"github.com/siddontang/ledisdb/log"
|
|
||||||
"path"
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/siddontang/ledisdb/log"
|
"github.com/siddontang/go-log/log"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
|
@ -492,23 +492,23 @@ func (db *DB) zrank(key []byte, member []byte, reverse bool) (int64, error) {
|
||||||
return -1, nil
|
return -1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) zIterator(key []byte, min int64, max int64, offset int, limit int, reverse bool) *leveldb.RangeLimitIterator {
|
func (db *DB) zIterator(key []byte, min int64, max int64, offset int, count int, reverse bool) *leveldb.RangeLimitIterator {
|
||||||
minKey := db.zEncodeStartScoreKey(key, min)
|
minKey := db.zEncodeStartScoreKey(key, min)
|
||||||
maxKey := db.zEncodeStopScoreKey(key, max)
|
maxKey := db.zEncodeStopScoreKey(key, max)
|
||||||
|
|
||||||
if !reverse {
|
if !reverse {
|
||||||
return db.db.RangeLimitIterator(minKey, maxKey, leveldb.RangeClose, offset, limit)
|
return db.db.RangeLimitIterator(minKey, maxKey, leveldb.RangeClose, offset, count)
|
||||||
} else {
|
} else {
|
||||||
return db.db.RevRangeLimitIterator(minKey, maxKey, leveldb.RangeClose, offset, limit)
|
return db.db.RevRangeLimitIterator(minKey, maxKey, leveldb.RangeClose, offset, count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) zRemRange(t *tx, key []byte, min int64, max int64, offset int, limit int) (int64, error) {
|
func (db *DB) zRemRange(t *tx, key []byte, min int64, max int64, offset int, count int) (int64, error) {
|
||||||
if len(key) > MaxKeySize {
|
if len(key) > MaxKeySize {
|
||||||
return 0, errKeySize
|
return 0, errKeySize
|
||||||
}
|
}
|
||||||
|
|
||||||
it := db.zIterator(key, min, max, offset, limit, false)
|
it := db.zIterator(key, min, max, offset, count, false)
|
||||||
var num int64 = 0
|
var num int64 = 0
|
||||||
for ; it.Valid(); it.Next() {
|
for ; it.Valid(); it.Next() {
|
||||||
sk := it.Key()
|
sk := it.Key()
|
||||||
|
@ -534,7 +534,7 @@ func (db *DB) zRemRange(t *tx, key []byte, min int64, max int64, offset int, lim
|
||||||
return num, nil
|
return num, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) zRange(key []byte, min int64, max int64, offset int, limit int, reverse bool) ([]ScorePair, error) {
|
func (db *DB) zRange(key []byte, min int64, max int64, offset int, count int, reverse bool) ([]ScorePair, error) {
|
||||||
if len(key) > MaxKeySize {
|
if len(key) > MaxKeySize {
|
||||||
return nil, errKeySize
|
return nil, errKeySize
|
||||||
}
|
}
|
||||||
|
@ -544,20 +544,20 @@ func (db *DB) zRange(key []byte, min int64, max int64, offset int, limit int, re
|
||||||
}
|
}
|
||||||
|
|
||||||
nv := 64
|
nv := 64
|
||||||
if limit > 0 {
|
if count > 0 {
|
||||||
nv = limit
|
nv = count
|
||||||
}
|
}
|
||||||
|
|
||||||
v := make([]ScorePair, 0, nv)
|
v := make([]ScorePair, 0, nv)
|
||||||
|
|
||||||
var it *leveldb.RangeLimitIterator
|
var it *leveldb.RangeLimitIterator
|
||||||
|
|
||||||
//if reverse and offset is 0, limit < 0, we may use forward iterator then reverse
|
//if reverse and offset is 0, count < 0, we may use forward iterator then reverse
|
||||||
//because leveldb iterator prev is slower than next
|
//because leveldb iterator prev is slower than next
|
||||||
if !reverse || (offset == 0 && limit < 0) {
|
if !reverse || (offset == 0 && count < 0) {
|
||||||
it = db.zIterator(key, min, max, offset, limit, false)
|
it = db.zIterator(key, min, max, offset, count, false)
|
||||||
} else {
|
} else {
|
||||||
it = db.zIterator(key, min, max, offset, limit, true)
|
it = db.zIterator(key, min, max, offset, count, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
for ; it.Valid(); it.Next() {
|
for ; it.Valid(); it.Next() {
|
||||||
|
@ -571,7 +571,7 @@ func (db *DB) zRange(key []byte, min int64, max int64, offset int, limit int, re
|
||||||
}
|
}
|
||||||
it.Close()
|
it.Close()
|
||||||
|
|
||||||
if reverse && (offset == 0 && limit < 0) {
|
if reverse && (offset == 0 && count < 0) {
|
||||||
for i, j := 0, len(v)-1; i < j; i, j = i+1, j-1 {
|
for i, j := 0, len(v)-1; i < j; i, j = i+1, j-1 {
|
||||||
v[i], v[j] = v[j], v[i]
|
v[i], v[j] = v[j], v[i]
|
||||||
}
|
}
|
||||||
|
@ -580,7 +580,7 @@ func (db *DB) zRange(key []byte, min int64, max int64, offset int, limit int, re
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) zParseLimit(key []byte, start int, stop int) (offset int, limit int, err error) {
|
func (db *DB) zParseLimit(key []byte, start int, stop int) (offset int, count int, err error) {
|
||||||
if start < 0 || stop < 0 {
|
if start < 0 || stop < 0 {
|
||||||
//refer redis implementation
|
//refer redis implementation
|
||||||
var size int64
|
var size int64
|
||||||
|
@ -614,7 +614,7 @@ func (db *DB) zParseLimit(key []byte, start int, stop int) (offset int, limit in
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = start
|
offset = start
|
||||||
limit = (stop - start) + 1
|
count = (stop - start) + 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -663,7 +663,7 @@ func (db *DB) ZRank(key []byte, member []byte) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) ZRemRangeByRank(key []byte, start int, stop int) (int64, error) {
|
func (db *DB) ZRemRangeByRank(key []byte, start int, stop int) (int64, error) {
|
||||||
offset, limit, err := db.zParseLimit(key, start, stop)
|
offset, count, err := db.zParseLimit(key, start, stop)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -674,7 +674,7 @@ func (db *DB) ZRemRangeByRank(key []byte, start int, stop int) (int64, error) {
|
||||||
t.Lock()
|
t.Lock()
|
||||||
defer t.Unlock()
|
defer t.Unlock()
|
||||||
|
|
||||||
rmCnt, err = db.zRemRange(t, key, MinScore, MaxScore, offset, limit)
|
rmCnt, err = db.zRemRange(t, key, MinScore, MaxScore, offset, count)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = t.Commit()
|
err = t.Commit()
|
||||||
}
|
}
|
||||||
|
@ -711,12 +711,12 @@ func (db *DB) ZRevRangeByScore(key []byte, min int64, max int64, offset int, cou
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) ZRangeGeneric(key []byte, start int, stop int, reverse bool) ([]ScorePair, error) {
|
func (db *DB) ZRangeGeneric(key []byte, start int, stop int, reverse bool) ([]ScorePair, error) {
|
||||||
offset, limit, err := db.zParseLimit(key, start, stop)
|
offset, count, err := db.zParseLimit(key, start, stop)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.zRange(key, MinScore, MaxScore, offset, limit, reverse)
|
return db.zRange(key, MinScore, MaxScore, offset, count, reverse)
|
||||||
}
|
}
|
||||||
|
|
||||||
//min and max must be inclusive
|
//min and max must be inclusive
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
//a wrapper for c++ leveldb
|
||||||
package leveldb
|
package leveldb
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -156,7 +157,7 @@ func (db *DB) initOptions(cfg *Config) {
|
||||||
db.syncWriteOpts.SetSync(true)
|
db.syncWriteOpts.SetSync(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) Close() {
|
func (db *DB) Close() error {
|
||||||
if db.db != nil {
|
if db.db != nil {
|
||||||
C.leveldb_close(db.db)
|
C.leveldb_close(db.db)
|
||||||
db.db = nil
|
db.db = nil
|
||||||
|
@ -176,6 +177,8 @@ func (db *DB) Close() {
|
||||||
db.writeOpts.Close()
|
db.writeOpts.Close()
|
||||||
db.iteratorOpts.Close()
|
db.iteratorOpts.Close()
|
||||||
db.syncWriteOpts.Close()
|
db.syncWriteOpts.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) Destroy() error {
|
func (db *DB) Destroy() error {
|
||||||
|
@ -274,23 +277,23 @@ func (db *DB) NewIterator() *Iterator {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) RangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
func (db *DB) RangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
||||||
return newRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, 0, -1, IteratorForward)
|
return NewRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, &Limit{0, -1})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) RevRangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
func (db *DB) RevRangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
||||||
return newRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, 0, -1, IteratorBackward)
|
return NewRevRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, &Limit{0, -1})
|
||||||
}
|
}
|
||||||
|
|
||||||
//limit < 0, unlimit
|
//count < 0, unlimit
|
||||||
//offset must >= 0, if < 0, will get nothing
|
//offset must >= 0, if < 0, will get nothing
|
||||||
func (db *DB) RangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *RangeLimitIterator {
|
func (db *DB) RangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, count int) *RangeLimitIterator {
|
||||||
return newRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, offset, limit, IteratorForward)
|
return NewRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, &Limit{offset, count})
|
||||||
}
|
}
|
||||||
|
|
||||||
//limit < 0, unlimit
|
//count < 0, unlimit
|
||||||
//offset must >= 0, if < 0, will get nothing
|
//offset must >= 0, if < 0, will get nothing
|
||||||
func (db *DB) RevRangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *RangeLimitIterator {
|
func (db *DB) RevRangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, count int) *RangeLimitIterator {
|
||||||
return newRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, offset, limit, IteratorBackward)
|
return NewRevRangeLimitIterator(db.NewIterator(), &Range{min, max, rangeType}, &Limit{offset, count})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) put(wo *WriteOptions, key, value []byte) error {
|
func (db *DB) put(wo *WriteOptions, key, value []byte) error {
|
||||||
|
|
|
@ -35,6 +35,11 @@ type Range struct {
|
||||||
Type uint8
|
Type uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Limit struct {
|
||||||
|
Offset int
|
||||||
|
Count int
|
||||||
|
}
|
||||||
|
|
||||||
type Iterator struct {
|
type Iterator struct {
|
||||||
it *C.leveldb_iterator_t
|
it *C.leveldb_iterator_t
|
||||||
}
|
}
|
||||||
|
@ -107,9 +112,7 @@ type RangeLimitIterator struct {
|
||||||
it *Iterator
|
it *Iterator
|
||||||
|
|
||||||
r *Range
|
r *Range
|
||||||
|
l *Limit
|
||||||
offset int
|
|
||||||
limit int
|
|
||||||
|
|
||||||
step int
|
step int
|
||||||
|
|
||||||
|
@ -126,11 +129,11 @@ func (it *RangeLimitIterator) Value() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (it *RangeLimitIterator) Valid() bool {
|
func (it *RangeLimitIterator) Valid() bool {
|
||||||
if it.offset < 0 {
|
if it.l.Offset < 0 {
|
||||||
return false
|
return false
|
||||||
} else if !it.it.Valid() {
|
} else if !it.it.Valid() {
|
||||||
return false
|
return false
|
||||||
} else if it.limit >= 0 && it.step >= it.limit {
|
} else if it.l.Count >= 0 && it.step >= it.l.Count {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,19 +174,26 @@ func (it *RangeLimitIterator) Close() {
|
||||||
it.it.Close()
|
it.it.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func newRangeLimitIterator(i *Iterator, r *Range, offset int, limit int, direction uint8) *RangeLimitIterator {
|
func NewRangeLimitIterator(i *Iterator, r *Range, l *Limit) *RangeLimitIterator {
|
||||||
|
return rangeLimitIterator(i, r, l, IteratorForward)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRevRangeLimitIterator(i *Iterator, r *Range, l *Limit) *RangeLimitIterator {
|
||||||
|
return rangeLimitIterator(i, r, l, IteratorBackward)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rangeLimitIterator(i *Iterator, r *Range, l *Limit, direction uint8) *RangeLimitIterator {
|
||||||
it := new(RangeLimitIterator)
|
it := new(RangeLimitIterator)
|
||||||
|
|
||||||
it.it = i
|
it.it = i
|
||||||
|
|
||||||
it.r = r
|
it.r = r
|
||||||
it.offset = offset
|
it.l = l
|
||||||
it.limit = limit
|
|
||||||
it.direction = direction
|
it.direction = direction
|
||||||
|
|
||||||
it.step = 0
|
it.step = 0
|
||||||
|
|
||||||
if offset < 0 {
|
if l.Offset < 0 {
|
||||||
return it
|
return it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +231,7 @@ func newRangeLimitIterator(i *Iterator, r *Range, offset int, limit int, directi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < offset; i++ {
|
for i := 0; i < l.Offset; i++ {
|
||||||
if it.it.Valid() {
|
if it.it.Valid() {
|
||||||
if it.direction == IteratorForward {
|
if it.direction == IteratorForward {
|
||||||
it.it.Next()
|
it.it.Next()
|
||||||
|
|
|
@ -34,21 +34,21 @@ func (s *Snapshot) NewIterator() *Iterator {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Snapshot) RangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
func (s *Snapshot) RangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
||||||
return newRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, 0, -1, IteratorForward)
|
return NewRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, &Limit{0, -1})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Snapshot) RevRangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
func (s *Snapshot) RevRangeIterator(min []byte, max []byte, rangeType uint8) *RangeLimitIterator {
|
||||||
return newRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, 0, -1, IteratorBackward)
|
return NewRevRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, &Limit{0, -1})
|
||||||
}
|
}
|
||||||
|
|
||||||
//limit < 0, unlimit
|
//count < 0, unlimit
|
||||||
//offset must >= 0, if < 0, will get nothing
|
//offset must >= 0, if < 0, will get nothing
|
||||||
func (s *Snapshot) RangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *RangeLimitIterator {
|
func (s *Snapshot) RangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, count int) *RangeLimitIterator {
|
||||||
return newRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, offset, limit, IteratorForward)
|
return NewRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, &Limit{offset, count})
|
||||||
}
|
}
|
||||||
|
|
||||||
//limit < 0, unlimit
|
//count < 0, unlimit
|
||||||
//offset must >= 0, if < 0, will get nothing
|
//offset must >= 0, if < 0, will get nothing
|
||||||
func (s *Snapshot) RevRangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, limit int) *RangeLimitIterator {
|
func (s *Snapshot) RevRangeLimitIterator(min []byte, max []byte, rangeType uint8, offset int, count int) *RangeLimitIterator {
|
||||||
return newRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, offset, limit, IteratorBackward)
|
return NewRevRangeLimitIterator(s.NewIterator(), &Range{min, max, rangeType}, &Limit{offset, count})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,193 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FileHandler struct {
|
|
||||||
fd *os.File
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFileHandler(fileName string, flag int) (*FileHandler, error) {
|
|
||||||
dir := path.Dir(fileName)
|
|
||||||
os.Mkdir(dir, 0777)
|
|
||||||
|
|
||||||
f, err := os.OpenFile(fileName, flag, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
h := new(FileHandler)
|
|
||||||
|
|
||||||
h.fd = f
|
|
||||||
|
|
||||||
return h, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *FileHandler) Write(b []byte) (n int, err error) {
|
|
||||||
return h.fd.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *FileHandler) Close() error {
|
|
||||||
return h.fd.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
type RotatingFileHandler struct {
|
|
||||||
fd *os.File
|
|
||||||
|
|
||||||
fileName string
|
|
||||||
maxBytes int
|
|
||||||
backupCount int
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRotatingFileHandler(fileName string, maxBytes int, backupCount int) (*RotatingFileHandler, error) {
|
|
||||||
dir := path.Dir(fileName)
|
|
||||||
os.Mkdir(dir, 0777)
|
|
||||||
|
|
||||||
h := new(RotatingFileHandler)
|
|
||||||
|
|
||||||
if maxBytes <= 0 {
|
|
||||||
return nil, fmt.Errorf("invalid max bytes")
|
|
||||||
}
|
|
||||||
|
|
||||||
h.fileName = fileName
|
|
||||||
h.maxBytes = maxBytes
|
|
||||||
h.backupCount = backupCount
|
|
||||||
|
|
||||||
var err error
|
|
||||||
h.fd, err = os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return h, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *RotatingFileHandler) Write(p []byte) (n int, err error) {
|
|
||||||
h.doRollover()
|
|
||||||
return h.fd.Write(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *RotatingFileHandler) Close() error {
|
|
||||||
if h.fd != nil {
|
|
||||||
return h.fd.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *RotatingFileHandler) doRollover() {
|
|
||||||
f, err := h.fd.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.maxBytes <= 0 {
|
|
||||||
return
|
|
||||||
} else if f.Size() < int64(h.maxBytes) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.backupCount > 0 {
|
|
||||||
h.fd.Close()
|
|
||||||
|
|
||||||
for i := h.backupCount - 1; i > 0; i-- {
|
|
||||||
sfn := fmt.Sprintf("%s.%d", h.fileName, i)
|
|
||||||
dfn := fmt.Sprintf("%s.%d", h.fileName, i+1)
|
|
||||||
|
|
||||||
os.Rename(sfn, dfn)
|
|
||||||
}
|
|
||||||
|
|
||||||
dfn := fmt.Sprintf("%s.1", h.fileName)
|
|
||||||
os.Rename(h.fileName, dfn)
|
|
||||||
|
|
||||||
h.fd, _ = os.OpenFile(h.fileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//refer: http://docs.python.org/2/library/logging.handlers.html
|
|
||||||
//same like python TimedRotatingFileHandler
|
|
||||||
|
|
||||||
type TimeRotatingFileHandler struct {
|
|
||||||
fd *os.File
|
|
||||||
|
|
||||||
baseName string
|
|
||||||
interval int64
|
|
||||||
suffix string
|
|
||||||
rolloverAt int64
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
WhenSecond = iota
|
|
||||||
WhenMinute
|
|
||||||
WhenHour
|
|
||||||
WhenDay
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewTimeRotatingFileHandler(baseName string, when int8, interval int) (*TimeRotatingFileHandler, error) {
|
|
||||||
dir := path.Dir(baseName)
|
|
||||||
os.Mkdir(dir, 0777)
|
|
||||||
|
|
||||||
h := new(TimeRotatingFileHandler)
|
|
||||||
|
|
||||||
h.baseName = baseName
|
|
||||||
|
|
||||||
switch when {
|
|
||||||
case WhenSecond:
|
|
||||||
h.interval = 1
|
|
||||||
h.suffix = "2006-01-02_15-04-05"
|
|
||||||
case WhenMinute:
|
|
||||||
h.interval = 60
|
|
||||||
h.suffix = "2006-01-02_15-04"
|
|
||||||
case WhenHour:
|
|
||||||
h.interval = 3600
|
|
||||||
h.suffix = "2006-01-02_15"
|
|
||||||
case WhenDay:
|
|
||||||
h.interval = 3600 * 24
|
|
||||||
h.suffix = "2006-01-02"
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("invalid when_rotate: %d", when)
|
|
||||||
}
|
|
||||||
|
|
||||||
h.interval = h.interval * int64(interval)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
h.fd, err = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
fInfo, _ := h.fd.Stat()
|
|
||||||
h.rolloverAt = fInfo.ModTime().Unix() + h.interval
|
|
||||||
|
|
||||||
return h, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *TimeRotatingFileHandler) doRollover() {
|
|
||||||
//refer http://hg.python.org/cpython/file/2.7/Lib/logging/handlers.py
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
if h.rolloverAt <= now.Unix() {
|
|
||||||
fName := h.baseName + now.Format(h.suffix)
|
|
||||||
h.fd.Close()
|
|
||||||
e := os.Rename(h.baseName, fName)
|
|
||||||
if e != nil {
|
|
||||||
panic(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
h.fd, _ = os.OpenFile(h.baseName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
|
||||||
|
|
||||||
h.rolloverAt = time.Now().Unix() + h.interval
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *TimeRotatingFileHandler) Write(b []byte) (n int, err error) {
|
|
||||||
h.doRollover()
|
|
||||||
return h.fd.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *TimeRotatingFileHandler) Close() error {
|
|
||||||
return h.fd.Close()
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Handler interface {
|
|
||||||
Write(p []byte) (n int, err error)
|
|
||||||
Close() error
|
|
||||||
}
|
|
||||||
|
|
||||||
type StreamHandler struct {
|
|
||||||
w io.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewStreamHandler(w io.Writer) (*StreamHandler, error) {
|
|
||||||
h := new(StreamHandler)
|
|
||||||
|
|
||||||
h.w = w
|
|
||||||
|
|
||||||
return h, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *StreamHandler) Write(b []byte) (n int, err error) {
|
|
||||||
return h.w.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *StreamHandler) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type NullHandler struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewNullHandler() (*NullHandler, error) {
|
|
||||||
return new(NullHandler), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *NullHandler) Write(b []byte) (n int, err error) {
|
|
||||||
return len(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *NullHandler) Close() {
|
|
||||||
|
|
||||||
}
|
|
226
log/log.go
226
log/log.go
|
@ -1,226 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
LevelTrace = iota
|
|
||||||
LevelDebug
|
|
||||||
LevelInfo
|
|
||||||
LevelWarn
|
|
||||||
LevelError
|
|
||||||
LevelFatal
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
Ltime = 1 << iota //time format "2006/01/02 15:04:05"
|
|
||||||
Lfile //file.go:123
|
|
||||||
Llevel //[Trace|Debug|Info...]
|
|
||||||
)
|
|
||||||
|
|
||||||
var LevelName [6]string = [6]string{"Trace", "Debug", "Info", "Warn", "Error", "Fatal"}
|
|
||||||
|
|
||||||
const TimeFormat = "2006/01/02 15:04:05"
|
|
||||||
|
|
||||||
const maxBufPoolSize = 16
|
|
||||||
|
|
||||||
type Logger struct {
|
|
||||||
sync.Mutex
|
|
||||||
|
|
||||||
level int
|
|
||||||
flag int
|
|
||||||
|
|
||||||
handler Handler
|
|
||||||
|
|
||||||
quit chan struct{}
|
|
||||||
msg chan []byte
|
|
||||||
|
|
||||||
bufs [][]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(handler Handler, flag int) *Logger {
|
|
||||||
var l = new(Logger)
|
|
||||||
|
|
||||||
l.level = LevelInfo
|
|
||||||
l.handler = handler
|
|
||||||
|
|
||||||
l.flag = flag
|
|
||||||
|
|
||||||
l.quit = make(chan struct{})
|
|
||||||
|
|
||||||
l.msg = make(chan []byte, 1024)
|
|
||||||
|
|
||||||
l.bufs = make([][]byte, 0, 16)
|
|
||||||
|
|
||||||
go l.run()
|
|
||||||
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDefault(handler Handler) *Logger {
|
|
||||||
return New(handler, Ltime|Lfile|Llevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStdHandler() *StreamHandler {
|
|
||||||
h, _ := NewStreamHandler(os.Stdout)
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
var std = NewDefault(newStdHandler())
|
|
||||||
|
|
||||||
func (l *Logger) run() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case msg := <-l.msg:
|
|
||||||
l.handler.Write(msg)
|
|
||||||
l.putBuf(msg)
|
|
||||||
case <-l.quit:
|
|
||||||
l.handler.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) popBuf() []byte {
|
|
||||||
l.Lock()
|
|
||||||
var buf []byte
|
|
||||||
if len(l.bufs) == 0 {
|
|
||||||
buf = make([]byte, 0, 1024)
|
|
||||||
} else {
|
|
||||||
buf = l.bufs[len(l.bufs)-1]
|
|
||||||
l.bufs = l.bufs[0 : len(l.bufs)-1]
|
|
||||||
}
|
|
||||||
l.Unlock()
|
|
||||||
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) putBuf(buf []byte) {
|
|
||||||
l.Lock()
|
|
||||||
if len(l.bufs) < maxBufPoolSize {
|
|
||||||
buf = buf[0:0]
|
|
||||||
l.bufs = append(l.bufs, buf)
|
|
||||||
}
|
|
||||||
l.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Close() {
|
|
||||||
if l.quit == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
close(l.quit)
|
|
||||||
l.quit = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) SetLevel(level int) {
|
|
||||||
l.level = level
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Output(callDepth int, level int, format string, v ...interface{}) {
|
|
||||||
if l.level > level {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := l.popBuf()
|
|
||||||
|
|
||||||
if l.flag&Ltime > 0 {
|
|
||||||
now := time.Now().Format(TimeFormat)
|
|
||||||
buf = append(buf, '[')
|
|
||||||
buf = append(buf, now...)
|
|
||||||
buf = append(buf, "] "...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if l.flag&Lfile > 0 {
|
|
||||||
_, file, line, ok := runtime.Caller(callDepth)
|
|
||||||
if !ok {
|
|
||||||
file = "???"
|
|
||||||
line = 0
|
|
||||||
} else {
|
|
||||||
for i := len(file) - 1; i > 0; i-- {
|
|
||||||
if file[i] == '/' {
|
|
||||||
file = file[i+1:]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = append(buf, file...)
|
|
||||||
buf = append(buf, ':')
|
|
||||||
|
|
||||||
strconv.AppendInt(buf, int64(line), 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
if l.flag&Llevel > 0 {
|
|
||||||
buf = append(buf, '[')
|
|
||||||
buf = append(buf, LevelName[level]...)
|
|
||||||
buf = append(buf, "] "...)
|
|
||||||
}
|
|
||||||
|
|
||||||
s := fmt.Sprintf(format, v...)
|
|
||||||
|
|
||||||
buf = append(buf, s...)
|
|
||||||
|
|
||||||
if s[len(s)-1] != '\n' {
|
|
||||||
buf = append(buf, '\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
l.msg <- buf
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Trace(format string, v ...interface{}) {
|
|
||||||
l.Output(2, LevelTrace, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Debug(format string, v ...interface{}) {
|
|
||||||
l.Output(2, LevelDebug, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Info(format string, v ...interface{}) {
|
|
||||||
l.Output(2, LevelInfo, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Warn(format string, v ...interface{}) {
|
|
||||||
l.Output(2, LevelWarn, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Error(format string, v ...interface{}) {
|
|
||||||
l.Output(2, LevelError, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *Logger) Fatal(format string, v ...interface{}) {
|
|
||||||
l.Output(2, LevelFatal, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetLevel(level int) {
|
|
||||||
std.SetLevel(level)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Trace(format string, v ...interface{}) {
|
|
||||||
std.Output(2, LevelTrace, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Debug(format string, v ...interface{}) {
|
|
||||||
std.Output(2, LevelDebug, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Info(format string, v ...interface{}) {
|
|
||||||
std.Output(2, LevelInfo, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Warn(format string, v ...interface{}) {
|
|
||||||
std.Output(2, LevelWarn, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Error(format string, v ...interface{}) {
|
|
||||||
std.Output(2, LevelError, format, v...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Fatal(format string, v ...interface{}) {
|
|
||||||
std.Output(2, LevelFatal, format, v...)
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStdStreamLog(t *testing.T) {
|
|
||||||
h, _ := NewStreamHandler(os.Stdout)
|
|
||||||
s := NewDefault(h)
|
|
||||||
s.Info("hello world")
|
|
||||||
|
|
||||||
s.Close()
|
|
||||||
|
|
||||||
Info("hello world")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRotatingFileLog(t *testing.T) {
|
|
||||||
path := "./test_log"
|
|
||||||
os.RemoveAll(path)
|
|
||||||
|
|
||||||
os.Mkdir(path, 0777)
|
|
||||||
fileName := path + "/test"
|
|
||||||
|
|
||||||
h, err := NewRotatingFileHandler(fileName, 10, 2)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := make([]byte, 10)
|
|
||||||
|
|
||||||
h.Write(buf)
|
|
||||||
|
|
||||||
h.Write(buf)
|
|
||||||
|
|
||||||
if _, err := os.Stat(fileName + ".1"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Stat(fileName + ".2"); err == nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
h.Write(buf)
|
|
||||||
if _, err := os.Stat(fileName + ".2"); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
h.Close()
|
|
||||||
|
|
||||||
os.RemoveAll(path)
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
package log
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SocketHandler struct {
|
|
||||||
c net.Conn
|
|
||||||
protocol string
|
|
||||||
addr string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSocketHandler(protocol string, addr string) (*SocketHandler, error) {
|
|
||||||
s := new(SocketHandler)
|
|
||||||
|
|
||||||
s.protocol = protocol
|
|
||||||
s.addr = addr
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *SocketHandler) Write(p []byte) (n int, err error) {
|
|
||||||
if err = h.connect(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := make([]byte, len(p)+4)
|
|
||||||
|
|
||||||
binary.BigEndian.PutUint32(buf, uint32(len(p)))
|
|
||||||
|
|
||||||
copy(buf[4:], p)
|
|
||||||
|
|
||||||
n, err = h.c.Write(buf)
|
|
||||||
if err != nil {
|
|
||||||
h.c.Close()
|
|
||||||
h.c = nil
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *SocketHandler) Close() error {
|
|
||||||
if h.c != nil {
|
|
||||||
h.c.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *SocketHandler) connect() error {
|
|
||||||
if h.c != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
h.c, err = net.DialTimeout(h.protocol, h.addr, 20*time.Second)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/siddontang/ledisdb/log"
|
"github.com/siddontang/go-log/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/siddontang/go-log/log"
|
||||||
"github.com/siddontang/ledisdb/ledis"
|
"github.com/siddontang/ledisdb/ledis"
|
||||||
"github.com/siddontang/ledisdb/log"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/siddontang/go-log/log"
|
||||||
"github.com/siddontang/ledisdb/ledis"
|
"github.com/siddontang/ledisdb/ledis"
|
||||||
"github.com/siddontang/ledisdb/log"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
Loading…
Reference in New Issue