aboutsummaryrefslogtreecommitdiffstats
path: root/adapter/statsclient/statseg_v2.go
diff options
context:
space:
mode:
Diffstat (limited to 'adapter/statsclient/statseg_v2.go')
-rw-r--r--adapter/statsclient/statseg_v2.go351
1 files changed, 351 insertions, 0 deletions
diff --git a/adapter/statsclient/statseg_v2.go b/adapter/statsclient/statseg_v2.go
new file mode 100644
index 0000000..7091ff9
--- /dev/null
+++ b/adapter/statsclient/statseg_v2.go
@@ -0,0 +1,351 @@
+// Copyright (c) 2020 Cisco and/or its affiliates.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package statsclient
+
+import (
+ "fmt"
+ "sync/atomic"
+ "unsafe"
+
+ "git.fd.io/govpp.git/adapter"
+)
+
+type statSegmentV2 struct {
+ sharedHeader []byte
+ memorySize int64
+}
+
+type sharedHeaderV2 struct {
+ version uint64
+ base unsafe.Pointer
+ epoch int64
+ inProgress int64
+ dirVector unsafe.Pointer
+ errorVector unsafe.Pointer
+}
+
+type statSegDirectoryEntryV2 struct {
+ directoryType statDirectoryType
+ // unionData can represent:
+ // - index
+ // - value
+ // - pointer to data
+ unionData uint64
+ name [128]byte
+}
+
+func newStatSegmentV2(data []byte, size int64) *statSegmentV2 {
+ return &statSegmentV2{
+ sharedHeader: data,
+ memorySize: size,
+ }
+}
+
+func (ss *statSegmentV2) loadSharedHeader(b []byte) (header sharedHeaderV2) {
+ h := (*sharedHeaderV2)(unsafe.Pointer(&b[0]))
+ return sharedHeaderV2{
+ version: atomic.LoadUint64(&h.version),
+ base: atomic.LoadPointer(&h.base),
+ epoch: atomic.LoadInt64(&h.epoch),
+ inProgress: atomic.LoadInt64(&h.inProgress),
+ dirVector: atomic.LoadPointer(&h.dirVector),
+ errorVector: atomic.LoadPointer(&h.errorVector),
+ }
+}
+
+func (ss *statSegmentV2) GetDirectoryVector() (unsafe.Pointer, error) {
+ header := ss.loadSharedHeader(ss.sharedHeader)
+ return ss.adjust(unsafe.Pointer(&header.dirVector))
+}
+
+func (ss *statSegmentV2) GetStatDirOnIndex(p unsafe.Pointer, index uint32) (unsafe.Pointer, statDirectoryName, statDirectoryType) {
+ statSegDir := unsafe.Pointer(uintptr(p) + uintptr(index)*unsafe.Sizeof(statSegDirectoryEntryV2{}))
+ dir := (*statSegDirectoryEntryV2)(statSegDir)
+ var name []byte
+ for n := 0; n < len(dir.name); n++ {
+ if dir.name[n] == 0 {
+ name = dir.name[:n]
+ break
+ }
+ }
+ return statSegDir, name, dir.directoryType
+}
+
+func (ss *statSegmentV2) GetEpoch() (int64, bool) {
+ sh := ss.loadSharedHeader(ss.sharedHeader)
+ return sh.epoch, sh.inProgress != 0
+}
+
+func (ss *statSegmentV2) CopyEntryData(statSegDir unsafe.Pointer) adapter.Stat {
+ dirEntry := (*statSegDirectoryEntryV2)(statSegDir)
+ if dirEntry.unionData == 0 {
+ debugf("data value or pointer not defined for %s", dirEntry.name)
+ return nil
+ }
+
+ switch adapter.StatType(dirEntry.directoryType) {
+ case statDirScalarIndex:
+ return adapter.ScalarStat(dirEntry.unionData)
+
+ case statDirErrorIndex:
+ dirVector, err := ss.getErrorVector()
+ if err != nil {
+ debugf("error vector pointer is out of range for %s", dirEntry.name)
+ return nil
+ }
+ vecLen := *(*uint32)(vectorLen(dirVector))
+ var errData adapter.Counter
+ for i := uint32(0); i < vecLen; i++ {
+ cb := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
+ cbVal, err := ss.adjust(vectorLen(cb))
+ if err != nil {
+ debugf("error counter pointer out of range")
+ continue
+ }
+ offset := uintptr(dirEntry.unionData) * unsafe.Sizeof(adapter.Counter(0))
+ val := *(*adapter.Counter)(statSegPointer(cbVal, offset))
+ errData += val
+ }
+ return adapter.ErrorStat(errData)
+
+ case statDirCounterVectorSimple:
+ dirVector, err := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ if err != nil {
+ debugf("data vector pointer is out of range for %s", dirEntry.name)
+ return nil
+ }
+ vecLen := *(*uint32)(vectorLen(dirVector))
+ data := make([][]adapter.Counter, vecLen)
+ for i := uint32(0); i < vecLen; i++ {
+ counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
+ counterVector, err := ss.adjust(vectorLen(counterVectorOffset))
+ if err != nil {
+ debugf("counter (vector simple) pointer out of range")
+ 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
+ }
+ }
+ return adapter.SimpleCounterStat(data)
+
+ case statDirCounterVectorCombined:
+ dirVector, err := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ if err != nil {
+ debugf("data vector pointer is out of range for %s", dirEntry.name)
+ return nil
+ }
+ vecLen := *(*uint32)(vectorLen(dirVector))
+ data := make([][]adapter.CombinedCounter, vecLen)
+ for i := uint32(0); i < vecLen; i++ {
+ counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
+ counterVector, err := ss.adjust(vectorLen(counterVectorOffset))
+ if err != nil {
+ debugf("counter (vector combined) pointer out of range")
+ 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
+ }
+ }
+ return adapter.CombinedCounterStat(data)
+
+ case statDirNameVector:
+ dirVector, err := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ if err != nil {
+ debugf("data vector pointer is out of range for %s", dirEntry.name)
+ return nil
+ }
+ vecLen := *(*uint32)(vectorLen(dirVector))
+ data := make([]adapter.Name, vecLen)
+ for i := uint32(0); i < vecLen; i++ {
+ nameVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
+ if uintptr(nameVectorOffset) == 0 {
+ debugf("name vector out of range for %s (%v)", dirEntry.name, i)
+ continue
+ }
+ nameVector, err := ss.adjust(vectorLen(nameVectorOffset))
+ if err != nil {
+ debugf("name data pointer out of range")
+ continue
+ }
+ nameVectorLen := *(*uint32)(vectorLen(nameVector))
+ name := make([]byte, 0, nameVectorLen)
+ for j := uint32(0); j < nameVectorLen; j++ {
+ offset := uintptr(j) * unsafe.Sizeof(byte(0))
+ value := *(*byte)(statSegPointer(nameVector, offset))
+ if value > 0 {
+ name = append(name, value)
+ }
+ }
+ data[i] = name
+ }
+ return adapter.NameStat(data)
+
+ case statDirEmpty:
+ // no-op
+
+ default:
+ // TODO: monitor occurrences with metrics
+ debugf("Unknown type %d for stat entry: %q", dirEntry.directoryType, dirEntry.name)
+ }
+ return nil
+}
+
+func (ss *statSegmentV2) UpdateEntryData(statSegDir unsafe.Pointer, stat *adapter.Stat) error {
+ dirEntry := (*statSegDirectoryEntryV2)(statSegDir)
+ switch (*stat).(type) {
+ case adapter.ScalarStat:
+ *stat = adapter.ScalarStat(dirEntry.unionData)
+
+ case adapter.ErrorStat:
+ dirVector, err := ss.getErrorVector()
+ if err != nil {
+ debugf("error vector pointer is out of range for %s", dirEntry.name)
+ return nil
+ }
+ vecLen := *(*uint32)(vectorLen(dirVector))
+ var errData adapter.Counter
+ for i := uint32(0); i < vecLen; i++ {
+ cb := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
+ cbVal, err := ss.adjust(vectorLen(cb))
+ if err != nil {
+ debugf("error counter pointer out of range")
+ continue
+ }
+ offset := uintptr(dirEntry.unionData) * unsafe.Sizeof(adapter.Counter(0))
+ val := *(*adapter.Counter)(statSegPointer(cbVal, offset))
+ errData += val
+ }
+ *stat = adapter.ErrorStat(errData)
+
+ case adapter.SimpleCounterStat:
+ dirVector, err := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ if err != nil {
+ debugf("data vector pointer is out of range for %s", dirEntry.name)
+ return nil
+ }
+ vecLen := *(*uint32)(vectorLen(dirVector))
+ data := (*stat).(adapter.SimpleCounterStat)
+ if uint32(len(data)) != vecLen {
+ return ErrStatDataLenIncorrect
+ }
+ for i := uint32(0); i < vecLen; i++ {
+ counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
+ counterVector, err := ss.adjust(vectorLen(counterVectorOffset))
+ if err != nil {
+ debugf("counter (vector simple) pointer out of range")
+ 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
+ }
+ }
+
+ case adapter.CombinedCounterStat:
+ dirVector, err := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ if err != nil {
+ debugf("data vector pointer is out of range for %s", dirEntry.name)
+ return nil
+ }
+ vecLen := *(*uint32)(vectorLen(dirVector))
+ data := (*stat).(adapter.CombinedCounterStat)
+ for i := uint32(0); i < vecLen; i++ {
+ counterVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
+ counterVector, err := ss.adjust(vectorLen(counterVectorOffset))
+ if err != nil {
+ debugf("counter (vector combined) pointer out of range")
+ 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
+ }
+ }
+
+ case adapter.NameStat:
+ dirVector, err := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ if err != nil {
+ debugf("data vector pointer is out of range for %s", dirEntry.name)
+ return nil
+ }
+ vecLen := *(*uint32)(vectorLen(dirVector))
+ data := (*stat).(adapter.NameStat)
+ for i := uint32(0); i < vecLen; i++ {
+ nameVectorOffset := statSegPointer(dirVector, uintptr(i+1)*unsafe.Sizeof(uint64(0)))
+ if uintptr(nameVectorOffset) == 0 {
+ debugf("name vector out of range for %s (%v)", dirEntry.name, i)
+ continue
+ }
+ nameVector, err := ss.adjust(vectorLen(nameVectorOffset))
+ if err != nil {
+ debugf("name data pointer out of range")
+ continue
+ }
+ nameVectorLen := *(*uint32)(vectorLen(nameVector))
+ nameData := data[i]
+ if uint32(len(nameData))+1 != nameVectorLen {
+ return ErrStatDataLenIncorrect
+ }
+ for j := uint32(0); j < nameVectorLen; j++ {
+ offset := uintptr(j) * unsafe.Sizeof(byte(0))
+ value := *(*byte)(statSegPointer(nameVector, offset))
+ if value == 0 {
+ break
+ }
+ nameData[j] = value
+ }
+ }
+
+ default:
+ if Debug {
+ Log.Debugf("Unrecognized stat type %T for stat entry: %v", stat, dirEntry.name)
+ }
+ }
+ return nil
+}
+
+// Adjust data pointer using shared header and base and return
+// the pointer to a data segment
+func (ss *statSegmentV2) adjust(data unsafe.Pointer) (unsafe.Pointer, error) {
+ header := ss.loadSharedHeader(ss.sharedHeader)
+ adjusted := unsafe.Pointer(uintptr(unsafe.Pointer(&ss.sharedHeader[0])) +
+ uintptr(*(*uint64)(data)) - uintptr(*(*uint64)(unsafe.Pointer(&header.base))))
+ if uintptr(unsafe.Pointer(&ss.sharedHeader[len(ss.sharedHeader)-1])) <= uintptr(adjusted) ||
+ uintptr(unsafe.Pointer(&ss.sharedHeader[0])) >= uintptr(adjusted) {
+ return nil, fmt.Errorf("adjusted data out of range for %v", data)
+ }
+ return adjusted, nil
+}
+
+func (ss *statSegmentV2) getErrorVector() (unsafe.Pointer, error) {
+ header := ss.loadSharedHeader(ss.sharedHeader)
+ return ss.adjust(unsafe.Pointer(&header.errorVector))
+}