diff options
author | Vladimir Lavor <vlavor@cisco.com> | 2021-03-17 12:27:10 +0100 |
---|---|---|
committer | Vladimir Lavor <vlavor@cisco.com> | 2021-05-05 13:26:19 +0200 |
commit | c380ee6064379258768fdfe4e9d4ad9138980ec0 (patch) | |
tree | 28903f9ee23bb3206e21a2c04001ebfc560de944 /adapter/statsclient/statsclient.go | |
parent | a6607d9c1ba37320984c13580c932076cbff6dd6 (diff) |
statsclient: allow index as pattern
* ListStats() returns stats identifiers containing the stat name and index
* New method PrepareDirOnIndex(indexes...). Instead of the name filter
it does not browse through all available indexes
* Stats example shows how to get the last epoch value (added "e" or "epoch" command)
Change-Id: Ibb15090fb0dfdb7f9b0ecf8ac07a5eb9a9ace8f8
Signed-off-by: Vladimir Lavor <vlavor@cisco.com>
Diffstat (limited to 'adapter/statsclient/statsclient.go')
-rw-r--r-- | adapter/statsclient/statsclient.go | 237 |
1 files changed, 134 insertions, 103 deletions
diff --git a/adapter/statsclient/statsclient.go b/adapter/statsclient/statsclient.go index b2d91db..16af16a 100644 --- a/adapter/statsclient/statsclient.go +++ b/adapter/statsclient/statsclient.go @@ -157,7 +157,7 @@ func (sc *StatsClient) Disconnect() error { 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 } @@ -166,76 +166,35 @@ func (sc *StatsClient) ListStats(patterns ...string) ([]string, error) { 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 } @@ -243,49 +202,55 @@ func (sc *StatsClient) PrepareDir(patterns ...string) (*adapter.StatDir, error) 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 } @@ -304,34 +269,18 @@ func (sc *StatsClient) UpdateDir(dir *adapter.StatDir) (err error) { 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 } @@ -518,10 +467,79 @@ func (sc *StatsClient) accessEnd(accessEpoch int64) bool { 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 { @@ -531,7 +549,7 @@ func (sc *StatsClient) listIndexes(patterns ...string) (indexes []uint32, err er } regexes[i] = r } - nameMatches := func(name []byte) bool { + nameMatches := func(name dirName) bool { for _, r := range regexes { if r.Match(name) { return true @@ -539,26 +557,20 @@ func (sc *StatsClient) listIndexes(patterns ...string) (indexes []uint32, err er } 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 @@ -573,3 +585,22 @@ func (sc *StatsClient) listIndexesFunc(f func(name []byte) bool) (indexes []uint 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 +} |