mirror of
https://github.com/penpot/penpot.git
synced 2025-01-09 00:10:11 -05:00
✨ Improve internal impl of objects-map
This commit is contained in:
parent
fa93e5a1a7
commit
16afa90b9c
1 changed files with 97 additions and 118 deletions
|
@ -34,9 +34,10 @@
|
|||
(declare create)
|
||||
|
||||
(defprotocol IObjectsMap
|
||||
(-initialize! [_])
|
||||
(-compact! [_])
|
||||
(-get-byte-array [_])
|
||||
(load! [_])
|
||||
(modified? [_])
|
||||
(compact! [_])
|
||||
(clone [_])
|
||||
(-get-key-hash [_ key])
|
||||
(-force-modified! [_]))
|
||||
|
||||
|
@ -70,7 +71,7 @@
|
|||
^:unsynchronized-mutable blob
|
||||
^:unsynchronized-mutable header
|
||||
^:unsynchronized-mutable content
|
||||
^:unsynchronized-mutable initialized?
|
||||
^:unsynchronized-mutable loaded?
|
||||
^:unsynchronized-mutable modified?]
|
||||
|
||||
IHashEq
|
||||
|
@ -84,47 +85,54 @@
|
|||
(.hasheq ^IHashEq this))
|
||||
|
||||
IObjectsMap
|
||||
(-initialize! [_]
|
||||
(when-not initialized?
|
||||
;; (l/trace :fn "-initialize!" :blob blob ::l/async false)
|
||||
(let [hsize (.getInt ^ByteBuffer blob 0)
|
||||
header' (.slice ^ByteBuffer blob 4 hsize)
|
||||
content' (.slice ^ByteBuffer blob
|
||||
(int (+ 4 hsize))
|
||||
(int (- (.remaining ^ByteBuffer blob)
|
||||
(+ 4 hsize))))
|
||||
(modified? [_] modified?)
|
||||
|
||||
nitems (long (/ (.remaining ^ByteBuffer header') RECORD-SIZE))
|
||||
positions' (reduce (fn [positions i]
|
||||
(let [hb (.slice ^ByteBuffer header'
|
||||
(int (* i RECORD-SIZE))
|
||||
(int RECORD-SIZE))
|
||||
msb (.getLong ^ByteBuffer hb)
|
||||
lsb (.getLong ^ByteBuffer hb)
|
||||
size (.getInt ^ByteBuffer hb)
|
||||
pos (.getInt ^ByteBuffer hb)
|
||||
key (uuid/custom msb lsb)
|
||||
val [size pos]]
|
||||
(assoc! positions key val)))
|
||||
(transient {})
|
||||
(range nitems))]
|
||||
(set! positions (persistent! positions'))
|
||||
(if *lazy*
|
||||
(set! cache {})
|
||||
(loop [cache' (transient {})
|
||||
entries (seq positions)]
|
||||
(if-let [[key [size pos]] (first entries)]
|
||||
(let [tmp (byte-array (- size 4))]
|
||||
(.get ^ByteBuffer content' (int (+ pos 4)) ^bytes tmp (int 0) (int (- size 4)))
|
||||
;; (l/trace :fn "-initialize!" :step "preload" :key key :size size :pos pos ::l/async false)
|
||||
(recur (assoc! cache' key (fres/decode tmp))
|
||||
(rest entries)))
|
||||
(load! [this]
|
||||
(let [hsize (.getInt ^ByteBuffer blob 0)
|
||||
header' (.slice ^ByteBuffer blob 4 hsize)
|
||||
content' (.slice ^ByteBuffer blob
|
||||
(int (+ 4 hsize))
|
||||
(int (- (.remaining ^ByteBuffer blob)
|
||||
(+ 4 hsize))))
|
||||
|
||||
(set! cache (persistent! cache')))))
|
||||
nitems (long (/ (.remaining ^ByteBuffer header') RECORD-SIZE))
|
||||
positions' (reduce (fn [positions i]
|
||||
(let [hb (.slice ^ByteBuffer header'
|
||||
(int (* i RECORD-SIZE))
|
||||
(int RECORD-SIZE))
|
||||
msb (.getLong ^ByteBuffer hb)
|
||||
lsb (.getLong ^ByteBuffer hb)
|
||||
size (.getInt ^ByteBuffer hb)
|
||||
pos (.getInt ^ByteBuffer hb)
|
||||
key (uuid/custom msb lsb)
|
||||
val [size pos]]
|
||||
(assoc! positions key val)))
|
||||
(transient {})
|
||||
(range nitems))]
|
||||
(set! positions (persistent! positions'))
|
||||
(if *lazy*
|
||||
(set! cache {})
|
||||
(loop [cache' (transient {})
|
||||
entries (seq positions)]
|
||||
(if-let [[key [size pos]] (first entries)]
|
||||
(let [tmp (byte-array (- size 4))]
|
||||
(.get ^ByteBuffer content' (int (+ pos 4)) ^bytes tmp (int 0) (int (- size 4)))
|
||||
(recur (assoc! cache' key (fres/decode tmp))
|
||||
(rest entries)))
|
||||
|
||||
(set! header header')
|
||||
(set! content content')
|
||||
(set! initialized? true))))
|
||||
(set! cache (persistent! cache')))))
|
||||
|
||||
(set! header header')
|
||||
(set! content content')
|
||||
(set! loaded? true))
|
||||
this)
|
||||
|
||||
(-get-key-hash [this key]
|
||||
(when-not loaded? (load! this))
|
||||
(if (contains? cache key)
|
||||
(c/hash (get cache key))
|
||||
(let [[_ pos] (get positions key)]
|
||||
(.getInt ^ByteBuffer content (int pos)))))
|
||||
|
||||
(-force-modified! [this]
|
||||
(set! modified? true)
|
||||
|
@ -133,7 +141,7 @@
|
|||
(set! positions (assoc positions key nil))
|
||||
(set! cache (assoc cache key val)))))
|
||||
|
||||
(-compact! [_]
|
||||
(compact! [this]
|
||||
(when modified?
|
||||
(let [[total-items total-size new-items new-hashes]
|
||||
(loop [entries (seq positions)
|
||||
|
@ -181,8 +189,6 @@
|
|||
hval (get new-hashes key)
|
||||
size (+ (alength ^bytes bval) 4)]
|
||||
|
||||
;; (l/trace :fn "-compact!" :cache "miss" :key key :size size :pos position ::l/async false)
|
||||
|
||||
(.putInt ^ByteBuffer rbuf (int size))
|
||||
(.putInt ^ByteBuffer rbuf (int position))
|
||||
(.rewind ^ByteBuffer rbuf)
|
||||
|
@ -199,7 +205,6 @@
|
|||
(.putInt ^ByteBuffer rbuf (int position))
|
||||
(.rewind ^ByteBuffer rbuf)
|
||||
|
||||
;; (l/trace :fn "-compact!" :cache "hit" :key key :size size :pos position ::l/async false)
|
||||
(.put ^ByteBuffer header' ^ByteBuffer rbuf)
|
||||
(.put ^ByteBuffer content' ^ByteBuffer cbuf)
|
||||
(recur (long (+ position size))
|
||||
|
@ -212,112 +217,82 @@
|
|||
(.rewind ^ByteBuffer content')
|
||||
(.rewind ^ByteBuffer blob')
|
||||
|
||||
;; (l/trace :fn "-compact!" :step "end" ::l/async false)
|
||||
|
||||
(set! positions positions')
|
||||
(set! modified? false)
|
||||
(set! blob blob')
|
||||
(set! header header')
|
||||
(set! content content'))))
|
||||
(set! content content')))
|
||||
this)
|
||||
|
||||
(-get-byte-array [this]
|
||||
;; (l/trace :fn "-get-byte-array" :this (.getHashCode this) :blob blob ::l/async false)
|
||||
(-compact! this)
|
||||
(.array ^ByteBuffer blob))
|
||||
|
||||
(-get-key-hash [this key]
|
||||
(-initialize! this)
|
||||
(if (contains? cache key)
|
||||
(c/hash (get cache key))
|
||||
(let [[_ pos] (get positions key)]
|
||||
(.getInt ^ByteBuffer content (int pos)))))
|
||||
(clone [_]
|
||||
(if loaded?
|
||||
(ObjectsMap. metadata hash positions cache blob header content loaded? modified?)
|
||||
(ObjectsMap. metadata nil nil nil blob nil nil false false)))
|
||||
|
||||
clojure.lang.IDeref
|
||||
(deref [_]
|
||||
{:positions positions
|
||||
:cache cache
|
||||
:blob blob
|
||||
:header header
|
||||
:content content
|
||||
:initialized? initialized?
|
||||
:modified? modified?})
|
||||
|
||||
Cloneable
|
||||
(clone [_]
|
||||
(if initialized?
|
||||
(ObjectsMap. metadata hash positions cache blob header content initialized? modified?)
|
||||
(ObjectsMap. metadata nil nil nil blob nil nil false false)))
|
||||
(deref [this]
|
||||
(compact! this)
|
||||
(.array ^ByteBuffer blob))
|
||||
|
||||
IObj
|
||||
(meta [_] metadata)
|
||||
(withMeta [this meta]
|
||||
(set! metadata meta)
|
||||
this)
|
||||
(withMeta [_ metadata]
|
||||
(ObjectsMap. metadata hash positions cache blob header content loaded? modified?))
|
||||
|
||||
Seqable
|
||||
(seq [this]
|
||||
(-initialize! this)
|
||||
(when-not loaded? (load! this))
|
||||
(RT/chunkIteratorSeq (.iterator ^Iterable this)))
|
||||
|
||||
IPersistentCollection
|
||||
(equiv [_ _]
|
||||
(throw (UnsupportedOperationException. "not implemented")))
|
||||
(equiv [this other]
|
||||
(identical? this other))
|
||||
|
||||
IPersistentMap
|
||||
(cons [this o]
|
||||
(-initialize! this)
|
||||
(when-not loaded? (load! this))
|
||||
(if (map-entry? o)
|
||||
(do
|
||||
;; (l/trace :fn "cons" :key (key o))
|
||||
(assoc this (key o) (val o)))
|
||||
(assoc this (key o) (val o))
|
||||
(if (vector? o)
|
||||
(do
|
||||
;; (l/trace :fn "cons" :key (nth o 0))
|
||||
(assoc this (nth o 0) (nth o 1)))
|
||||
(assoc this (nth o 0) (nth o 1))
|
||||
(throw (UnsupportedOperationException. "invalid arguments to cons")))))
|
||||
|
||||
(empty [_]
|
||||
(create))
|
||||
|
||||
(containsKey [this key]
|
||||
(-initialize! this)
|
||||
(when-not loaded? (load! this))
|
||||
(contains? positions key))
|
||||
|
||||
(entryAt [this key]
|
||||
(-initialize! this)
|
||||
(when-not loaded? (load! this))
|
||||
(ObjectsMapEntry. this key))
|
||||
|
||||
(valAt [this key]
|
||||
(-initialize! this)
|
||||
;; (strace/print-stack-trace (ex-info "" {}))
|
||||
(when-not loaded? (load! this))
|
||||
(if (contains? cache key)
|
||||
(do
|
||||
;; (l/trace :fn "valAt" :key key :cache "hit")
|
||||
(get cache key))
|
||||
(do
|
||||
(if (contains? positions key)
|
||||
(let [[size pos] (get positions key)
|
||||
tmp (byte-array (- size 4))]
|
||||
(.get ^ByteBuffer content (int (+ pos 4)) ^bytes tmp (int 0) (int (- size 4)))
|
||||
;; (l/trace :fn "valAt" :key key :cache "miss" :size size :pos pos)
|
||||
|
||||
(let [val (fres/decode tmp)]
|
||||
(set! cache (assoc cache key val))
|
||||
val))
|
||||
(do
|
||||
;; (l/trace :fn "valAt" :key key :cache "miss" :val nil)
|
||||
(set! cache (assoc cache key nil))
|
||||
nil)))))
|
||||
(get cache key)
|
||||
(if (contains? positions key)
|
||||
(let [[size pos] (get positions key)
|
||||
tmp (byte-array (- size 4))]
|
||||
(.get ^ByteBuffer content (int (+ pos 4)) ^bytes tmp (int 0) (int (- size 4)))
|
||||
(let [val (fres/decode tmp)]
|
||||
(set! cache (assoc cache key val))
|
||||
val))
|
||||
(do
|
||||
(set! cache (assoc cache key nil))
|
||||
nil))))
|
||||
|
||||
(valAt [this key not-found]
|
||||
(-initialize! this)
|
||||
(when-not loaded? (load! this))
|
||||
(if (.containsKey ^IPersistentMap positions key)
|
||||
(.valAt this key)
|
||||
not-found))
|
||||
|
||||
(assoc [this key val]
|
||||
(-initialize! this)
|
||||
;; (l/trace :fn "assoc" :key key ::l/async false)
|
||||
(when-not loaded? (load! this))
|
||||
(when-not (instance? UUID key)
|
||||
(throw (IllegalArgumentException. "key should be an instance of UUID")))
|
||||
(ObjectsMap. metadata
|
||||
nil
|
||||
(assoc positions key nil)
|
||||
|
@ -325,15 +300,14 @@
|
|||
blob
|
||||
header
|
||||
content
|
||||
initialized?
|
||||
loaded?
|
||||
true))
|
||||
|
||||
(assocEx [_ _ _]
|
||||
(throw (UnsupportedOperationException. "method not implemented")))
|
||||
|
||||
(without [this key]
|
||||
(-initialize! this)
|
||||
;; (l/trace :fn "without" :key key ::l/async false)
|
||||
(when-not loaded? (load! this))
|
||||
(ObjectsMap. metadata
|
||||
nil
|
||||
(dissoc positions key)
|
||||
|
@ -341,16 +315,17 @@
|
|||
blob
|
||||
header
|
||||
content
|
||||
initialized?
|
||||
loaded?
|
||||
true))
|
||||
|
||||
Counted
|
||||
(count [_]
|
||||
(count [this]
|
||||
(when-not loaded? (load! this))
|
||||
(count positions))
|
||||
|
||||
Iterable
|
||||
(iterator [this]
|
||||
(-initialize! this)
|
||||
(when-not loaded? (load! this))
|
||||
(ObjectsMapIterator. (.iterator ^Iterable positions) this))
|
||||
)
|
||||
|
||||
|
@ -376,12 +351,16 @@
|
|||
objects
|
||||
(into (create) objects)))
|
||||
|
||||
(defn objects-map?
|
||||
[o]
|
||||
(instance? ObjectsMap o))
|
||||
|
||||
(fres/add-handlers!
|
||||
{:name "penpot/experimental/objects-map"
|
||||
:class ObjectsMap
|
||||
:wfn (fn [n w o]
|
||||
(fres/write-tag! w n)
|
||||
(fres/write-bytes! w (-get-byte-array o)))
|
||||
(fres/write-bytes! w (deref o)))
|
||||
:rfn (fn [r]
|
||||
(-> r fres/read-object! create))})
|
||||
|
||||
|
|
Loading…
Reference in a new issue