[ARVADOS] created: 2359eabb2e84dd9aa5109332c37b0f50aee896bc
git at public.curoverse.com
git at public.curoverse.com
Tue Jul 7 16:34:07 EDT 2015
at 2359eabb2e84dd9aa5109332c37b0f50aee896bc (commit)
commit 2359eabb2e84dd9aa5109332c37b0f50aee896bc
Author: Tom Clegg <tom at curoverse.com>
Date: Tue Jul 7 16:31:55 2015 -0400
6222: Add memory stats to status.json.
Reduce malloc activity in status.json.
Remove abandoned GetVolumeStatus, and move its tests over to
volume_unix_test.go.
diff --git a/services/keepstore/bufferpool.go b/services/keepstore/bufferpool.go
index 373bfc7..9a35094 100644
--- a/services/keepstore/bufferpool.go
+++ b/services/keepstore/bufferpool.go
@@ -3,12 +3,15 @@ package main
import (
"log"
"sync"
+ "sync/atomic"
"time"
)
type bufferPool struct {
// limiter has a "true" placeholder for each in-use buffer.
limiter chan bool
+ // allocated is the number of bytes currently allocated to buffers.
+ allocated uint64
// Pool has unused buffers.
sync.Pool
}
@@ -16,6 +19,7 @@ type bufferPool struct {
func newBufferPool(count int, bufSize int) *bufferPool {
p := bufferPool{}
p.New = func() interface{} {
+ atomic.AddUint64(&p.allocated, uint64(bufSize))
return make([]byte, bufSize)
}
p.limiter = make(chan bool, count)
@@ -42,3 +46,18 @@ func (p *bufferPool) Put(buf []byte) {
p.Pool.Put(buf)
<-p.limiter
}
+
+// Alloc returns the number of bytes allocated to buffers.
+func (p *bufferPool) Alloc() uint64 {
+ return atomic.LoadUint64(&p.allocated)
+}
+
+// Cap returns the maximum number of buffers allowed.
+func (p *bufferPool) Cap() int {
+ return cap(p.limiter)
+}
+
+// Len returns the number of buffers in use right now.
+func (p *bufferPool) Len() int {
+ return len(p.limiter)
+}
diff --git a/services/keepstore/handlers.go b/services/keepstore/handlers.go
index 3898b55..d1169d5 100644
--- a/services/keepstore/handlers.go
+++ b/services/keepstore/handlers.go
@@ -19,8 +19,9 @@ import (
"net/http"
"os"
"regexp"
+ "runtime"
"strconv"
- "syscall"
+ "sync"
"time"
)
@@ -185,60 +186,52 @@ type VolumeStatus struct {
BytesUsed uint64 `json:"bytes_used"`
}
+type PoolStatus struct {
+ Alloc uint64 `json:"BytesAllocated"`
+ Cap int `json:"BuffersMax"`
+ Len int `json:"BuffersInUse"`
+}
+
type NodeStatus struct {
- Volumes []*VolumeStatus `json:"volumes"`
+ Volumes []*VolumeStatus `json:"volumes"`
+ BufferPool PoolStatus
+ Memory runtime.MemStats
}
+var st NodeStatus
+var stLock sync.Mutex
func StatusHandler(resp http.ResponseWriter, req *http.Request) {
- st := GetNodeStatus()
- if jstat, err := json.Marshal(st); err == nil {
+ stLock.Lock()
+ ReadNodeStatus(&st)
+ jstat, err := json.Marshal(&st)
+ stLock.Unlock()
+ if err == nil {
resp.Write(jstat)
} else {
log.Printf("json.Marshal: %s\n", err)
- log.Printf("NodeStatus = %v\n", st)
+ log.Printf("NodeStatus = %v\n", &st)
http.Error(resp, err.Error(), 500)
}
}
-// GetNodeStatus
-// Returns a NodeStatus struct describing this Keep
-// node's current status.
+// ReadNodeStatus populates the given NodeStatus struct with current
+// values.
//
-func GetNodeStatus() *NodeStatus {
- st := new(NodeStatus)
-
- st.Volumes = make([]*VolumeStatus, len(KeepVM.AllReadable()))
- for i, vol := range KeepVM.AllReadable() {
- st.Volumes[i] = vol.Status()
+func ReadNodeStatus(st *NodeStatus) {
+ vols := KeepVM.AllReadable()
+ if cap(st.Volumes) < len(vols) {
+ st.Volumes = make([]*VolumeStatus, len(vols))
}
- return st
-}
-
-// GetVolumeStatus
-// Returns a VolumeStatus describing the requested volume.
-//
-func GetVolumeStatus(volume string) *VolumeStatus {
- var fs syscall.Statfs_t
- var devnum uint64
-
- if fi, err := os.Stat(volume); err == nil {
- devnum = fi.Sys().(*syscall.Stat_t).Dev
- } else {
- log.Printf("GetVolumeStatus: os.Stat: %s\n", err)
- return nil
+ st.Volumes = st.Volumes[:0]
+ for _, vol := range vols {
+ if s := vol.Status(); s != nil {
+ st.Volumes = append(st.Volumes, s)
+ }
}
-
- err := syscall.Statfs(volume, &fs)
- if err != nil {
- log.Printf("GetVolumeStatus: statfs: %s\n", err)
- return nil
- }
- // These calculations match the way df calculates disk usage:
- // "free" space is measured by fs.Bavail, but "used" space
- // uses fs.Blocks - fs.Bfree.
- free := fs.Bavail * uint64(fs.Bsize)
- used := (fs.Blocks - fs.Bfree) * uint64(fs.Bsize)
- return &VolumeStatus{volume, devnum, free, used}
+ st.BufferPool.Alloc = bufs.Alloc()
+ st.BufferPool.Cap = bufs.Cap()
+ st.BufferPool.Len = bufs.Len()
+ runtime.ReadMemStats(&st.Memory)
}
// DeleteHandler processes DELETE requests.
diff --git a/services/keepstore/keepstore_test.go b/services/keepstore/keepstore_test.go
index 811cc70..e01b013 100644
--- a/services/keepstore/keepstore_test.go
+++ b/services/keepstore/keepstore_test.go
@@ -414,43 +414,6 @@ func TestIndex(t *testing.T) {
}
}
-// TestNodeStatus
-// Test that GetNodeStatus returns valid info about available volumes.
-//
-// TODO(twp): set up appropriate interfaces to permit more rigorous
-// testing.
-//
-func TestNodeStatus(t *testing.T) {
- defer teardown()
-
- // Set up test Keep volumes with some blocks.
- KeepVM = MakeTestVolumeManager(2)
- defer KeepVM.Close()
-
- vols := KeepVM.AllReadable()
- vols[0].Put(TEST_HASH, TEST_BLOCK)
- vols[1].Put(TEST_HASH_2, TEST_BLOCK_2)
-
- // Get node status and make a basic sanity check.
- st := GetNodeStatus()
- for i := range vols {
- volinfo := st.Volumes[i]
- mtp := volinfo.MountPoint
- if mtp != "/bogo" {
- t.Errorf("GetNodeStatus mount_point %s, expected /bogo", mtp)
- }
- if volinfo.DeviceNum == 0 {
- t.Errorf("uninitialized device_num in %v", volinfo)
- }
- if volinfo.BytesFree == 0 {
- t.Errorf("uninitialized bytes_free in %v", volinfo)
- }
- if volinfo.BytesUsed == 0 {
- t.Errorf("uninitialized bytes_used in %v", volinfo)
- }
- }
-}
-
// ========================================
// Helper functions for unit tests.
// ========================================
diff --git a/services/keepstore/volume_unix.go b/services/keepstore/volume_unix.go
index 61a98b5..7c8e40c 100644
--- a/services/keepstore/volume_unix.go
+++ b/services/keepstore/volume_unix.go
@@ -141,7 +141,7 @@ func (v *UnixVolume) Put(loc string, block []byte) error {
}
// Status returns a VolumeStatus struct describing the volume's
-// current state.
+// current state, or nil if an error occurs.
//
func (v *UnixVolume) Status() *VolumeStatus {
var fs syscall.Statfs_t
diff --git a/services/keepstore/volume_unix_test.go b/services/keepstore/volume_unix_test.go
index 1320d31..6bafa7c 100644
--- a/services/keepstore/volume_unix_test.go
+++ b/services/keepstore/volume_unix_test.go
@@ -326,3 +326,23 @@ func TestIsFull(t *testing.T) {
t.Errorf("%s: should no longer be full", v)
}
}
+
+func TestNodeStatus(t *testing.T) {
+ v := TempUnixVolume(t, false, false)
+ defer _teardown(v)
+
+ // Get node status and make a basic sanity check.
+ volinfo := v.Status()
+ if volinfo.MountPoint != v.root {
+ t.Errorf("GetNodeStatus mount_point %s, expected %s", volinfo.MountPoint, v.root)
+ }
+ if volinfo.DeviceNum == 0 {
+ t.Errorf("uninitialized device_num in %v", volinfo)
+ }
+ if volinfo.BytesFree == 0 {
+ t.Errorf("uninitialized bytes_free in %v", volinfo)
+ }
+ if volinfo.BytesUsed == 0 {
+ t.Errorf("uninitialized bytes_used in %v", volinfo)
+ }
+}
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list