1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! Whether the lookups happening on this thread are a client reading a key.
//!
//! `INFO stats` carries two numbers most dashboards watching a server are built
//! on. `keyspace_hits` is the reads that found what they went looking for and
//! `keyspace_misses` is the reads that did not, and the hit rate everyone quotes
//! is the first over the sum of the two. What makes the pair worth anything is
//! the word read. A `SET` landing on a name nobody was using is not a cache
//! miss, and neither is the `RPUSH` that makes a list, so a count of every
//! lookup the server does would be a ratio that means nothing.
//!
//! Nothing under here knows which kind it is looking at.
//! [`super::keyspace::Keyspace`] has one set of lookups and both kinds of
//! command come through them: `GET` and `APPEND` ask the map for the same key in
//! the same way, and what tells them apart is upstairs in the command table.
//!
//! # Why a thread local
//!
//! Because the alternative is an argument on every lookup, and the lookups are
//! reached through a few hundred typed methods rather than called directly.
//! Threading a flag down through `Keyspace::get` and `Keyspace::sadd` and all the
//! rest of them, so that the funnel underneath can add one to a counter, would
//! be a parameter on the whole API for the sake of a statistic.
//!
//! So the layer that does know says it once on the thread it is about to run the
//! command on, the same way [`super::news`] installs its hook, and the funnels
//! read a flag. That is a thread local read and a test on a path that has
//! already hashed a key and walked a bucket for it.
//!
//! # Why it is a setting and not a count
//!
//! The counters themselves sit on the keyspace the lookup went to, beside
//! `expired_keys` and for the same reason: the stripe is already held and the
//! line is already in this core's cache, so the count is an add to a field, and
//! a shared counter would be a line every thread on the server has to take
//! ownership of to write to.
use Cell;
thread_local!
/// Count the lookups on this thread as a client's reads, or stop counting them,
/// until the answer is dropped.
///
/// The setting that was there comes back at the end rather than the one the
/// thread started on, so a command running inside another one leaves the outer
/// one where it was. `EXEC` and `EVAL` are both of those: the commands inside
/// them arm this each in turn, and what is wrapped around them is a write in one
/// case and a read in the other, neither of which is what the commands inside
/// should be counted as.
/// Stop counting until the answer is dropped, for a lookup that is not one of
/// the command's own.
///
/// A real server counts in `lookupKey` and reaches it once per key it was sent,
/// so what it counts is the command's key list. This one reaches its own lookups
/// as many times as its shape needs: `ZRANGE` asks for the window and then walks
/// it, `GEOSEARCH` asks whether the key is there, then where the centre member
/// is, then reads it, and a command that reads a key and then writes it looks it
/// up on the way to both. Redis's answer to the second half of that is the
/// `LOOKUP_WRITE` flag, which turns off the counters and the miss notification
/// together, and it has no need of an answer to the first half.
///
/// So this is that flag and the rest of it: the lookups it covers are either the
/// same key over again or a key on the way to being written, and neither is
/// something a hit rate should have in it. It goes after the lookup that does
/// count, so what is inside it is everything that follows.
/// What [`reading`] hands back, which puts the thread's setting back when it
/// goes.
;
/// Whether a lookup happening now is part of a client's read.
pub