Optimizations for statsclient
[govpp.git] / adapter / statsclient / statseg.go
1 package statsclient
2
3 import (
4         "sync/atomic"
5         "time"
6         "unsafe"
7 )
8
9 var (
10         MaxWaitInProgress    = time.Millisecond * 100
11         CheckDelayInProgress = time.Microsecond * 10
12 )
13
14 type sharedHeaderBase struct {
15         epoch           int64
16         inProgress      int64
17         directoryOffset int64
18         errorOffset     int64
19         statsOffset     int64
20 }
21
22 type statSegSharedHeader struct {
23         version uint64
24         sharedHeaderBase
25 }
26
27 func (h *statSegSharedHeader) legacyVersion() bool {
28         // older VPP (<=19.04) did not have version in stat segment header
29         // we try to provide fallback support by skipping it in header
30         if h.version > maxVersion && h.inProgress > 1 && h.epoch == 0 {
31                 return true
32         }
33         return false
34 }
35
36 func statSegHeader(b []byte) (header statSegSharedHeader) {
37         h := (*statSegSharedHeader)(unsafe.Pointer(&b[0]))
38         header.version = atomic.LoadUint64(&h.version)
39         header.epoch = atomic.LoadInt64(&h.epoch)
40         header.inProgress = atomic.LoadInt64(&h.inProgress)
41         header.directoryOffset = atomic.LoadInt64(&h.directoryOffset)
42         header.errorOffset = atomic.LoadInt64(&h.errorOffset)
43         header.statsOffset = atomic.LoadInt64(&h.statsOffset)
44         return
45 }
46
47 func statSegHeaderLegacy(b []byte) (header statSegSharedHeader) {
48         h := (*sharedHeaderBase)(unsafe.Pointer(&b[0]))
49         header.version = 0
50         header.epoch = atomic.LoadInt64(&h.epoch)
51         header.inProgress = atomic.LoadInt64(&h.inProgress)
52         header.directoryOffset = atomic.LoadInt64(&h.directoryOffset)
53         header.errorOffset = atomic.LoadInt64(&h.errorOffset)
54         header.statsOffset = atomic.LoadInt64(&h.statsOffset)
55         return
56 }
57
58 type statSegAccess struct {
59         epoch int64
60 }
61
62 func (c *statSegment) accessStart() statSegAccess {
63         t := time.Now()
64
65         epoch, inprog := c.getEpoch()
66         for inprog {
67                 if time.Since(t) > MaxWaitInProgress {
68                         return statSegAccess{}
69                 } else {
70                         time.Sleep(CheckDelayInProgress)
71                 }
72                 epoch, inprog = c.getEpoch()
73         }
74         return statSegAccess{
75                 epoch: epoch,
76         }
77 }
78
79 func (c *statSegment) accessEnd(acc *statSegAccess) bool {
80         epoch, inprog := c.getEpoch()
81         if acc.epoch != epoch || inprog {
82                 return false
83         }
84         return true
85 }
86
87 type vecHeader struct {
88         length     uint64
89         vectorData [0]uint8
90 }
91
92 func vectorLen(v unsafe.Pointer) uint64 {
93         vec := *(*vecHeader)(unsafe.Pointer(uintptr(v) - unsafe.Sizeof(uintptr(0))))
94         return vec.length
95 }
96
97 //go:nosplit
98 func statSegPointer(p unsafe.Pointer, offset uintptr) unsafe.Pointer {
99         return unsafe.Pointer(uintptr(p) + offset)
100 }