support error counters also as normal counters
[govpp.git] / adapter / statsclient / stat_segment_api.go
1 //  Copyright (c) 2020 Cisco and/or its affiliates.
2 //
3 //  Licensed under the Apache License, Version 2.0 (the "License");
4 //  you may not use this file except in compliance with the License.
5 //  You may obtain a copy of the License at:
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 //  Unless required by applicable law or agreed to in writing, software
10 //  distributed under the License is distributed on an "AS IS" BASIS,
11 //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 //  See the License for the specific language governing permissions and
13 //  limitations under the License.
14
15 package statsclient
16
17 import (
18         "fmt"
19         "git.fd.io/govpp.git/adapter"
20         "sync/atomic"
21         "time"
22         "unsafe"
23 )
24
25 var (
26         // ErrStatDataLenIncorrect is returned when stat data does not match vector
27         // length of a respective data directory
28         ErrStatDataLenIncorrect = fmt.Errorf("stat data length incorrect")
29 )
30
31 var (
32         MaxWaitInProgress    = time.Millisecond * 100
33         CheckDelayInProgress = time.Microsecond * 10
34 )
35
36 const (
37         minVersion = 1
38         maxVersion = 2
39 )
40
41 var dirTypeMapping = map[dirType]adapter.StatType{
42         1: adapter.ScalarIndex,
43         2: adapter.SimpleCounterVector,
44         3: adapter.CombinedCounterVector,
45         4: adapter.NameVector,
46         5: adapter.Empty,
47         6: adapter.Symlink,
48 }
49
50 var dirTypeMappingLegacy = map[dirType]adapter.StatType{
51         1: adapter.ScalarIndex,
52         2: adapter.SimpleCounterVector,
53         3: adapter.CombinedCounterVector,
54         4: adapter.ErrorIndex,
55         5: adapter.NameVector,
56         6: adapter.Empty,
57         7: adapter.Symlink,
58 }
59
60 type (
61         dirVector  unsafe.Pointer
62         dirSegment unsafe.Pointer
63         dirName    []byte
64         dirType    int32
65 )
66
67 // statSegment represents common API for every stats API version
68 type statSegment interface {
69         // GetDirectoryVector returns pointer to memory where the beginning
70         // of the data directory is located.
71         GetDirectoryVector() dirVector
72
73         // GetStatDirOnIndex accepts directory vector and particular index.
74         // Returns pointer to the beginning of the segment. Also the directory
75         // name as [128]byte and the directory type is returned for easy use
76         // without needing to know the exact segment version.
77         //
78         // Note that if the index is equal to 0, the result pointer points to
79         // the same memory address as the argument.
80         GetStatDirOnIndex(v dirVector, index uint32) (dirSegment, dirName, dirType)
81
82         // GetEpoch re-loads stats header and returns current epoch
83         //and 'inProgress' value
84         GetEpoch() (int64, bool)
85
86         // CopyEntryData accepts pointer to a directory segment and returns adapter.Stat
87         // based on directory type populated with data. The index is an optional parameter
88         // (used by symlinks) returning stats for item on the given index only.
89         // Use ^uint32(0) as an empty index (since 0 is a valid value).
90         CopyEntryData(segment dirSegment, index uint32) adapter.Stat
91
92         // UpdateEntryData accepts pointer to a directory segment with data, and stat
93         // segment to update
94         UpdateEntryData(segment dirSegment, s *adapter.Stat) error
95 }
96
97 // vecHeader represents a vector header
98 type vecHeader struct {
99         length     uint64
100         vectorData [0]uint8
101 }
102
103 func getVersion(data []byte) uint64 {
104         type apiVersion struct {
105                 value uint64
106         }
107         header := (*apiVersion)(unsafe.Pointer(&data[0]))
108         version := &apiVersion{
109                 value: atomic.LoadUint64(&header.value),
110         }
111         debugf("stats API version loaded: %d", version.value)
112         return version.value
113 }
114
115 func vectorLen(v dirVector) dirVector {
116         vec := *(*vecHeader)(unsafe.Pointer(uintptr(v) - unsafe.Sizeof(uint64(0))))
117         return dirVector(&vec.length)
118 }
119
120 func getStatType(dirTypeNum dirType, useLegacyMapping bool) (dirTyp adapter.StatType) {
121         var exists bool
122         if useLegacyMapping {
123                 dirTyp, exists = dirTypeMappingLegacy[dirTypeNum]
124         } else {
125                 dirTyp, exists = dirTypeMapping[dirTypeNum]
126         }
127         if exists {
128                 return dirTyp
129         }
130         return adapter.Unknown
131 }
132
133 //go:nosplit
134 func statSegPointer(v dirVector, offset uintptr) dirVector {
135         return dirVector(uintptr(v) + offset)
136 }