-
Notifications
You must be signed in to change notification settings - Fork 0
/
keys.clj
99 lines (90 loc) · 3.89 KB
/
keys.clj
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
(ns memento.redis.keys
(:require [taoensso.carmine :as car]
[taoensso.carmine.protocol :as p])
(:import (java.nio ByteBuffer)
(java.security MessageDigest)
(memento.base Segment)))
(def ^MessageDigest sha1-digest (MessageDigest/getInstance "sha1"))
(def ^MessageDigest sha256-digest (MessageDigest/getInstance "sha-256"))
(defn digest [dig-name o]
(.digest
(case dig-name
:sha-256 sha256-digest
:sha1 sha1-digest)
(p/byte-str o)))
(defn wildcard
"Creates a wildcard key from a list key. It will select all keys with additional
elements in the list. It will not select the key itself.
Need to use REAL list, not list*. Metadata on the list is ignored as it screws up wildcarding
Escapes bytes ? * [ \\ from provided key."
[key]
(let [^bytes b-arr (p/byte-str (with-meta key nil))
b-arr-len (alength b-arr)
;; set the list count to ?
_ (aset b-arr 7 (byte 63))
^ByteBuffer bb (.put (ByteBuffer/allocate (* 2 (alength b-arr)))
b-arr 0 8)]
(loop [i 8]
(when (< i b-arr-len)
(let [b (aget b-arr i)]
(case b
;; escape these bytes
(42 63 92 91) (.put bb (byte 92))
nil)
(.put bb b)
(recur (inc i)))))
;; add last * and prepare for reading
(let [output (byte-array (-> bb (.put (byte 42)) .flip .remaining))
_ (.get bb output)]
(p/raw output))))
(defn by-pattern
"Returns a SCAN result sequence, partitioned to 1000 items per batch.
Needs to be called inside car/wcar.
Returns an eduction."
[key]
(let [scan-from-cursor #(car/with-replies (car/scan % "COUNT" 100 "MATCH" key))]
(eduction
(take-while some?)
(mapcat #(% 1))
(partition-all 1000)
(iterate
(fn [[cursor entries]]
(when (and cursor (not= cursor "0"))
(scan-from-cursor cursor)))
(scan-from-cursor "0")))))
(defprotocol KeysGenerator
"Generates keys to be used when working with Redis."
(cache-wildcard-key [this cache-name]
"A wildcard (glob) key that will return all keys used by a particular cache.")
(segment-wildcard-key [this cache-name segment]
"A wildcard (glob) key that will return all keys used by a particular memoized
function. Segment is memento.base.Segment.")
(entry-key [this cache-name segment args-key]
"A concrete key for an entry. Segment is memento.base.Segment.")
(sec-index-id-key [this cache-name id]
"ID for the SET that houses all the keys that get invalidated by id.")
(sec-indexes-key [this]
"ID for the SET that houses all base keys of secondary indexes.")
(base-wildcard-keys [this]
"Returns a coll of wildcard keys that will select all keys of all Memento Redis caches
that use this kind of Keys Generator, used for nuking all the caches."))
(defn default-keys-generator [memento-space-prefix
memento-secondary-index-prefix
anon-key-strat]
(let [segment-id-fn (case anon-key-strat
:stringify #(if (fn? %) (str %) %)
:empty #(if (fn? %) nil %))]
(reify KeysGenerator
(cache-wildcard-key [this cache-name]
(wildcard (list memento-space-prefix cache-name)))
(segment-wildcard-key [this cache-name segment]
(wildcard (list memento-space-prefix cache-name (segment-id-fn (.getId ^Segment segment)))))
(entry-key [this cache-name segment args-key]
(list memento-space-prefix cache-name (segment-id-fn (.getId ^Segment segment)) args-key))
(sec-index-id-key [this cache-name id]
(list memento-secondary-index-prefix cache-name id))
(sec-indexes-key [this]
(list memento-secondary-index-prefix nil))
(base-wildcard-keys [this]
[(wildcard (list memento-space-prefix))
(wildcard (list memento-secondary-index-prefix))]))))