Skip to content

Commit

Permalink
[WIP] Remove Resource Handle Cache
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderkiel committed Apr 7, 2022
1 parent dca4e44 commit d3869a5
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 80 deletions.
30 changes: 18 additions & 12 deletions docs/performance/fhir-search.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ In this section, FHIR Search for selecting Observation resources with a certain

### Counting

All measurements are done after Blaze is in a steady state with all resource handles to hit in it's resource handle cache in order to cancel out additional seeks necessary to determine the current version of each resource. A resource handle doesn't contain the actual resource content which is not necessary for counting.
All measurements are done after Blaze is in a steady state with its RocksDB block cache filled so that no cache misses occur.

Counting is done using the following `curl` command:

```sh
time curl -s "http://localhost:8080/fhir/Observation?code=http://loinc.org|$CODE&_summary=count"
```

| CPU | RAM (GB) | Heap Mem (GB) | Block Cache (GB) | # Resources | # Observations | Code | # Hits | Time (s) |
|-------------|---------:|--------------:|-----------------:|------------:|---------------:|---------|-------:|---------:|
| E5-2687W v4 | 128 | 4 | 1 | 29 M | 28 M | 17861-6 | 171 k | 0.2 |
| E5-2687W v4 | 128 | 4 | 1 | 29 M | 28 M | 39156-5 | 967 k | 1 |
| E5-2687W v4 | 128 | 4 | 1 | 29 M | 28 M | 29463-7 | 1.3 M | 1.6 |
| E5-2687W v4 | 128 | 30 | 10 | 292 M | 278 M | 17861-6 | 1.7 M | 1.7 |
| E5-2687W v4 | 128 | 30 | 10 | 292 M | 278 M | 39156-5 | 9.7 M | 10 |
| E5-2687W v4 | 128 | 30 | 10 | 292 M | 278 M | 29463-7 | 13 M | 15 |
| CPU | RAM (GB) | Heap Mem (GB) | Block Cache (GB) | # Resources | # Observations | Code | # Hits | Time (s) | Time (µs)/ Hit |
|-------------|---------:|--------------:|-----------------:|------------:|---------------:|---------|-------:|---------:|---------------:|
| E5-2687W v4 | 128 | 4 | 4 | 29 M | 28 M | 17861-6 | 171 k | 0.66 | 3.9 |
| E5-2687W v4 | 128 | 4 | 4 | 29 M | 28 M | 39156-5 | 967 k | 3.2 | 3.3 |
| E5-2687W v4 | 128 | 4 | 4 | 29 M | 28 M | 29463-7 | 1.3 M | 4.4 | 3.4 |
| E5-2687W v4 | 128 | 4 | 24 | 292 M | 278 M | 17861-6 | 1.7 M | 5.9 | 3.5 |
| E5-2687W v4 | 128 | 4 | 24 | 292 M | 278 M | 39156-5 | 9.7 M | 28 | 2.9 |
| E5-2687W v4 | 128 | 4 | 24 | 292 M | 278 M | 29463-7 | 13 M | 37 | 2.8 |

According to the measurements the time needed by Blaze to count resources only depends on the number of hits and equals roughly in **1 second per 1 million hits**.

Expand All @@ -41,9 +41,9 @@ blazectl download --server http://localhost:8080/fhir Observation -q "code=http:

| CPU | RAM (GB) | Heap Mem (GB) | Block Cache (GB) | # Resources | # Observations | Code | # Hits | Time (s) |
|-------------|---------:|--------------:|-----------------:|------------:|---------------:|---------|-------:|---------:|
| E5-2687W v4 | 128 | 4 | 1 | 29 M | 28 M | 17861-6 | 171 k | 4.6 |
| E5-2687W v4 | 128 | 4 | 1 | 29 M | 28 M | 39156-5 | 967 k | 26 |
| E5-2687W v4 | 128 | 4 | 1 | 29 M | 28 M | 29463-7 | 1.3 M | 35 |
| E5-2687W v4 | 128 | 4 | 4 | 29 M | 28 M | 17861-6 | 171 k | 4.9 |
| E5-2687W v4 | 128 | 4 | 4 | 29 M | 28 M | 39156-5 | 967 k | 26 |
| E5-2687W v4 | 128 | 4 | 4 | 29 M | 28 M | 29463-7 | 1.3 M | 37 |
| E5-2687W v4 | 128 | 30 | 10 | 292 M | 278 M | 17861-6 | 1.7 M | 48 |
| E5-2687W v4 | 128 | 30 | 10 | 292 M | 278 M | 39156-5 | 9.7 M | 284 |
| E5-2687W v4 | 128 | 30 | 10 | 292 M | 278 M | 29463-7 | 13 M | 410 |
Expand Down Expand Up @@ -101,6 +101,12 @@ jvm_memory_pool_bytes_used{pool="G1 Old Gen",} 8.325004288E9

Here the value `8.325004288E9` is in bytes and `E9` means GB. So we have 8.3 GB used old generation here which makes out most of the total heap size. So if you had configured Blaze with a maximum heap size of 10 GB, that usage would be much like a healthy upper limit.

#### RocksDB Block Cache

```sh
curl -s http://localhost:8081/metrics | grep blaze_rocksdb_block_cache_index_miss_total | grep '"index"'
```

#### Resource / Resource Handle Cache

The resource cache metrics can be found under keys starting with `blaze_db_cache`. Among others there is the `resource-cache` and the `resource-handle-cache`. The metrics are a bit more difficult to interpret without a Prometheus/Grafana infrastructure, because they are counters starting Blaze startup. So after a longer runtime, one has to calculate relative differences here. But right after the start of Blaze, the numbers are very useful on its own.
Expand Down
13 changes: 9 additions & 4 deletions modules/byte-buffer/src/blaze/byte_buffer.clj
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,15 @@

(defn get-long!
{:inline
(fn [byte-buffer]
`(.getLong ~(vary-meta byte-buffer assoc :tag `ByteBuffer)))}
[byte-buffer]
(.getLong ^ByteBuffer byte-buffer))
(fn
([byte-buffer]
`(.getLong ~(vary-meta byte-buffer assoc :tag `ByteBuffer)))
([byte-buffer index]
`(.getLong ~(vary-meta byte-buffer assoc :tag `ByteBuffer) (int ~index))))}
([byte-buffer]
(.getLong ^ByteBuffer byte-buffer))
([byte-buffer index]
(.getLong ^ByteBuffer byte-buffer (int index))))


(defn copy-into-byte-array!
Expand Down
99 changes: 36 additions & 63 deletions modules/db/src/blaze/db/impl/index/resource_as_of.clj
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
[blaze.db.impl.iterators :as i]
[blaze.db.kv :as kv])
(:import
[com.github.benmanes.caffeine.cache Cache]
[com.google.common.primitives Ints]
[java.util.function Function]))
[blaze.db.impl.index.resource_handle ResourceHandle]
[com.google.common.primitives Ints]))


(set! *warn-on-reflection* true)
Expand Down Expand Up @@ -379,79 +378,53 @@
(i/kvs! raoi (decoder) (start-key tid id start-t))))


(defn- resource-handle** [raoi tb kb vb tid id t]
;; fill target buffer
(bb/clear! tb)
(bb/put-int! tb tid)
(bb/put-byte-string! tb id)
(bb/put-long! tb (codec/descending-long t))
;; flip target buffer to be ready for seek
(bb/flip! tb)
(kv/seek-buffer! raoi tb)
(when (kv/valid? raoi)
;; read key
(bb/clear! kb)
(kv/key! raoi kb)
;; we have to check that we are still on target, because otherwise we
;; would find the next resource
;; focus target buffer on tid and id
(bb/rewind! tb)
(bb/set-limit! tb (unchecked-subtract-int (bb/limit tb) codec/t-size))
;; focus key buffer on tid and id
(bb/set-limit! kb (unchecked-subtract-int (bb/limit kb) codec/t-size))
(when (= tb kb)
;; focus key buffer on t
(let [limit (bb/limit kb)]
(bb/set-position! kb limit)
(bb/set-limit! kb (unchecked-add-int limit codec/t-size)))
;; read value
(bb/clear! vb)
(kv/value! raoi vb)
;; create resource handle
(rh/resource-handle
tid
(codec/id-string id)
(codec/descending-long (bb/get-long! kb))
vb))))


;; For performance reasons, we use that special Key class instead of a a simple
;; triple vector
(deftype Key [^long tid ^Object id ^long t]
Object
(equals [_ x]
(and (instance? Key x)
(= tid (.-tid ^Key x))
(.equals id (.-id ^Key x))
(= t (.-t ^Key x))))
(hashCode [_]
(-> tid
(unchecked-multiply-int 31)
(unchecked-add-int (.hashCode id))
(unchecked-multiply-int 31)
(unchecked-add-int t))))


(defn resource-handle
"Returns a function which can be called with a `tid`, an `id` and an optional
`t` which will lookup the resource handle in `raoi` using `rh-cache` as cache.
The `t` is the default if `t` isn't given at the returned function.
The returned function can't be called concurrently."
[rh-cache raoi t]
[_rh-cache raoi t]
(let [tb (bb/allocate-direct max-key-size)
kb (bb/allocate-direct max-key-size)
vb (bb/allocate-direct value-size)
rh (reify Function
(apply [_ key]
(resource-handle** raoi tb kb vb (.-tid ^Key key)
(.-id ^Key key) (.-t ^Key key))))]
vb (bb/allocate-direct value-size)]
(fn resource-handle
([tid id]
(resource-handle tid id t))
([tid id t]
(.get ^Cache rh-cache (Key. tid id t) rh)))))
;; fill target buffer
(bb/clear! tb)
(bb/put-int! tb tid)
(bb/put-byte-string! tb id)
(bb/put-long! tb (codec/descending-long t))
;; flip target buffer to be ready for seek
(bb/flip! tb)
(kv/seek-buffer! raoi tb)
(when (kv/valid? raoi)
;; read key
(bb/clear! kb)
(kv/key! raoi kb)
;; we have to check that we are still on target, because otherwise we
;; would find the next resource
;; focus target buffer on tid and id
(bb/rewind! tb)
(let [t-start (unchecked-subtract-int (bb/limit tb) codec/t-size)
mismatch (bb/mismatch tb kb)]
(when (or (neg? mismatch) (< t-start mismatch))
;; read value
(bb/clear! vb)
(kv/value! raoi vb)
;; create resource handle
(let [hash (bs/from-byte-buffer vb codec/hash-size)
state (bb/get-long! vb)]
(ResourceHandle.
tid
(codec/id-string id)
(codec/descending-long (bb/get-long! kb t-start))
hash
(rh/state->num-changes state)
(rh/state->op state))))))))))


(defn num-of-instance-changes
Expand Down
1 change: 0 additions & 1 deletion modules/db/src/blaze/db/impl/iterators.clj
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@
(map #(vswap! buf-state read-key! %))))



(defn- key-decoder [decode]
(comp
(key-reader (decode))
Expand Down

0 comments on commit d3869a5

Please sign in to comment.