66 */
77
88use std:: collections:: BTreeMap ;
9+ use std:: ops:: Sub ;
910
1011use anyhow:: Context ;
1112use edenfs_error:: EdenFsError ;
@@ -14,6 +15,372 @@ use edenfs_error::Result;
1415use crate :: client:: Client ;
1516use crate :: client:: EdenFsClient ;
1617
18+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
19+ /// EdenFS filesystem counters
20+ /// The exact VFS implementation depends on the platform
21+ pub struct FilesystemTelemetryCounters {
22+ // The number of successful open filesystem operations.
23+ pub syscall_opens : i64 ,
24+ // The number of successful read operations.
25+ pub syscall_reads : i64 ,
26+ // The number of successful readdir operations.
27+ pub syscall_readdirs : i64 ,
28+ // The number of successful write operations.
29+ pub syscall_writes : i64 ,
30+ // The number of successful stat operations.
31+ pub syscall_stats : i64 ,
32+ }
33+
34+ impl Sub for FilesystemTelemetryCounters {
35+ type Output = Self ;
36+
37+ fn sub ( self , rhs : Self ) -> Self :: Output {
38+ Self {
39+ syscall_opens : self . syscall_opens - rhs. syscall_opens ,
40+ syscall_reads : self . syscall_reads - rhs. syscall_reads ,
41+ syscall_readdirs : self . syscall_readdirs - rhs. syscall_readdirs ,
42+ syscall_writes : self . syscall_writes - rhs. syscall_writes ,
43+ syscall_stats : self . syscall_stats - rhs. syscall_stats ,
44+ }
45+ }
46+ }
47+
48+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
49+ pub struct ThriftTelemetryCounters { }
50+
51+ impl Sub for ThriftTelemetryCounters {
52+ type Output = Self ;
53+
54+ fn sub ( self , _rhs : Self ) -> Self :: Output {
55+ Self { }
56+ }
57+ }
58+
59+ /// Remote backends
60+ /// EdenAPI backend counters
61+ /// There are no misses as Mononoke is the source of truth for the data
62+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
63+ pub struct EdenApiBackendTelemetryCounters {
64+ /// The number of file content fetches from the EdenAPI backend
65+ pub edenapi_fetches_blobs : i64 ,
66+ /// The number of tree fetches from the EdenAPI backend
67+ pub edenapi_fetches_trees : i64 ,
68+ /// Total number of http requests performed to the EdenAPI backend combined for files and trees
69+ pub edenapi_requests : i64 ,
70+ }
71+
72+ impl Sub for EdenApiBackendTelemetryCounters {
73+ type Output = Self ;
74+
75+ fn sub ( self , rhs : Self ) -> Self :: Output {
76+ Self {
77+ edenapi_fetches_blobs : self . edenapi_fetches_blobs - rhs. edenapi_fetches_blobs ,
78+ edenapi_fetches_trees : self . edenapi_fetches_trees - rhs. edenapi_fetches_trees ,
79+ edenapi_requests : self . edenapi_requests - rhs. edenapi_requests ,
80+ }
81+ }
82+ }
83+
84+ /// LFS backend counters
85+ /// There are no misses as Mononoke is the source of truth for the data
86+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
87+ pub struct LfsBackendTelemetryCounters {
88+ /// The number of file content fetches from the LFS backend
89+ pub lfs_fetches_blobs : i64 ,
90+ /// The number of tree fetches from the LFS backend
91+ pub lfs_fetches_trees : i64 ,
92+ /// Total number of http requests performed to the LFS backend combined for files and trees
93+ pub lfs_requests : i64 ,
94+ }
95+
96+ impl Sub for LfsBackendTelemetryCounters {
97+ type Output = Self ;
98+
99+ fn sub ( self , rhs : Self ) -> Self :: Output {
100+ Self {
101+ lfs_fetches_blobs : self . lfs_fetches_blobs - rhs. lfs_fetches_blobs ,
102+ lfs_fetches_trees : self . lfs_fetches_trees - rhs. lfs_fetches_trees ,
103+ lfs_requests : self . lfs_requests - rhs. lfs_requests ,
104+ }
105+ }
106+ }
107+
108+ /// CASd backend counters
109+ /// There could be misses as the storage layer is TTL based
110+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
111+ pub struct CASCBackendTelemetryCounters {
112+ /// The number of file content fetches from the CAS backend
113+ pub cas_fetches_blobs : i64 ,
114+ /// The number of file content fetches from the CAS backend that were not found
115+ pub cas_missing_blobs : i64 ,
116+ /// The number of tree fetches from the CAS backend
117+ pub cas_fetches_trees : i64 ,
118+ /// The number of tree fetches from the CAS backend that were not found
119+ pub cas_missing_trees : i64 ,
120+ }
121+
122+ impl Sub for CASCBackendTelemetryCounters {
123+ type Output = Self ;
124+
125+ fn sub ( self , rhs : Self ) -> Self :: Output {
126+ Self {
127+ cas_fetches_blobs : self . cas_fetches_blobs - rhs. cas_fetches_blobs ,
128+ cas_missing_blobs : self . cas_missing_blobs - rhs. cas_missing_blobs ,
129+ cas_fetches_trees : self . cas_fetches_trees - rhs. cas_fetches_trees ,
130+ cas_missing_trees : self . cas_missing_trees - rhs. cas_missing_trees ,
131+ }
132+ }
133+ }
134+
135+ /// Remote backend counters to track the number of fetches from the remote backends
136+ /// typically with much higher latency than the local caches
137+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
138+ pub struct RemoteBackendTelemetryCounters {
139+ pub edenapi_backend : Option < EdenApiBackendTelemetryCounters > ,
140+ pub casc_backend : Option < CASCBackendTelemetryCounters > ,
141+ pub lfs_backend : Option < LfsBackendTelemetryCounters > ,
142+ }
143+
144+ impl Sub for RemoteBackendTelemetryCounters {
145+ type Output = Self ;
146+
147+ fn sub ( self , rhs : Self ) -> Self :: Output {
148+ Self {
149+ edenapi_backend : match ( self . edenapi_backend , rhs. edenapi_backend ) {
150+ ( Some ( lhs) , Some ( rhs) ) => Some ( lhs - rhs) ,
151+ ( lhs, None ) => lhs,
152+ ( None , _) => None ,
153+ } ,
154+ casc_backend : match ( self . casc_backend , rhs. casc_backend ) {
155+ ( Some ( lhs) , Some ( rhs) ) => Some ( lhs - rhs) ,
156+ ( lhs, None ) => lhs,
157+ ( None , _) => None ,
158+ } ,
159+ lfs_backend : match ( self . lfs_backend , rhs. lfs_backend ) {
160+ ( Some ( lhs) , Some ( rhs) ) => Some ( lhs - rhs) ,
161+ ( lhs, None ) => lhs,
162+ ( None , _) => None ,
163+ } ,
164+ }
165+ }
166+ }
167+
168+ /// Local caches (sapling "local" cache is skipped as it serves only a few fetches only for commits made locally)
169+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
170+ pub struct SaplingCacheTelemetryCounters {
171+ // Blobs
172+ pub sapling_cache_blobs_hits : i64 ,
173+ pub sapling_cache_blobs_misses : i64 ,
174+ // Trees
175+ pub sapling_cache_trees_hits : i64 ,
176+ pub sapling_cache_trees_misses : i64 ,
177+ }
178+
179+ impl Sub for SaplingCacheTelemetryCounters {
180+ type Output = Self ;
181+
182+ fn sub ( self , rhs : Self ) -> Self :: Output {
183+ Self {
184+ sapling_cache_blobs_hits : self . sapling_cache_blobs_hits - rhs. sapling_cache_blobs_hits ,
185+ sapling_cache_blobs_misses : self . sapling_cache_blobs_misses
186+ - rhs. sapling_cache_blobs_misses ,
187+ sapling_cache_trees_hits : self . sapling_cache_trees_hits - rhs. sapling_cache_trees_hits ,
188+ sapling_cache_trees_misses : self . sapling_cache_trees_misses
189+ - rhs. sapling_cache_trees_misses ,
190+ }
191+ }
192+ }
193+
194+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
195+ pub struct SaplingLFSCacheTelemetryCounters {
196+ // Blobs
197+ pub sapling_lfs_cache_blobs_hits : i64 ,
198+ pub sapling_lfs_cache_blobs_misses : i64 ,
199+ // Trees
200+ pub sapling_lfs_cache_trees_hits : i64 ,
201+ pub sapling_lfs_cache_trees_misses : i64 ,
202+ }
203+ impl Sub for SaplingLFSCacheTelemetryCounters {
204+ type Output = Self ;
205+
206+ fn sub ( self , rhs : Self ) -> Self :: Output {
207+ Self {
208+ sapling_lfs_cache_blobs_hits : self . sapling_lfs_cache_blobs_hits
209+ - rhs. sapling_lfs_cache_blobs_hits ,
210+ sapling_lfs_cache_blobs_misses : self . sapling_lfs_cache_blobs_misses
211+ - rhs. sapling_lfs_cache_blobs_misses ,
212+ sapling_lfs_cache_trees_hits : self . sapling_lfs_cache_trees_hits
213+ - rhs. sapling_lfs_cache_trees_hits ,
214+ sapling_lfs_cache_trees_misses : self . sapling_lfs_cache_trees_misses
215+ - rhs. sapling_lfs_cache_trees_misses ,
216+ }
217+ }
218+ }
219+
220+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
221+ pub struct CASCLocalCacheTelemetryCounters {
222+ // Blobs
223+ /// Total number of blobs fetched from the CAS local cache layers (on-disk cache and lmdb cache layer)
224+ pub cas_local_cache_blobs_hits : i64 ,
225+ /// Blobs fetched from lmdb cache layer
226+ pub cas_local_cache_blobs_lmdb_hits : i64 ,
227+ pub cas_local_cache_blobs_misses : i64 ,
228+ // Trees
229+ /// Total number of trees fetched from the CAS local cache layers (on-disk cache and lmdb cache layer)
230+ pub cas_local_cache_trees_hits : i64 ,
231+ /// Trees fetched from lmdb cache layer
232+ pub cas_local_cache_trees_lmdb_hits : i64 ,
233+ pub cas_local_cache_trees_misses : i64 ,
234+ }
235+
236+ impl Sub for CASCLocalCacheTelemetryCounters {
237+ type Output = Self ;
238+
239+ fn sub ( self , rhs : Self ) -> Self :: Output {
240+ Self {
241+ cas_local_cache_blobs_hits : self . cas_local_cache_blobs_hits
242+ - rhs. cas_local_cache_blobs_hits ,
243+ cas_local_cache_blobs_lmdb_hits : self . cas_local_cache_blobs_lmdb_hits
244+ - rhs. cas_local_cache_blobs_lmdb_hits ,
245+ cas_local_cache_blobs_misses : self . cas_local_cache_blobs_misses
246+ - rhs. cas_local_cache_blobs_misses ,
247+ cas_local_cache_trees_hits : self . cas_local_cache_trees_hits
248+ - rhs. cas_local_cache_trees_hits ,
249+ cas_local_cache_trees_lmdb_hits : self . cas_local_cache_trees_lmdb_hits
250+ - rhs. cas_local_cache_trees_lmdb_hits ,
251+ cas_local_cache_trees_misses : self . cas_local_cache_trees_misses
252+ - rhs. cas_local_cache_trees_misses ,
253+ }
254+ }
255+ }
256+
257+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
258+ pub struct LocalStoreCacheTelemetryCounters {
259+ // Blobs
260+ pub local_store_cache_blobs_hits : i64 ,
261+ pub local_store_cache_blobs_misses : i64 ,
262+ // Trees
263+ pub local_store_cache_trees_hits : i64 ,
264+ pub local_store_cache_trees_misses : i64 ,
265+ }
266+
267+ impl Sub for LocalStoreCacheTelemetryCounters {
268+ type Output = Self ;
269+
270+ fn sub ( self , rhs : Self ) -> Self :: Output {
271+ Self {
272+ local_store_cache_blobs_hits : self . local_store_cache_blobs_hits
273+ - rhs. local_store_cache_blobs_hits ,
274+ local_store_cache_blobs_misses : self . local_store_cache_blobs_misses
275+ - rhs. local_store_cache_blobs_misses ,
276+ local_store_cache_trees_hits : self . local_store_cache_trees_hits
277+ - rhs. local_store_cache_trees_hits ,
278+ local_store_cache_trees_misses : self . local_store_cache_trees_misses
279+ - rhs. local_store_cache_trees_misses ,
280+ }
281+ }
282+ }
283+
284+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
285+ pub struct InMemoryCacheTelemetryCounters {
286+ // Blobs
287+ pub in_memory_cache_blobs_hits : i64 ,
288+ pub in_memory_cache_blobs_misses : i64 ,
289+ // Trees
290+ pub in_memory_cache_trees_hits : i64 ,
291+ pub in_memory_cache_trees_misses : i64 ,
292+ }
293+
294+ impl Sub for InMemoryCacheTelemetryCounters {
295+ type Output = Self ;
296+
297+ fn sub ( self , rhs : Self ) -> Self :: Output {
298+ Self {
299+ in_memory_cache_blobs_hits : self . in_memory_cache_blobs_hits
300+ - rhs. in_memory_cache_blobs_hits ,
301+ in_memory_cache_blobs_misses : self . in_memory_cache_blobs_misses
302+ - rhs. in_memory_cache_blobs_misses ,
303+ in_memory_cache_trees_hits : self . in_memory_cache_trees_hits
304+ - rhs. in_memory_cache_trees_hits ,
305+ in_memory_cache_trees_misses : self . in_memory_cache_trees_misses
306+ - rhs. in_memory_cache_trees_misses ,
307+ }
308+ }
309+ }
310+
311+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
312+ pub struct LocalCacheTelemetryCounters {
313+ /// Shared Sapling Cache counters (known also as hgcache)
314+ pub sapling_cache : Option < SaplingCacheTelemetryCounters > ,
315+ /// Shared Sapling LFS Cache counters (known also as hgcache)
316+ pub sapling_lfs_cache : Option < SaplingLFSCacheTelemetryCounters > ,
317+ /// CASd local cache counters
318+ pub casc_local_cache : Option < CASCLocalCacheTelemetryCounters > ,
319+ /// Local store cache counters (eden rocksdb cache)
320+ pub local_store_cache : Option < LocalStoreCacheTelemetryCounters > ,
321+ /// In memory (eden) cache counters
322+ pub in_memory_local_cache : Option < InMemoryCacheTelemetryCounters > ,
323+ }
324+
325+ impl Sub for LocalCacheTelemetryCounters {
326+ type Output = Self ;
327+
328+ fn sub ( self , rhs : Self ) -> Self :: Output {
329+ Self {
330+ sapling_cache : match ( self . sapling_cache , rhs. sapling_cache ) {
331+ ( Some ( lhs) , Some ( rhs) ) => Some ( lhs - rhs) ,
332+ ( lhs, None ) => lhs,
333+ ( None , _) => None ,
334+ } ,
335+ sapling_lfs_cache : match ( self . sapling_lfs_cache , rhs. sapling_lfs_cache ) {
336+ ( Some ( lhs) , Some ( rhs) ) => Some ( lhs - rhs) ,
337+ ( lhs, None ) => lhs,
338+ ( None , _) => None ,
339+ } ,
340+ casc_local_cache : match ( self . casc_local_cache , rhs. casc_local_cache ) {
341+ ( Some ( lhs) , Some ( rhs) ) => Some ( lhs - rhs) ,
342+ ( lhs, None ) => lhs,
343+ ( None , _) => None ,
344+ } ,
345+ local_store_cache : match ( self . local_store_cache , rhs. local_store_cache ) {
346+ ( Some ( lhs) , Some ( rhs) ) => Some ( lhs - rhs) ,
347+ ( lhs, None ) => lhs,
348+ ( None , _) => None ,
349+ } ,
350+ in_memory_local_cache : match ( self . in_memory_local_cache , rhs. in_memory_local_cache ) {
351+ ( Some ( lhs) , Some ( rhs) ) => Some ( lhs - rhs) ,
352+ ( lhs, None ) => lhs,
353+ ( None , _) => None ,
354+ } ,
355+ }
356+ }
357+ }
358+
359+ /// EdenFS cummulative counters
360+ /// This is a subset of the counters that are available as part of the EdenFS telemetry
361+ /// Only covers cumulative counters that are incremented on operations during the lifetime of the EdenFS process
362+ /// It is possible to snapshot the counters and compare them to a previous snapshot
363+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
364+ pub struct TelemetryCounters {
365+ pub fs_stats : FilesystemTelemetryCounters ,
366+ pub thrift_stats : ThriftTelemetryCounters ,
367+ pub backend_stats : RemoteBackendTelemetryCounters ,
368+ pub local_cache_stats : LocalCacheTelemetryCounters ,
369+ }
370+
371+ impl Sub for TelemetryCounters {
372+ type Output = Self ;
373+
374+ fn sub ( self , rhs : Self ) -> Self :: Output {
375+ Self {
376+ fs_stats : self . fs_stats - rhs. fs_stats ,
377+ thrift_stats : self . thrift_stats - rhs. thrift_stats ,
378+ backend_stats : self . backend_stats - rhs. backend_stats ,
379+ local_cache_stats : self . local_cache_stats - rhs. local_cache_stats ,
380+ }
381+ }
382+ }
383+
17384impl EdenFsClient {
18385 pub async fn get_regex_counters ( & self , arg_regex : & str ) -> Result < BTreeMap < String , i64 > > {
19386 self . with_thrift ( |thrift| thrift. getRegexCounters ( arg_regex) )
0 commit comments