Skip to content

Commit 19603e4

Browse files
author
Konstantin Nikitin
committed
Fetching Statistics from memcached server
1 parent 72a6864 commit 19603e4

1 file changed

Lines changed: 84 additions & 0 deletions

File tree

memcache/memcache.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ var (
110110
resultTouched = []byte("TOUCHED\r\n")
111111

112112
resultClientErrorPrefix = []byte("CLIENT_ERROR ")
113+
114+
statsGetHits = []byte("STAT get_hits ")
115+
statsGetMisses = []byte("STAT get_misses ")
116+
statsBytesWritten = []byte("STAT bytes_written ")
117+
statsItems = []byte("STAT curr_items ")
118+
statsBytes = []byte("STAT bytes ")
113119
)
114120

115121
// New returns a memcache client using the provided server(s)
@@ -171,6 +177,24 @@ type conn struct {
171177
c *Client
172178
}
173179

180+
// Statistics is a record of memcached usage stats.
181+
type Statistics struct {
182+
// Counter of cache hits.
183+
Hits uint64
184+
185+
// Counter of cache misses.
186+
Misses uint64
187+
188+
// Counter of bytes transferred for gets.
189+
ByteHits uint64
190+
191+
// Items currently in the cache.
192+
Items uint64
193+
194+
// Size of all items currently in the cache.
195+
Bytes uint64
196+
}
197+
174198
// release returns this connection back to the client's free pool
175199
func (cn *conn) release() {
176200
cn.c.putFreeConn(cn.addr, cn)
@@ -667,3 +691,63 @@ func (c *Client) incrDecr(verb, key string, delta uint64) (uint64, error) {
667691
})
668692
return val, err
669693
}
694+
695+
func parseStatsLine(s []byte, expectedPrefix []byte) (uint64, error) {
696+
if !bytes.HasPrefix(s, expectedPrefix) {
697+
return 0, errors.New("line does not start with exceptedPrefix")
698+
}
699+
return strconv.ParseUint(
700+
string(s[len(expectedPrefix):len(s)-2]), 10, 64)
701+
}
702+
703+
// parseStatsResponse reads a GET response from r and calls cb for each
704+
// read and allocated Item
705+
func parseStatsResponse(r *bufio.Reader, stats *Statistics) error {
706+
for {
707+
line, err := r.ReadSlice('\n')
708+
if err != nil {
709+
return err
710+
}
711+
if bytes.Equal(line, resultEnd) {
712+
return nil
713+
}
714+
if hits, err := parseStatsLine(line, statsGetHits); err == nil {
715+
stats.Hits = hits
716+
continue
717+
}
718+
if misses, err := parseStatsLine(line, statsGetMisses); err == nil {
719+
stats.Misses = misses
720+
continue
721+
}
722+
if bytesWritten, err := parseStatsLine(line, statsBytesWritten); err == nil {
723+
stats.ByteHits = bytesWritten
724+
continue
725+
}
726+
if items, err := parseStatsLine(line, statsItems); err == nil {
727+
stats.Items = items
728+
continue
729+
}
730+
if bytes_total, err := parseStatsLine(line, statsBytes); err == nil {
731+
stats.Bytes = bytes_total
732+
continue
733+
}
734+
}
735+
}
736+
737+
738+
func (c *Client) Stats(addr net.Addr) (*Statistics, error) {
739+
stats := new(Statistics)
740+
err := c.withAddrRw(addr, func(rw *bufio.ReadWriter) error {
741+
if _, err := fmt.Fprintf(rw, "stats\r\n"); err != nil {
742+
return err
743+
}
744+
if err := rw.Flush(); err != nil {
745+
return err
746+
}
747+
if err := parseStatsResponse(rw.Reader, stats); err != nil {
748+
return err
749+
}
750+
return nil
751+
})
752+
return stats, err
753+
}

0 commit comments

Comments
 (0)