-
-
Notifications
You must be signed in to change notification settings - Fork 149
/
db.clj
115 lines (94 loc) · 3.85 KB
/
db.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
(ns clojure-lsp.db
(:require
[clojure-lsp.config :as config]
[clojure-lsp.logger :as logger]
[clojure-lsp.shared :as shared]
[clojure.java.io :as io]
[cognitect.transit :as transit])
(:import
[java.io OutputStream]))
(set! *warn-on-reflection* true)
(def ^:private db-logger-tag "[DB]")
(def initial-db {:documents {}
:dep-graph {}})
(defonce db* (atom initial-db))
(def version 12)
(defn ^:private sqlite-db-file [project-root]
(io/file (str project-root) ".lsp" ".cache" "sqlite.db"))
(defn ^:private datalevin-db-files [db]
(let [cache-dir ^java.io.File (config/local-cache-dir db)]
[(io/file cache-dir "data.mdb")
(io/file cache-dir "lock.mdb")]))
(defn ^:private transit-local-db-file [db]
(io/file (config/local-cache-dir db) "db.transit.json"))
(defn ^:private transit-global-db-file []
(io/file (config/global-cache-dir) "db.transit.json"))
(defn ^:private remove-old-sqlite-db-file! [project-root-path]
(let [old-db-file (sqlite-db-file project-root-path)]
(when (shared/file-exists? old-db-file)
(io/delete-file old-db-file true))))
(defn ^:private remove-old-datalevin-db-file! [db]
(->> (datalevin-db-files db)
(filter shared/file-exists?)
(mapv #(io/delete-file % true))))
(defn db-exists? [db]
(shared/file-exists? (transit-local-db-file db)))
(defn remove-db! [db]
(io/delete-file (transit-local-db-file db)))
(defn ^:private no-flush-output-stream [^OutputStream os]
(proxy [java.io.BufferedOutputStream] [os]
(flush [])
(close []
(let [^java.io.BufferedOutputStream this this]
(proxy-super flush)
(proxy-super close)))))
(defn ^:private upsert-cache! [cache cache-file]
(try
(shared/logging-time
"Manual GC before upsert db took %s"
;; Reduce a little bit Out of memory exceptions when writing the cache for huge caches.
(System/gc))
(shared/logging-time
(str db-logger-tag " Upserting transit analysis to " cache-file " cache took %s")
(io/make-parents cache-file)
;; https://github.com/cognitect/transit-clj/issues/43
(with-open [os ^OutputStream (no-flush-output-stream (io/output-stream cache-file))]
(let [writer (transit/writer os :json)]
(transit/write writer cache))))
(catch Throwable e
(logger/error db-logger-tag "Could not upsert db cache" e))))
(defn ^:private read-cache [cache-file]
(try
(shared/logging-time
(str db-logger-tag " Reading transit analysis cache from " cache-file " db took %s")
(if (shared/file-exists? cache-file)
(let [cache (with-open [is (io/input-stream cache-file)]
(transit/read (transit/reader is :json)))]
(when (= version (:version cache))
cache))
(logger/error db-logger-tag "No cache DB file found")))
(catch Throwable e
(logger/error db-logger-tag "Could not load global cache from DB" e))))
(defn upsert-local-cache! [{:keys [project-root] :as project-cache} db]
(remove-old-sqlite-db-file! project-root)
(remove-old-datalevin-db-file! db)
(upsert-cache! project-cache (transit-local-db-file db)))
(defn read-local-cache [project-root db]
(let [project-analysis (read-cache (transit-local-db-file db))]
(when (= (str project-root) (:project-root project-analysis))
project-analysis)))
(defn read-and-update-cache! [db db-change-fn]
(-> (shared/uri->path (:project-root-uri db))
(read-local-cache db)
(db-change-fn)
(upsert-local-cache! db)))
(defn ^:private upsert-global-cache! [global-cache]
(upsert-cache! global-cache (transit-global-db-file)))
(defn read-global-cache []
(let [global-cache (read-cache (transit-global-db-file))]
(when (= version (:version global-cache))
global-cache)))
(defn read-and-update-global-cache! [db-change-fn]
(-> (read-global-cache)
(db-change-fn)
(upsert-global-cache!)))