summaryrefslogtreecommitdiffstats
path: root/adapter/statsclient
diff options
context:
space:
mode:
authorVladimir Lavor <vlavor@cisco.com>2021-05-13 11:15:48 +0200
committerVladimir Lavor <vlavor@cisco.com>2021-05-26 09:53:08 +0200
commitba6e92d715c59dc71c4e18e66b262d07578d524b (patch)
treecfea5f53750b52d3eccf7bdb1947936dd7e31ee1 /adapter/statsclient
parentc380ee6064379258768fdfe4e9d4ad9138980ec0 (diff)
statsclient: added symlinks
Symlink support based on https://gerrit.fd.io/r/c/vpp/+/31636 Added new stat types `CounterStat` and `CombinedCounterStat` which represent simple/combined value of a single item (interface, node) as a array of values by workers. Example: /if/names NameVector [local0 tap0 tap1] /if/ip6 SimpleCounterVector [[0 9 0] [0 25 3] [0 0 60] [0 0 0]] /interfaces/tap0/ip6 SimpleCounterVector [[9] [25] [0] [0]] /interfaces/tap1/ip6 SimpleCounterVector [[0] [3] [60] [0]] Field `Symlink` added to StatEntry to mark symlink stats. For stats v2 only Change-Id: Iadc825f3c42b05bfc9a91462dba8a0b0068c7cd6 Signed-off-by: Vladimir Lavor <vlavor@cisco.com>
Diffstat (limited to 'adapter/statsclient')
-rw-r--r--adapter/statsclient/stat_segment_api.go7
-rw-r--r--adapter/statsclient/statsclient.go6
-rw-r--r--adapter/statsclient/statseg_v1.go5
-rw-r--r--adapter/statsclient/statseg_v2.go80
4 files changed, 82 insertions, 16 deletions
diff --git a/adapter/statsclient/stat_segment_api.go b/adapter/statsclient/stat_segment_api.go
index 23755a5..2161e6e 100644
--- a/adapter/statsclient/stat_segment_api.go
+++ b/adapter/statsclient/stat_segment_api.go
@@ -46,6 +46,7 @@ const (
statDirErrorIndex = 4
statDirNameVector = 5
statDirEmpty = 6
+ statDirSymlink = 7
)
type (
@@ -75,8 +76,10 @@ type statSegment interface {
GetEpoch() (int64, bool)
// CopyEntryData accepts pointer to a directory segment and returns adapter.Stat
- // based on directory type populated with data
- CopyEntryData(segment dirSegment) adapter.Stat
+ // based on directory type populated with data. The index is an optional parameter
+ // (used by symlinks) returning stats for item on the given index only.
+ // Use ^uint32(0) as an empty index (since 0 is a valid value).
+ CopyEntryData(segment dirSegment, index uint32) adapter.Stat
// UpdateEntryData accepts pointer to a directory segment with data, and stat
// segment to update
diff --git a/adapter/statsclient/statsclient.go b/adapter/statsclient/statsclient.go
index 16af16a..0b16a77 100644
--- a/adapter/statsclient/statsclient.go
+++ b/adapter/statsclient/statsclient.go
@@ -505,13 +505,15 @@ func (sc *StatsClient) getStatEntriesOnIndex(vector dirVector, indexes ...uint32
if len(dirName) == 0 {
return
}
+ d := sc.CopyEntryData(dirPtr, ^uint32(0))
entries = append(entries, adapter.StatEntry{
StatIdentifier: adapter.StatIdentifier{
Index: index,
Name: dirName,
},
- Type: adapter.StatType(dirType),
- Data: sc.CopyEntryData(dirPtr),
+ Type: d.Type(),
+ Data: d,
+ Symlink: adapter.StatType(dirType) == adapter.Symlink,
})
}
return entries, nil
diff --git a/adapter/statsclient/statseg_v1.go b/adapter/statsclient/statseg_v1.go
index e9e8331..efd487e 100644
--- a/adapter/statsclient/statseg_v1.go
+++ b/adapter/statsclient/statseg_v1.go
@@ -93,7 +93,7 @@ func (ss *statSegmentV1) GetEpoch() (int64, bool) {
return sh.epoch, sh.inProgress != 0
}
-func (ss *statSegmentV1) CopyEntryData(segment dirSegment) adapter.Stat {
+func (ss *statSegmentV1) CopyEntryData(segment dirSegment, _ uint32) adapter.Stat {
dirEntry := (*statSegDirectoryEntryV1)(segment)
dirType := adapter.StatType(dirEntry.directoryType)
@@ -214,6 +214,9 @@ func (ss *statSegmentV1) CopyEntryData(segment dirSegment) adapter.Stat {
case statDirEmpty:
// no-op
+ case statDirSymlink:
+ debugf("Symlinks are not supported for stats v1")
+
default:
// TODO: monitor occurrences with metrics
debugf("Unknown type %d for stat entry: %q", dirEntry.directoryType, dirEntry.name)
diff --git a/adapter/statsclient/statseg_v2.go b/adapter/statsclient/statseg_v2.go
index 10bc5f5..16f1729 100644
--- a/adapter/statsclient/statseg_v2.go
+++ b/adapter/statsclient/statseg_v2.go
@@ -15,6 +15,8 @@
package statsclient
import (
+ "bytes"
+ "encoding/binary"
"sync/atomic"
"unsafe"
@@ -38,6 +40,7 @@ type sharedHeaderV2 struct {
type statSegDirectoryEntryV2 struct {
directoryType dirType
// unionData can represent:
+ // - symlink indexes
// - index
// - value
// - pointer to data
@@ -87,7 +90,7 @@ func (ss *statSegmentV2) GetEpoch() (int64, bool) {
return sh.epoch, sh.inProgress != 0
}
-func (ss *statSegmentV2) CopyEntryData(segment dirSegment) adapter.Stat {
+func (ss *statSegmentV2) CopyEntryData(segment dirSegment, index uint32) adapter.Stat {
dirEntry := (*statSegDirectoryEntryV2)(segment)
if dirEntry.unionData == 0 {
debugf("data value or pointer not defined for %s", dirEntry.name)
@@ -135,11 +138,21 @@ func (ss *statSegmentV2) CopyEntryData(segment dirSegment) adapter.Stat {
continue
}
counterVectorLength := *(*uint32)(vectorLen(counterVector))
- data[i] = make([]adapter.Counter, counterVectorLength)
- for j := uint32(0); j < counterVectorLength; j++ {
- offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
- val := *(*adapter.Counter)(statSegPointer(counterVector, offset))
- data[i][j] = val
+ if index == ^uint32(0) {
+ data[i] = make([]adapter.Counter, counterVectorLength)
+ for j := uint32(0); j < counterVectorLength; j++ {
+ offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
+ data[i][j] = *(*adapter.Counter)(statSegPointer(counterVector, offset))
+ }
+ } else {
+ data[i] = make([]adapter.Counter, 1) // expect single value
+ for j := uint32(0); j < counterVectorLength; j++ {
+ offset := uintptr(j) * unsafe.Sizeof(adapter.Counter(0))
+ if index == j {
+ data[i][0] = *(*adapter.Counter)(statSegPointer(counterVector, offset))
+ break
+ }
+ }
}
}
return adapter.SimpleCounterStat(data)
@@ -160,11 +173,21 @@ func (ss *statSegmentV2) CopyEntryData(segment dirSegment) adapter.Stat {
continue
}
counterVectorLength := *(*uint32)(vectorLen(counterVector))
- data[i] = make([]adapter.CombinedCounter, counterVectorLength)
- for j := uint32(0); j < counterVectorLength; j++ {
- offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
- val := *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
- data[i][j] = val
+ if index == ^uint32(0) {
+ data[i] = make([]adapter.CombinedCounter, counterVectorLength)
+ for j := uint32(0); j < counterVectorLength; j++ {
+ offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
+ data[i][j] = *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
+ }
+ } else {
+ data[i] = make([]adapter.CombinedCounter, 1) // expect single value pair
+ for j := uint32(0); j < counterVectorLength; j++ {
+ offset := uintptr(j) * unsafe.Sizeof(adapter.CombinedCounter{})
+ if index == j {
+ data[i][0] = *(*adapter.CombinedCounter)(statSegPointer(counterVector, offset))
+ break
+ }
+ }
}
}
return adapter.CombinedCounterStat(data)
@@ -205,6 +228,22 @@ func (ss *statSegmentV2) CopyEntryData(segment dirSegment) adapter.Stat {
return adapter.EmptyStat("<none>")
// no-op
+ case statDirSymlink:
+ // prevent recursion loops
+ if index != ^uint32(0) {
+ debugf("received symlink with defined item index")
+ return nil
+ }
+ i1, i2 := ss.getSymlinkIndexes(dirEntry)
+ // use first index to get the stats directory the symlink points to
+ header := ss.loadSharedHeader(ss.sharedHeader)
+ dirVector := ss.adjust(dirVector(&header.dirVector))
+ statSegDir2 := dirSegment(uintptr(dirVector) + uintptr(i1)*unsafe.Sizeof(statSegDirectoryEntryV2{}))
+
+ // retry with actual stats segment and use second index to get
+ // stats for the required item
+ return ss.CopyEntryData(statSegDir2, i2)
+
default:
// TODO: monitor occurrences with metrics
debugf("Unknown type %d for stat entry: %q", dirEntry.directoryType, dirEntry.name)
@@ -349,3 +388,22 @@ func (ss *statSegmentV2) getErrorVector() dirVector {
header := ss.loadSharedHeader(ss.sharedHeader)
return ss.adjust(dirVector(&header.errorVector))
}
+
+func (ss *statSegmentV2) getSymlinkIndexes(dirEntry *statSegDirectoryEntryV2) (index1, index2 uint32) {
+ var b bytes.Buffer
+ if err := binary.Write(&b, binary.LittleEndian, dirEntry.unionData); err != nil {
+ debugf("error getting symlink indexes for %s: %v", dirEntry.name, err)
+ return
+ }
+ if len(b.Bytes()) != 8 {
+ debugf("incorrect symlink union data length for %s: expected 8, got %d", dirEntry.name, len(b.Bytes()))
+ return
+ }
+ for i := range b.Bytes()[:4] {
+ index1 += uint32(b.Bytes()[i]) << (uint32(i) * 8)
+ }
+ for i := range b.Bytes()[4:] {
+ index2 += uint32(b.Bytes()[i+4]) << (uint32(i) * 8)
+ }
+ return
+}