Skip to content

Commit 5bd4e3b

Browse files
committed
lesson #17
1 parent fbda206 commit 5bd4e3b

File tree

5 files changed

+433
-12
lines changed

5 files changed

+433
-12
lines changed

Diff for: mini-redis/src/mini_redis/core.clj

+67-12
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
[clojure.string :as str])
55
(:import
66
[java.io BufferedReader Writer]
7-
[java.net ServerSocket])
7+
[java.net ServerSocket]
8+
[java.util.concurrent Executors ScheduledExecutorService TimeUnit])
89
(:gen-class))
910

1011

@@ -13,6 +14,52 @@
1314
(atom {}))
1415

1516

17+
(def keys-to-expire
18+
(atom []))
19+
20+
21+
(defn expire-key [key]
22+
(fn []
23+
(swap! database assoc key nil)
24+
(swap! keys-to-expire
25+
(fn [expire-keys]
26+
(remove #(= (second %) key) expire-keys)))))
27+
28+
29+
(defn set-key-to-expire [key timestamp]
30+
(swap! keys-to-expire
31+
(fn [expire-keys]
32+
(->> (conj expire-keys [timestamp key])
33+
(sort-by first)
34+
(vec)))))
35+
36+
37+
(comment
38+
@keys-to-expire
39+
(set-key-to-expire "name" 123123123)
40+
(expire-key "name"))
41+
42+
43+
(def ^ScheduledExecutorService cleanup-pool
44+
(Executors/newScheduledThreadPool 10))
45+
46+
47+
(defn schedule-cleanup-task []
48+
(let [current-time (System/currentTimeMillis)
49+
five-seconds-later (+ current-time 5000)
50+
keys-to-schedule (->> @keys-to-expire
51+
(take-while #(< (first %) five-seconds-later)))]
52+
(doseq [[timestamp key] keys-to-schedule]
53+
(.schedule cleanup-pool
54+
^Runnable (expire-key key)
55+
^Long (- timestamp current-time)
56+
TimeUnit/MILLISECONDS))))
57+
58+
59+
(defn start-cleanup-worker []
60+
(.scheduleAtFixedRate cleanup-pool schedule-cleanup-task 0 5 TimeUnit/SECONDS))
61+
62+
1663

1764
;; обрабатываем команды от клиентов
1865
(defmulti handle-command
@@ -36,19 +83,23 @@
3683
(swap! database assoc key val)
3784

3885
(when (and opt (= (.toUpperCase opt) "PX"))
39-
(let [timeout (Integer/parseInt optarg)]
40-
(future
41-
(Thread/sleep timeout)
42-
(swap! database dissoc key))))
86+
(let [delay (Integer/parseInt optarg)
87+
current-time (System/currentTimeMillis)
88+
timestamp (+ current-time delay)]
89+
(if (< timestamp (+ current-time 5000))
90+
(.schedule cleanup-pool ^Runnable (expire-key key) delay TimeUnit/MILLISECONDS)
91+
(set-key-to-expire key timestamp))))
92+
4393
;; ответ клиенту
4494
"OK")
4595

4696

4797
(defmethod handle-command :get
4898
[[_ [key-len key]]]
49-
(if-some [entry (find @database key)]
50-
(val entry)
51-
"(nil)"))
99+
(let [entry (find @database key)]
100+
(if (some? (val entry))
101+
(val entry)
102+
"(nil)")))
52103

53104

54105
;; needed for redis-cli
@@ -129,7 +180,7 @@
129180
(doseq [msg-in (repeatedly #(read-message reader))
130181
:while (not (empty? msg-in))
131182
:let [msg-out (handler msg-in)]]
132-
(println "msg-in" msg-in "msg-out" msg-out "\n")
183+
(println "msg-in" msg-in)
133184
;; отправляем ответ
134185
(send-message writer msg-out)))))
135186

@@ -154,19 +205,22 @@
154205

155206

156207
;; graceful shutdown
157-
(defn shutdown-hook [server]
208+
(defn shutdown-hook [server worker]
158209
(.addShutdownHook (Runtime/getRuntime)
159210
(Thread. ^Runnable
160211
(fn []
161212
(.close server)
213+
(future-cancel worker)
214+
(.shutdown cleanup-pool)
162215
(shutdown-agents)))))
163216

164217

165218
;; точка входа
166219
(defn -main
167220
[& args]
168-
(let [server (run-server 6379 handle-message)]
169-
(shutdown-hook server)
221+
(let [server (run-server 6379 handle-message)
222+
worker (start-cleanup-worker)]
223+
(shutdown-hook server worker)
170224
server))
171225

172226

@@ -176,6 +230,7 @@
176230
(-main))
177231

178232
@database
233+
@keys-to-expire
179234

180235
(.close server)
181236
nil)

Diff for: otus-17/README.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
## Clojure Developer. Урок 17
2+
3+
Полезные ссылки
4+
5+
- https://clojure.org/news/2012/05/15/anatomy-of-reducer
6+
- https://clojuredatascience.com/posts/2015-09-12-parallel-folds-reducers-tesser-linear-regression.html
7+
- https://github.com/clj-commons/claypoole
8+
9+
Для работы с виртуальными потоками установить JVM флаг `--enable-preview`

Diff for: otus-17/project.clj

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(defproject otus-17 "0.1.0-SNAPSHOT"
2+
:dependencies [[org.clojure/clojure "1.11.1"]]
3+
:repl-options {:init-ns otus-17.core})

0 commit comments

Comments
 (0)