statsclient: added symlinks
[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 const (
42         statDirIllegal               = 0
43         statDirScalarIndex           = 1
44         statDirCounterVectorSimple   = 2
45         statDirCounterVectorCombined = 3
46         statDirErrorIndex            = 4
47         statDirNameVector            = 5
48         statDirEmpty                 = 6
49         statDirSymlink               = 7
50 )
51
52 type (
53         dirVector  unsafe.Pointer
54         dirSegment unsafe.Pointer
55         dirName    []byte
56         dirType    int32
57 )
58
59 // statSegment represents common API for every stats API version
60 type statSegment interface {
61         // GetDirectoryVector returns pointer to memory where the beginning
62         // of the data directory is located.
63         GetDirectoryVector() dirVector
64
65         // GetStatDirOnIndex accepts directory vector and particular index.
66         // Returns pointer to the beginning of the segment. Also the directory
67         // name as [128]byte and the directory type is returned for easy use
68         // without needing to know the exact segment version.
69         //
70         // Note that if the index is equal to 0, the result pointer points to
71         // the same memory address as the argument.
72         GetStatDirOnIndex(v dirVector, index uint32) (dirSegment, dirName, dirType)
73
74         // GetEpoch re-loads stats header and returns current epoch
75         //and 'inProgress' value
76         GetEpoch() (int64, bool)
77
78         // CopyEntryData accepts pointer to a directory segment and returns adapter.Stat
79         // based on directory type populated with data. The index is an optional parameter
80         // (used by symlinks) returning stats for item on the given index only.
81         // Use ^uint32(0) as an empty index (since 0 is a valid value).
82         CopyEntryData(segment dirSegment, index uint32) adapter.Stat
83
84         // UpdateEntryData accepts pointer to a directory segment with data, and stat
85         // segment to update
86         UpdateEntryData(segment dirSegment, s *adapter.Stat) error
87 }
88
89 // vecHeader represents a vector header
90 type vecHeader struct {
91         length     uint64
92         vectorData [0]uint8
93 }
94
95 func (t dirType) String() string {
96         return adapter.StatType(t).String()
97 }
98
99 func getVersion(data []byte) uint64 {
100         type apiVersion struct {
101                 value uint64
102         }
103         header := (*apiVersion)(unsafe.Pointer(&data[0]))
104         version := &apiVersion{
105                 value: atomic.LoadUint64(&header.value),
106         }
107         debugf("stats API version loaded: %d", version.value)
108         return version.value
109 }
110
111 func vectorLen(v dirVector) dirVector {
112         vec := *(*vecHeader)(unsafe.Pointer(uintptr(v) - unsafe.Sizeof(uint64(0))))
113         return dirVector(&vec.length)
114 }
115
116 //go:nosplit
117 func statSegPointer(v dirVector, offset uintptr) dirVector {
118         return dirVector(uintptr(v) + offset)
119 }