}
// ListStats mocks name listing for all stats.
-func (a *StatsAdapter) ListStats(patterns ...string) ([]string, error) {
- var statNames []string
+func (a *StatsAdapter) ListStats(patterns ...string) ([]adapter.StatIdentifier, error) {
+ var statNames []adapter.StatIdentifier
for _, stat := range a.entries {
- statNames = append(statNames, string(stat.Name))
+ statNames = append(statNames, adapter.StatIdentifier{
+ Name: stat.Name,
+ Index: stat.Index,
+ })
}
return statNames, nil
}
return a.dir, nil
}
+func (a *StatsAdapter) PrepareDirOnIndex(indexes ...uint32) (*adapter.StatDir, error) {
+ return a.dir, nil
+}
+
func (a *StatsAdapter) UpdateDir(dir *adapter.StatDir) error {
*dir = *a.dir
return nil
// Disconnect terminates client connection.
Disconnect() error
- // ListStats lists names for stats matching patterns.
- ListStats(patterns ...string) (names []string, err error)
+ // ListStats lists indexed names for stats matching patterns.
+ ListStats(patterns ...string) (indexes []StatIdentifier, err error)
// DumpStats dumps all stat entries.
DumpStats(patterns ...string) (entries []StatEntry, err error)
// PrepareDir prepares new stat dir for entries that match any of prefixes.
PrepareDir(patterns ...string) (*StatDir, error)
+ // PrepareDirOnIndex prepares new stat dir for entries that match any of indexes.
+ PrepareDirOnIndex(indexes ...uint32) (*StatDir, error)
// UpdateDir updates stat dir and all of their entries.
UpdateDir(dir *StatDir) error
}
// StatDir defines directory of stats entries created by PrepareDir.
type StatDir struct {
Epoch int64
- Indexes []uint32
Entries []StatEntry
}
+// StatIdentifier holds a stat entry name and index
+type StatIdentifier struct {
+ Index uint32
+ Name []byte
+}
+
// StatEntry represents single stat entry. The type of stat stored in Data
// is defined by Type.
type StatEntry struct {
- Name []byte
+ StatIdentifier
Type StatType
Data Stat
}
type CombinedCounter [2]uint64
func (s CombinedCounter) Packets() uint64 {
- return uint64(s[0])
+ return s[0]
}
func (s CombinedCounter) Bytes() uint64 {
- return uint64(s[1])
+ return s[1]
}
// Name represents string value stored under name vector.
func ReduceCombinedCounterStatIndex(s CombinedCounterStat, i int) [2]uint64 {
var val [2]uint64
for _, w := range s {
- val[0] += uint64(w[i][0])
- val[1] += uint64(w[i][1])
+ val[0] += w[i][0]
+ val[1] += w[i][1]
}
return val
}
statDirEmpty = 6
)
-type statDirectoryType int32
-
-type statDirectoryName []byte
+type (
+ dirVector unsafe.Pointer
+ dirSegment unsafe.Pointer
+ dirName []byte
+ dirType int32
+)
// statSegment represents common API for every stats API version
type statSegment interface {
// GetDirectoryVector returns pointer to memory where the beginning
// of the data directory is located.
- GetDirectoryVector() unsafe.Pointer
+ GetDirectoryVector() dirVector
// GetStatDirOnIndex accepts directory vector and particular index.
// Returns pointer to the beginning of the segment. Also the directory
//
// Note that if the index is equal to 0, the result pointer points to
// the same memory address as the argument.
- GetStatDirOnIndex(directory unsafe.Pointer, index uint32) (unsafe.Pointer, statDirectoryName, statDirectoryType)
+ GetStatDirOnIndex(v dirVector, index uint32) (dirSegment, dirName, dirType)
// GetEpoch re-loads stats header and returns current epoch
//and 'inProgress' value
// CopyEntryData accepts pointer to a directory segment and returns adapter.Stat
// based on directory type populated with data
- CopyEntryData(segment unsafe.Pointer) adapter.Stat
+ CopyEntryData(segment dirSegment) adapter.Stat
// UpdateEntryData accepts pointer to a directory segment with data, and stat
// segment to update
- UpdateEntryData(segment unsafe.Pointer, s *adapter.Stat) error
+ UpdateEntryData(segment dirSegment, s *adapter.Stat) error
}
// vecHeader represents a vector header
vectorData [0]uint8
}
-func (t statDirectoryType) String() string {
+func (t dirType) String() string {
return adapter.StatType(t).String()
}
return version.value
}
-func vectorLen(v unsafe.Pointer) unsafe.Pointer {
+func vectorLen(v dirVector) dirVector {
vec := *(*vecHeader)(unsafe.Pointer(uintptr(v) - unsafe.Sizeof(uint64(0))))
- return unsafe.Pointer(&vec.length)
+ return dirVector(&vec.length)
}
//go:nosplit
-func statSegPointer(p unsafe.Pointer, offset uintptr) unsafe.Pointer {
- return unsafe.Pointer(uintptr(p) + offset)
+func statSegPointer(v dirVector, offset uintptr) dirVector {
+ return dirVector(uintptr(v) + offset)
}
return nil
}
-func (sc *StatsClient) ListStats(patterns ...string) ([]string, error) {
+func (sc *StatsClient) ListStats(patterns ...string) (entries []adapter.StatIdentifier, err error) {
if !sc.isConnected() {
return nil, adapter.ErrStatsDisconnected
}
return nil, adapter.ErrStatsAccessFailed
}
- indexes, err := sc.listIndexes(patterns...)
+ entries, err = sc.getIdentifierEntries(patterns...)
if err != nil {
return nil, err
}
- dirVector := sc.GetDirectoryVector()
- if dirVector == nil {
- return nil, fmt.Errorf("failed to list stats: %v", err)
- }
- vecLen := *(*uint32)(vectorLen(dirVector))
-
- var names []string
- for _, index := range indexes {
- if index >= vecLen {
- return nil, fmt.Errorf("stat entry index %d out of dir vector len (%d)", index, vecLen)
- }
- _, dirName, _ := sc.GetStatDirOnIndex(dirVector, index)
- names = append(names, string(dirName))
- }
-
if !sc.accessEnd(accessEpoch) {
return nil, adapter.ErrStatsDataBusy
}
-
- return names, nil
+ return entries, nil
}
func (sc *StatsClient) DumpStats(patterns ...string) (entries []adapter.StatEntry, err error) {
if !sc.isConnected() {
return nil, adapter.ErrStatsDisconnected
}
+
accessEpoch := sc.accessStart()
if accessEpoch == 0 {
return nil, adapter.ErrStatsAccessFailed
}
- indexes, err := sc.listIndexes(patterns...)
+ entries, err = sc.getStatEntries(patterns...)
if err != nil {
return nil, err
}
- dirVector := sc.GetDirectoryVector()
- if dirVector == nil {
- return nil, err
- }
- dirLen := *(*uint32)(vectorLen(dirVector))
-
- debugf("dumping entries for %d indexes", len(indexes))
-
- entries = make([]adapter.StatEntry, 0, len(indexes))
- for _, index := range indexes {
- if index >= dirLen {
- return nil, fmt.Errorf("stat entry index %d out of dir vector length (%d)", index, dirLen)
- }
- dirPtr, dirName, dirType := sc.GetStatDirOnIndex(dirVector, index)
- if len(dirName) == 0 {
- continue
- }
- entry := adapter.StatEntry{
- Name: append([]byte(nil), dirName...),
- Type: adapter.StatType(dirType),
- Data: sc.CopyEntryData(dirPtr),
- }
- entries = append(entries, entry)
- }
-
if !sc.accessEnd(accessEpoch) {
return nil, adapter.ErrStatsDataBusy
}
-
return entries, nil
}
if !sc.isConnected() {
return nil, adapter.ErrStatsDisconnected
}
- dir := new(adapter.StatDir)
accessEpoch := sc.accessStart()
if accessEpoch == 0 {
return nil, adapter.ErrStatsAccessFailed
}
- indexes, err := sc.listIndexes(patterns...)
+ entries, err := sc.getStatEntries(patterns...)
if err != nil {
return nil, err
}
- dir.Indexes = indexes
- dirVector := sc.GetDirectoryVector()
- if dirVector == nil {
- return nil, err
+ if !sc.accessEnd(accessEpoch) {
+ return nil, adapter.ErrStatsDataBusy
}
- dirLen := *(*uint32)(vectorLen(dirVector))
- debugf("dumping entries for %d indexes", len(indexes))
+ dir := &adapter.StatDir{
+ Epoch: accessEpoch,
+ Entries: entries,
+ }
- entries := make([]adapter.StatEntry, 0, len(indexes))
- for _, index := range indexes {
- if index >= dirLen {
- return nil, fmt.Errorf("stat entry index %d out of dir vector length (%d)", index, dirLen)
- }
- dirPtr, dirName, dirType := sc.GetStatDirOnIndex(dirVector, index)
- if len(dirName) == 0 {
- continue
- }
- entry := adapter.StatEntry{
- Name: append([]byte(nil), dirName...),
- Type: adapter.StatType(dirType),
- Data: sc.CopyEntryData(dirPtr),
- }
- entries = append(entries, entry)
+ return dir, nil
+}
+
+func (sc *StatsClient) PrepareDirOnIndex(indexes ...uint32) (*adapter.StatDir, error) {
+ if !sc.isConnected() {
+ return nil, adapter.ErrStatsDisconnected
+ }
+
+ accessEpoch := sc.accessStart()
+ if accessEpoch == 0 {
+ return nil, adapter.ErrStatsAccessFailed
+ }
+ vector := sc.GetDirectoryVector()
+ if vector == nil {
+ return nil, fmt.Errorf("failed to prepare dir on index: directory vector is nil")
+ }
+ entries, err := sc.getStatEntriesOnIndex(vector, indexes...)
+ if err != nil {
+ return nil, err
}
- dir.Entries = entries
if !sc.accessEnd(accessEpoch) {
return nil, adapter.ErrStatsDataBusy
}
- dir.Epoch = accessEpoch
+
+ dir := &adapter.StatDir{
+ Epoch: accessEpoch,
+ Entries: entries,
+ }
return dir, nil
}
if accessEpoch == 0 {
return adapter.ErrStatsAccessFailed
}
-
dirVector := sc.GetDirectoryVector()
if dirVector == nil {
return err
}
- for i, index := range dir.Indexes {
- statSegDir, dirName, dirType := sc.GetStatDirOnIndex(dirVector, index)
- if len(dirName) == 0 {
- continue
- }
- entry := &dir.Entries[i]
- if !bytes.Equal(dirName, entry.Name) {
- continue
- }
- if adapter.StatType(dirType) != entry.Type {
- continue
- }
- if entry.Data == nil {
- continue
- }
- if err := sc.UpdateEntryData(statSegDir, &entry.Data); err != nil {
- return fmt.Errorf("updating stat data for entry %s failed: %v", dirName, err)
+ for i := 0; i < len(dir.Entries); i++ {
+ if err := sc.updateStatOnIndex(&dir.Entries[i], dirVector); err != nil {
+ return err
}
}
if !sc.accessEnd(accessEpoch) {
return adapter.ErrStatsDataBusy
}
-
return nil
}
return true
}
+// getStatEntries retrieves all stats matching desired patterns, or all stats if no pattern is provided.
+func (sc *StatsClient) getStatEntries(patterns ...string) (entries []adapter.StatEntry, err error) {
+ vector := sc.GetDirectoryVector()
+ if vector == nil {
+ return nil, fmt.Errorf("failed to get stat entries: directory vector is nil")
+ }
+ indexes, err := sc.listIndexes(vector, patterns...)
+ if err != nil {
+ return nil, err
+ }
+ return sc.getStatEntriesOnIndex(vector, indexes...)
+}
+
+// getIdentifierEntries retrieves all identifiers matching desired patterns, or all identifiers
+// if no pattern is provided.
+func (sc *StatsClient) getIdentifierEntries(patterns ...string) (identifiers []adapter.StatIdentifier, err error) {
+ vector := sc.GetDirectoryVector()
+ if vector == nil {
+ return nil, fmt.Errorf("failed to get identifier entries: directory vector is nil")
+ }
+ indexes, err := sc.listIndexes(vector, patterns...)
+ if err != nil {
+ return nil, err
+ }
+ return sc.getIdentifierEntriesOnIndex(vector, indexes...)
+}
+
+// getStatEntriesOnIndex retrieves stats on indexes, or all stats if indexes are not defined.
+func (sc *StatsClient) getStatEntriesOnIndex(vector dirVector, indexes ...uint32) (entries []adapter.StatEntry, err error) {
+ dirLen := *(*uint32)(vectorLen(vector))
+ for _, index := range indexes {
+ if index >= dirLen {
+ return nil, fmt.Errorf("stat entry index %d out of dir vector length (%d)", index, dirLen)
+ }
+ dirPtr, dirName, dirType := sc.GetStatDirOnIndex(vector, index)
+ if len(dirName) == 0 {
+ return
+ }
+ entries = append(entries, adapter.StatEntry{
+ StatIdentifier: adapter.StatIdentifier{
+ Index: index,
+ Name: dirName,
+ },
+ Type: adapter.StatType(dirType),
+ Data: sc.CopyEntryData(dirPtr),
+ })
+ }
+ return entries, nil
+}
+
+// getIdentifierEntriesOnIndex retrieves identifiers on indexes, or all identifiers if indexes are not defined.
+func (sc *StatsClient) getIdentifierEntriesOnIndex(vector dirVector, indexes ...uint32) (identifiers []adapter.StatIdentifier, err error) {
+ dirLen := *(*uint32)(vectorLen(vector))
+ for _, index := range indexes {
+ if index >= dirLen {
+ return nil, fmt.Errorf("stat entry index %d out of dir vector length (%d)", index, dirLen)
+ }
+ _, dirName, _ := sc.GetStatDirOnIndex(vector, index)
+ if len(dirName) == 0 {
+ return
+ }
+ identifiers = append(identifiers, adapter.StatIdentifier{
+ Index: index,
+ Name: dirName,
+ })
+ }
+ return identifiers, nil
+}
+
// listIndexes lists indexes for all stat entries that match any of the regex patterns.
-func (sc *StatsClient) listIndexes(patterns ...string) (indexes []uint32, err error) {
+func (sc *StatsClient) listIndexes(vector dirVector, patterns ...string) (indexes []uint32, err error) {
if len(patterns) == 0 {
- return sc.listIndexesFunc(nil)
+ return sc.listIndexesFunc(vector, nil)
}
var regexes = make([]*regexp.Regexp, len(patterns))
for i, pattern := range patterns {
}
regexes[i] = r
}
- nameMatches := func(name []byte) bool {
+ nameMatches := func(name dirName) bool {
for _, r := range regexes {
if r.Match(name) {
return true
}
return false
}
- return sc.listIndexesFunc(nameMatches)
+ return sc.listIndexesFunc(vector, nameMatches)
}
// listIndexesFunc lists stats indexes. The optional function
// argument filters returned values or returns all if empty
-func (sc *StatsClient) listIndexesFunc(f func(name []byte) bool) (indexes []uint32, err error) {
+func (sc *StatsClient) listIndexesFunc(vector dirVector, f func(name dirName) bool) (indexes []uint32, err error) {
if f == nil {
// there is around ~3157 stats, so to avoid too many allocations
// we set capacity to 3200 when listing all stats
indexes = make([]uint32, 0, 3200)
}
-
- dirVector := sc.GetDirectoryVector()
- if dirVector == nil {
- return nil, err
- }
- vecLen := *(*uint32)(vectorLen(dirVector))
-
+ vecLen := *(*uint32)(vectorLen(vector))
for i := uint32(0); i < vecLen; i++ {
- _, dirName, _ := sc.GetStatDirOnIndex(dirVector, i)
+ _, dirName, _ := sc.GetStatDirOnIndex(vector, i)
if f != nil {
if len(dirName) == 0 || !f(dirName) {
continue
func (sc *StatsClient) isConnected() bool {
return atomic.LoadUint32(&sc.connected) == 1
}
+
+// updateStatOnIndex refreshes the entry data.
+func (sc *StatsClient) updateStatOnIndex(entry *adapter.StatEntry, vector dirVector) (err error) {
+ dirLen := *(*uint32)(vectorLen(vector))
+ if entry.Index >= dirLen {
+ return fmt.Errorf("stat entry index %d out of dir vector length (%d)", entry.Index, dirLen)
+ }
+ dirPtr, dirName, dirType := sc.GetStatDirOnIndex(vector, entry.Index)
+ if len(dirName) == 0 ||
+ !bytes.Equal(dirName, entry.Name) ||
+ adapter.StatType(dirType) != entry.Type ||
+ entry.Data == nil {
+ return nil
+ }
+ if err := sc.UpdateEntryData(dirPtr, &entry.Data); err != nil {
+ err = fmt.Errorf("updating stat data for entry %s failed: %v", dirName, err)
+ }
+ return
+}
}
type statSegDirectoryEntryV1 struct {
- directoryType statDirectoryType
+ directoryType dirType
// unionData can represent:
// - offset
// - index
}
}
-func (ss *statSegmentV1) GetDirectoryVector() unsafe.Pointer {
+func (ss *statSegmentV1) GetDirectoryVector() dirVector {
dirOffset, _, _ := ss.getOffsets()
- return unsafe.Pointer(&ss.sharedHeader[dirOffset])
+ return dirVector(&ss.sharedHeader[dirOffset])
}
-func (ss *statSegmentV1) GetErrorVector() (unsafe.Pointer, error) {
+func (ss *statSegmentV1) getErrorVector() (unsafe.Pointer, error) {
return nil, fmt.Errorf("error vector is not defined for stats API v1")
}
-func (ss *statSegmentV1) GetStatDirOnIndex(p unsafe.Pointer, index uint32) (unsafe.Pointer, statDirectoryName, statDirectoryType) {
- statSegDir := unsafe.Pointer(uintptr(p) + uintptr(index)*unsafe.Sizeof(statSegDirectoryEntryV1{}))
+func (ss *statSegmentV1) GetStatDirOnIndex(v dirVector, index uint32) (dirSegment, dirName, dirType) {
+ statSegDir := dirSegment(uintptr(v) + uintptr(index)*unsafe.Sizeof(statSegDirectoryEntryV1{}))
dir := (*statSegDirectoryEntryV1)(statSegDir)
var name []byte
for n := 0; n < len(dir.name); n++ {
break
}
}
- return statSegDir, name, dir.directoryType
+ return statSegDir, dirName(name), dir.directoryType
}
func (ss *statSegmentV1) GetEpoch() (int64, bool) {
return sh.epoch, sh.inProgress != 0
}
-func (ss *statSegmentV1) CopyEntryData(statSegDir unsafe.Pointer) adapter.Stat {
- dirEntry := (*statSegDirectoryEntryV1)(statSegDir)
+func (ss *statSegmentV1) CopyEntryData(segment dirSegment) adapter.Stat {
+ dirEntry := (*statSegDirectoryEntryV1)(segment)
dirType := adapter.StatType(dirEntry.directoryType)
switch dirType {
}
_, errOffset, _ := ss.getOffsets()
- offsetVector := unsafe.Pointer(&ss.sharedHeader[errOffset])
+ offsetVector := dirVector(&ss.sharedHeader[errOffset])
var errData []adapter.Counter
cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
offset := uintptr(cb) + uintptr(dirEntry.unionData)*unsafe.Sizeof(adapter.Counter(0))
debugf("error index, cb: %d, offset: %d", cb, offset)
- val := *(*adapter.Counter)(statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), offset))
+ val := *(*adapter.Counter)(statSegPointer(dirVector(&ss.sharedHeader[0]), offset))
errData = append(errData, val)
}
return adapter.ErrorStat(errData)
break
}
- vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
- offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
+ vecLen := *(*uint32)(vectorLen(dirVector(&ss.sharedHeader[dirEntry.unionData])))
+ offsetVector := statSegPointer(dirVector(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
data := make([][]adapter.Counter, vecLen)
for i := uint32(0); i < vecLen; i++ {
cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
- counterVec := unsafe.Pointer(&ss.sharedHeader[uintptr(cb)])
+ counterVec := dirVector(&ss.sharedHeader[uintptr(cb)])
vecLen2 := *(*uint32)(vectorLen(counterVec))
data[i] = make([]adapter.Counter, vecLen2)
for j := uint32(0); j < vecLen2; j++ {
break
}
- vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
- offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
+ vecLen := *(*uint32)(vectorLen(dirVector(&ss.sharedHeader[dirEntry.unionData])))
+ offsetVector := statSegPointer(dirVector(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
data := make([][]adapter.CombinedCounter, vecLen)
for i := uint32(0); i < vecLen; i++ {
cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
- counterVec := unsafe.Pointer(&ss.sharedHeader[uintptr(cb)])
+ counterVec := dirVector(&ss.sharedHeader[uintptr(cb)])
vecLen2 := *(*uint32)(vectorLen(counterVec))
data[i] = make([]adapter.CombinedCounter, vecLen2)
for j := uint32(0); j < vecLen2; j++ {
break
}
- vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
- offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
+ vecLen := *(*uint32)(vectorLen(dirVector(&ss.sharedHeader[dirEntry.unionData])))
+ offsetVector := statSegPointer(dirVector(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
data := make([]adapter.Name, vecLen)
for i := uint32(0); i < vecLen; i++ {
debugf("name vector out of range for %s (%v)", dirEntry.name, i)
continue
}
- nameVec := unsafe.Pointer(&ss.sharedHeader[cb])
+ nameVec := dirVector(&ss.sharedHeader[cb])
vecLen2 := *(*uint32)(vectorLen(nameVec))
nameStr := make([]byte, 0, vecLen2)
return nil
}
-func (ss *statSegmentV1) UpdateEntryData(statSegDir unsafe.Pointer, stat *adapter.Stat) error {
- dirEntry := (*statSegDirectoryEntryV1)(statSegDir)
+func (ss *statSegmentV1) UpdateEntryData(segment dirSegment, stat *adapter.Stat) error {
+ dirEntry := (*statSegDirectoryEntryV1)(segment)
switch (*stat).(type) {
case adapter.ScalarStat:
*stat = adapter.ScalarStat(dirEntry.unionData)
}
_, errOffset, _ := ss.getOffsets()
- offsetVector := unsafe.Pointer(&ss.sharedHeader[errOffset])
+ offsetVector := dirVector(&ss.sharedHeader[errOffset])
var errData []adapter.Counter
- vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[errOffset])))
+ vecLen := *(*uint32)(vectorLen(dirVector(&ss.sharedHeader[errOffset])))
for i := uint32(0); i < vecLen; i++ {
cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
offset := uintptr(cb) + uintptr(dirEntry.unionData)*unsafe.Sizeof(adapter.Counter(0))
- val := *(*adapter.Counter)(statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), offset))
+ val := *(*adapter.Counter)(statSegPointer(dirVector(&ss.sharedHeader[0]), offset))
errData = append(errData, val)
}
*stat = adapter.ErrorStat(errData)
break
}
- vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
- offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
+ vecLen := *(*uint32)(vectorLen(dirVector(&ss.sharedHeader[dirEntry.unionData])))
+ offsetVector := statSegPointer(dirVector(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
data := (*stat).(adapter.SimpleCounterStat)
if uint32(len(data)) != vecLen {
}
for i := uint32(0); i < vecLen; i++ {
cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
- counterVec := unsafe.Pointer(&ss.sharedHeader[uintptr(cb)])
+ counterVec := dirVector(&ss.sharedHeader[uintptr(cb)])
vecLen2 := *(*uint32)(vectorLen(counterVec))
simpleData := data[i]
if uint32(len(simpleData)) != vecLen2 {
break
}
- vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
- offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
+ vecLen := *(*uint32)(vectorLen(dirVector(&ss.sharedHeader[dirEntry.unionData])))
+ offsetVector := statSegPointer(dirVector(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
data := (*stat).(adapter.CombinedCounterStat)
if uint32(len(data)) != vecLen {
}
for i := uint32(0); i < vecLen; i++ {
cb := *(*uint64)(statSegPointer(offsetVector, uintptr(i)*unsafe.Sizeof(uint64(0))))
- counterVec := unsafe.Pointer(&ss.sharedHeader[uintptr(cb)])
+ counterVec := dirVector(&ss.sharedHeader[uintptr(cb)])
vecLen2 := *(*uint32)(vectorLen(counterVec))
combData := data[i]
if uint32(len(combData)) != vecLen2 {
break
}
- vecLen := *(*uint32)(vectorLen(unsafe.Pointer(&ss.sharedHeader[dirEntry.unionData])))
- offsetVector := statSegPointer(unsafe.Pointer(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
+ vecLen := *(*uint32)(vectorLen(dirVector(&ss.sharedHeader[dirEntry.unionData])))
+ offsetVector := statSegPointer(dirVector(&ss.sharedHeader[0]), uintptr(dirEntry.offsetVector))
data := (*stat).(adapter.NameStat)
if uint32(len(data)) != vecLen {
if cb == 0 {
continue
}
- nameVec := unsafe.Pointer(&ss.sharedHeader[cb])
+ nameVec := dirVector(&ss.sharedHeader[cb])
vecLen2 := *(*uint32)(vectorLen(nameVec))
nameData := data[i]
}
type statSegDirectoryEntryV2 struct {
- directoryType statDirectoryType
+ directoryType dirType
// unionData can represent:
// - index
// - value
}
}
-func (ss *statSegmentV2) GetDirectoryVector() unsafe.Pointer {
+func (ss *statSegmentV2) GetDirectoryVector() dirVector {
header := ss.loadSharedHeader(ss.sharedHeader)
- return ss.adjust(unsafe.Pointer(&header.dirVector))
+ return ss.adjust(dirVector(&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{}))
+func (ss *statSegmentV2) GetStatDirOnIndex(v dirVector, index uint32) (dirSegment, dirName, dirType) {
+ statSegDir := dirSegment(uintptr(v) + uintptr(index)*unsafe.Sizeof(statSegDirectoryEntryV2{}))
dir := (*statSegDirectoryEntryV2)(statSegDir)
var name []byte
for n := 0; n < len(dir.name); n++ {
return sh.epoch, sh.inProgress != 0
}
-func (ss *statSegmentV2) CopyEntryData(statSegDir unsafe.Pointer) adapter.Stat {
- dirEntry := (*statSegDirectoryEntryV2)(statSegDir)
+func (ss *statSegmentV2) CopyEntryData(segment dirSegment) adapter.Stat {
+ dirEntry := (*statSegDirectoryEntryV2)(segment)
if dirEntry.unionData == 0 {
debugf("data value or pointer not defined for %s", dirEntry.name)
return nil
return adapter.ErrorStat(errData)
case statDirCounterVectorSimple:
- dirVector := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ dirVector := ss.adjust(dirVector(&dirEntry.unionData))
if dirVector == nil {
debugf("data vector pointer is out of range for %s", dirEntry.name)
return nil
return adapter.SimpleCounterStat(data)
case statDirCounterVectorCombined:
- dirVector := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ dirVector := ss.adjust(dirVector(&dirEntry.unionData))
if dirVector == nil {
debugf("data vector pointer is out of range for %s", dirEntry.name)
return nil
return adapter.CombinedCounterStat(data)
case statDirNameVector:
- dirVector := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ dirVector := ss.adjust(dirVector(&dirEntry.unionData))
if dirVector == nil {
debugf("data vector pointer is out of range for %s", dirEntry.name)
return nil
return nil
}
-func (ss *statSegmentV2) UpdateEntryData(statSegDir unsafe.Pointer, stat *adapter.Stat) error {
- dirEntry := (*statSegDirectoryEntryV2)(statSegDir)
+func (ss *statSegmentV2) UpdateEntryData(segment dirSegment, stat *adapter.Stat) error {
+ dirEntry := (*statSegDirectoryEntryV2)(segment)
switch (*stat).(type) {
case adapter.ScalarStat:
*stat = adapter.ScalarStat(dirEntry.unionData)
*stat = adapter.ErrorStat(errData)
case adapter.SimpleCounterStat:
- dirVector := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ dirVector := ss.adjust(dirVector(&dirEntry.unionData))
if dirVector == nil {
debugf("data vector pointer is out of range for %s", dirEntry.name)
return nil
}
case adapter.CombinedCounterStat:
- dirVector := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ dirVector := ss.adjust(dirVector(&dirEntry.unionData))
if dirVector == nil {
debugf("data vector pointer is out of range for %s", dirEntry.name)
return nil
}
case adapter.NameStat:
- dirVector := ss.adjust(unsafe.Pointer(&dirEntry.unionData))
+ dirVector := ss.adjust(dirVector(&dirEntry.unionData))
if dirVector == nil {
debugf("data vector pointer is out of range for %s", 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 {
+func (ss *statSegmentV2) adjust(data dirVector) dirVector {
header := ss.loadSharedHeader(ss.sharedHeader)
- adjusted := unsafe.Pointer(uintptr(unsafe.Pointer(&ss.sharedHeader[0])) +
+ adjusted := dirVector(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 adjusted
}
-func (ss *statSegmentV2) getErrorVector() unsafe.Pointer {
+func (ss *statSegmentV2) getErrorVector() dirVector {
header := ss.loadSharedHeader(ss.sharedHeader)
- return ss.adjust(unsafe.Pointer(&header.errorVector))
+ return ss.adjust(dirVector(&header.errorVector))
}
return nil
}
-func (c *statClient) ListStats(patterns ...string) (stats []string, err error) {
+func (c *statClient) ListStats(patterns ...string) (indexes []adapter.StatIdentifier, err error) {
dir := C.govpp_stat_segment_ls(convertStringSlice(patterns))
if dir == nil {
return nil, adapter.ErrStatsDataBusy
l := C.govpp_stat_segment_vec_len(unsafe.Pointer(dir))
for i := 0; i < int(l); i++ {
nameChar := C.govpp_stat_segment_dir_index_to_name(dir, C.uint32_t(i))
- stats = append(stats, C.GoString(nameChar))
+ indexes = append(indexes, adapter.StatIdentifier{
+ Name: []byte(C.GoString(nameChar)),
+ Index: uint32(i),
+ })
C.free(unsafe.Pointer(nameChar))
}
- return stats, nil
+ return indexes, nil
}
func (c *statClient) DumpStats(patterns ...string) (stats []adapter.StatEntry, err error) {
typ := adapter.StatType(C.govpp_stat_segment_data_type(&v))
stat := adapter.StatEntry{
- Name: []byte(name),
+ StatIdentifier: adapter.StatIdentifier{
+ Name: []byte(name),
+ Index: uint32(i),
+ },
Type: typ,
}
return nil, adapter.ErrNotImplemented
}
+func (c *statClient) PrepareDirOnIndex(indexes ...uint32) (*adapter.StatDir, error) {
+ return nil, adapter.ErrNotImplemented
+}
+
func (c *statClient) UpdateDir(dir *adapter.StatDir) error {
return adapter.ErrNotImplemented
}
return nil
}
-func (*stubStatClient) ListStats(patterns ...string) (statNames []string, err error) {
+func (*stubStatClient) ListStats(patterns ...string) (indexes []adapter.StatIdentifier, err error) {
return nil, adapter.ErrNotImplemented
}
return nil, adapter.ErrNotImplemented
}
+func (*stubStatClient) PrepareDirOnIndex(indexes ...uint32) (*adapter.StatDir, error) {
+ return nil, adapter.ErrNotImplemented
+}
+
func (*stubStatClient) UpdateDir(dir *adapter.StatDir) error {
return adapter.ErrNotImplemented
}
"fmt"
"log"
"os"
+ "strconv"
"strings"
"time"
func init() {
flag.Usage = func() {
- fmt.Fprintf(os.Stderr, "%s: usage [ls|dump|poll|errors|interfaces|nodes|system|buffers|memory] <patterns>...\n", os.Args[0])
+ fmt.Fprintf(os.Stderr, "%s: usage [ls|dump|poll|errors|interfaces|nodes|system|buffers|memory|epoch] <patterns/index>...\n", os.Args[0])
flag.PrintDefaults()
os.Exit(1)
}
flag.Parse()
skipZeros := !*dumpAll
- var patterns []string
+ patterns := make([]string, 0)
+ indexes := make([]uint32, 0)
if flag.NArg() > 0 {
- patterns = flag.Args()[1:]
+ for _, arg := range flag.Args()[1:] {
+ if index, err := strconv.Atoi(arg); err == nil {
+ indexes = append(indexes, uint32(index))
+ continue
+ }
+ patterns = append(patterns, arg)
+ }
}
var (
case "dump":
fmt.Printf("Dumping stats.. %s\n", strings.Join(patterns, " "))
- dumpStats(client, patterns, skipZeros)
+ dumpStats(client, patterns, indexes, skipZeros)
case "poll":
fmt.Printf("Polling stats.. %s\n", strings.Join(patterns, " "))
case "list", "ls", "":
fmt.Printf("Listing stats.. %s\n", strings.Join(patterns, " "))
- listStats(client, patterns)
+ listStats(client, patterns, indexes)
+
+ case "epoch", "e":
+ fmt.Printf("Getting epoch..\n")
+
+ getEpoch(client)
default:
fmt.Printf("invalid command: %q\n", cmd)
}
}
-func listStats(client adapter.StatsAPI, patterns []string) {
- list, err := client.ListStats(patterns...)
- if err != nil {
- log.Fatalln("listing stats failed:", err)
+func listStats(client adapter.StatsAPI, patterns []string, indexes []uint32) {
+ var err error
+ list := make([]adapter.StatIdentifier, 0)
+ if (len(patterns) == 0 && len(indexes) == 0) || len(patterns) != 0 {
+ list, err = client.ListStats(patterns...)
+ if err != nil {
+ log.Fatalln("listing stats failed:", err)
+ }
+ }
+ if len(indexes) != 0 {
+ dir, err := client.PrepareDirOnIndex(indexes...)
+ if err != nil {
+ log.Fatalln("listing stats failed:", err)
+ }
+ for _, onIndexSi := range dir.Entries {
+ list = append(list, onIndexSi.StatIdentifier)
+ }
}
-
for _, stat := range list {
- fmt.Printf(" - %v\n", stat)
+ fmt.Printf(" - %d\t %v\n", stat.Index, string(stat.Name))
}
fmt.Printf("Listed %d stats\n", len(list))
}
-func dumpStats(client adapter.StatsAPI, patterns []string, skipZeros bool) {
- stats, err := client.DumpStats(patterns...)
+func getEpoch(client adapter.StatsAPI) {
+ dir, err := client.PrepareDir()
if err != nil {
- log.Fatalln("dumping stats failed:", err)
+ log.Fatalln("failed to prepare dir in order to read epoch:", err)
+ }
+ d := *dir
+ fmt.Printf("Epoch %d\n", d.Epoch)
+}
+
+func dumpStats(client adapter.StatsAPI, patterns []string, indexes []uint32, skipZeros bool) {
+ var err error
+ stats := make([]adapter.StatEntry, 0)
+ if (len(patterns) == 0 && len(indexes) == 0) || len(patterns) != 0 {
+ stats, err = client.DumpStats(patterns...)
+ if err != nil {
+ log.Fatalln("dumping stats failed:", err)
+ }
+ }
+ if len(indexes) != 0 {
+ dir, err := client.PrepareDirOnIndex(indexes...)
+ if err != nil {
+ log.Fatalln("dumping stats failed:", err)
+ }
+ for _, onIndexSi := range dir.Entries {
+ stats = append(stats, onIndexSi)
+ }
}
n := 0