Skip to content

Commit

Permalink
Refactoring stats and some cleanup/debugging helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
dspearson committed Jun 4, 2023
1 parent 7fe5faf commit 822e557
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 91 deletions.
15 changes: 15 additions & 0 deletions src/phlegyas/buffers.clj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
[^java.nio.ByteBuffer buffer]
(.getShort buffer))

(defn get-size
"Read a short from the byte buffer."
[^java.nio.ByteBuffer buffer]
(.getShort buffer)
(.getShort buffer))

(defn get-int
"Read an integer from the byte buffer."
[^java.nio.ByteBuffer buffer]
Expand Down Expand Up @@ -71,6 +77,15 @@
(.putShort buffer (ushort->short x))
data))

(defn put-size
"Wrap a stat size in a byte-array."
[x]
(let [data (byte-array 4)
^java.nio.ByteBuffer buffer (wrap-buffer data)]
(.putShort buffer (ushort->short (+ 2 x)))
(.putShort buffer (ushort->short x))
data))

(defn put-int
"Wrap an int in a byte-array."
[x]
Expand Down
28 changes: 18 additions & 10 deletions src/phlegyas/frames.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
(:require
[clojure.core.async :refer [thread]]
[manifold.stream :as s]
[taoensso.timbre :as timbre
:refer [info debug error]]
[phlegyas.types
:refer [frame-byte
frame-layouts
Expand Down Expand Up @@ -30,26 +32,31 @@
(let [^java.nio.ByteBuffer frame (wrap-buffer packet)
_ (frame-length frame)
ftype (frame-type frame)
layout (get frame-layouts ftype)]
(into {:frame ftype} (for [field layout] {field ((get get-operation field) frame)}))))
layout (get frame-layouts ftype)
frame (into {:frame ftype} (map (fn [field] {field ((field get-operation) frame)}) layout))]
(debug "Disassembled packet" frame)
frame))

(defn assemble
"Takes in a frame and frame type, calculates the final size of the frame
by adding 5, 4 bytes for the size and 1 byte for the type, looking up `type-bytes`
from the `phlegyas.types` namespace, and adding the size and type to the sequence."
[frame ftype]
(let [frame-size (+ 5 (apply + (map count frame)))
type-bytes (get frame-byte ftype)]
(cons ((:fsize put-operation) frame-size) (cons ((:ftype put-operation) type-bytes) frame))))
type-bytes (get frame-byte ftype)
fsize-op ((:fsize put-operation) frame-size)
ftype-op ((:ftype put-operation) type-bytes)]
(into [fsize-op ftype-op] frame)))

(defn assemble-packet
"Takes in a map representing a frame (see `frame-layouts` in the `phlegyas.types` namespace, and
intro(9P) manual), and encodes it."
[frame]
(let [ftype (:frame frame)
layout (get frame-layouts ftype)]
(println "Frame to assemble:" frame)
(-> (for [typ layout] ((get put-operation typ) (get frame typ))) flatten (assemble ftype) pack)))
layout (get frame-layouts ftype)
packet (-> (map #((% put-operation) (% frame)) layout) flatten (assemble ftype) pack)]
(debug "Assembled packet" (into [] packet))
packet))

(defn dispatch-frame
"Cuts frames along their boundaries, returning any partially assembled packets back to
Expand All @@ -58,11 +65,12 @@
(loop [x packet]
(if (< (count x) 4)
(vec x)
(let [l (-> (subvec x 0 4) byte-array ^java.nio.ByteBuffer wrap-buffer frame-length)]
(let [header (subvec x 0 4)
l (-> header byte-array ^java.nio.ByteBuffer wrap-buffer frame-length)]
(if (< (count x) l)
(vec x)
(do
(s/put! out (-> x (subvec 0 l) byte-array disassemble-packet))
(let [frame (subvec x 0 l)]
(s/put! out (-> frame byte-array disassemble-packet))
(recur (vec (subvec x l)))))))))

(defn frame-assembler
Expand Down
16 changes: 4 additions & 12 deletions src/phlegyas/sqlitefs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
[system fs-name]
(jdbc/with-transaction [tx (:phlegyas/database @system)]
(let [fs (db/get-filesystem tx {:name fs-name})
root-node (db/get-node tx {:path (:rnode fs)})]
root-node (db/get-node tx {:qid-path (:rnode fs)})]
(assoc fs :root root-node))))

(defn add-directory
Expand Down Expand Up @@ -124,23 +124,15 @@

:else
(let [stat (first paths-remaining)
data (for [typ layout]
((get put-operation typ) (get stat typ)))]
data (map #((% put-operation) (% stat)) layout)]
(recur (conj accum data)
(:qid-path stat)
(+ data-size (count data))
(rest paths-remaining)))))))

;; (defn insert-block
;; Insert a block into the database"
;; [system block]
;; (jdbc/with-transaction [tx (:phlegyas/database @system)]
;; (db/insert-block tx block))

(defn calculate-block-info
"Given an offset and a block size, calculate the block index and the
position in the block."
[offset block-size]
(let [block-index (quot offset block-size)
position-in-block (mod offset block-size)]
{:block-index block-index, :position-in-block position-in-block}))
{:block-index (quot offset block-size)
:position-in-block (mod offset block-size)})
4 changes: 2 additions & 2 deletions src/phlegyas/state.clj
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@
(add-mapping frame-newfid fs-name path)))
:reply {:nwqids []}})
(let [wname-paths (walk-path fs path frame-wnames)
qids (for [p wname-paths] (stat->qid (path->stat fs p)))]
qids (map #(stat->qid (path->stat fs %)) wname-paths)]
(if (< (count wname-paths) (count frame-wnames))
(state! {:reply {:nwqids qids}})
(state! {:update (fn [x] (-> x
Expand Down Expand Up @@ -527,7 +527,7 @@
(state! {}))

;; this looks up frame types, and resolves functions for handling them in the current namespace.
(def state-handlers ((fn [] (into {} (for [[k v] frame-byte] [k (-> k name symbol resolve)])))))
(def state-handlers ((fn [] (into {} (map (fn [[k _]] [k (-> k name symbol resolve)]) frame-byte)))))

(defn state-handler
"An example state handler. Takes in a `frame`, the `state` atom, and an outport.
Expand Down
8 changes: 4 additions & 4 deletions src/phlegyas/types.clj
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,15 @@
:Rremove [:tag]

:Tstat [:tag :fid]
:Rstat [:tag :size :size :type :dev :qid-type :qid-vers :qid-path :mode :atime :mtime :length :name :uid :gid :muid]
:Rstat [:tag :size :type :dev :qid-type :qid-vers :qid-path :mode :atime :mtime :length :name :uid :gid :muid]

:Twstat [:tag :fid :size :type :dev :qid-type :qid-vers :qid-path :mode :atime :mtime :length :name :uid :gid :muid]
:Rwstat [:tag]})

(def type-size {:tag 2
:oldtag 2
:msize 4
:size 2
:size 4
:fid 4
:afid 4
:newfid 4
Expand Down Expand Up @@ -180,7 +180,7 @@
:atime #'buffers/get-int
:mtime #'buffers/get-int
:length #'buffers/get-long
:size #'buffers/get-short})
:size #'buffers/get-size})

(def put-operation {:version #'buffers/put-string
:name #'buffers/put-string
Expand Down Expand Up @@ -215,7 +215,7 @@
:length #'buffers/put-long
:fsize #'buffers/put-int
:ftype #'buffers/put-byte
:size #'buffers/put-short})
:size #'buffers/put-size})

;; we iterate over the keys in the buffer-operator map, and resolve functions for reading them.
(def reverse-frame-byte (reverse-map frame-byte))
Expand Down
82 changes: 41 additions & 41 deletions src/phlegyas/util.clj
Original file line number Diff line number Diff line change
Expand Up @@ -48,51 +48,51 @@
which is an anaphoric macro that creates a lexical environment and defines
a number of useful variables for us."
([name args body]
`(defn ~name ~args (do (with-frame-bindings ~body))))
`(defn ~name ~args (with-frame-bindings ~body)))
([name docstr args body]
`(defn ~name ~docstr ~args (do (with-frame-bindings ~body)))))
`(defn ~name ~docstr ~args (with-frame-bindings ~body))))

(defmacro with-frame-bindings
([body]
`(with-frame-bindings ~'frame ~body))
([frame body]
`(let [frame# ~frame
~'state (:state ~'connection)
~'current-state (if (instance? clojure.lang.Atom ~'state) ~'@state {})
~'frame-ftype (:frame frame#)
~'frame-tag (:tag frame#)
~'frame-qid-type (:qid-type frame#)
~'frame-qid-vers (:qid-vers frame#)
~'frame-qid-path (:qid-path frame#)
~'frame-nwqids (:nwqids frame#)
~'frame-wnames (:wnames frame#)
~'frame-iounit (:iounit frame#)
~'frame-iomode (:iomode frame#)
~'frame-count (:count frame#)
~'frame-size (:size frame#)
~'frame-type (:type frame#)
~'frame-perm (:perm frame#)
~'frame-atime (:atime frame#)
~'frame-mtime (:mtime frame#)
~'frame-length (:length frame#)
~'frame-name (:name frame#)
~'frame-uname (:uname frame#)
~'frame-muid (:muid frame#)
~'frame-data (:data frame#)
~'frame-offset (:offset frame#)
~'frame-fid (:fid frame#)
~'frame-ename (:ename frame#)
~'frame-version (:version frame#)
~'frame-afid (:afid frame#)
~'frame-aname (:aname frame#)
~'frame-oldtag (:oldtag frame#)
~'frame-newfid (:newfid frame#)
~'frame-msize (:msize frame#)
~'mapping (or (get (:mapping ~'current-state) (keywordize ~'frame-fid)) {})
~'fs-name (:filesystem ~'mapping)
~'fs (get (:fs-map ~'current-state) ~'fs-name)
~'fsid (:id ~'fs)
~'path (:path ~'mapping)]
`(let [frame# ~frame
{~'state :state} ~'connection
~'current-state (if (instance? clojure.lang.Atom ~'state) ~'@state {})
{~'frame-ftype :frame
~'frame-tag :tag
~'frame-qid-type :qid-type
~'frame-qid-vers :qid-vers
~'frame-qid-path :qid-path
~'frame-nwqids :nwqids
~'frame-wnames :wnames
~'frame-iounit :iounit
~'frame-iomode :iomode
~'frame-count :count
~'frame-size :size
~'frame-type :type
~'frame-perm :perm
~'frame-atime :atime
~'frame-mtime :mtime
~'frame-length :length
~'frame-name :name
~'frame-uname :uname
~'frame-muid :muid
~'frame-data :data
~'frame-offset :offset
~'frame-fid :fid
~'frame-ename :ename
~'frame-version :version
~'frame-afid :afid
~'frame-aname :aname
~'frame-oldtag :oldtag
~'frame-newfid :newfid
~'frame-msize :msize} frame#
~'mapping (or ((keywordize ~'frame-fid) (:mapping ~'current-state)) {})
{~'fs-name :filesystem} ~'mapping
~'fs ((:fs-map ~'current-state) ~'fs-name)
{~'fsid :id} ~'fs
{~'path :path} ~'mapping]
(~@body))))

(defmacro with-server
Expand Down Expand Up @@ -146,12 +146,12 @@
(defmacro reverse-map
"Reverses a map, keywordizing the value."
[table]
`(into {} (for [[k# v#] ~table] [(keywordize v#) k#])))
`(into {} (map (fn [[k# v#]] [(keywordize v#) k#]) ~table)))

(defn sizeof-string
"Count the number of bytes in a string."
[s]
(count (#^bytes .getBytes ^String s "UTF-8")))
(count (.getBytes s "UTF-8")))

(defn parse-int
"Coerce a string to integer."
Expand Down
19 changes: 10 additions & 9 deletions src/phlegyas/vfs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -381,15 +381,16 @@
case, a fid is not changed. Walks are only successful if the entire path can
be walked."
[fs path wnames]
(loop [candidates wnames
search-path path
paths []]
(let [candidate (first candidates)
candidate-path (when candidate (wname->path fs search-path candidate))]
(cond
(nil? candidate) paths
(nil? candidate-path) paths
:else (recur (rest candidates) candidate-path (conj paths candidate-path))))))
(let [paths (reduce (fn [acc wname]
(let [candidate-path (wname->path fs (last acc) wname)]
(if (nil? candidate-path)
(reduced acc)
(conj acc candidate-path))))
[path]
wnames)]
(if (= (count paths) (inc (count wnames)))
paths
(vec (butlast paths)))))

(defn stat->role
"Given a stat, and a user, find what role we have on it."
Expand Down
30 changes: 17 additions & 13 deletions test/phlegyas/sqlitefs_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,29 @@
(deftest new-filesystem
(with-system
(let [fs-name (uuid!)
fs (vfs/create-filesystem system fs-name)
_ (vfs/create-filesystem system fs-name)
created-fs-name (:name (vfs/get-filesystem system fs-name))]
(is (uuid= fs-name created-fs-name)))))

(deftest filesystem-with-nested-directory
(with-system
(let [fs-name (uuid!)
fs (vfs/create-filesystem system fs-name)
root-directory (vfs/get-node system {:qid-path (:rnode fs)})
sub-directory-1 (vfs/add-directory system root-directory "sub-directory-1")
sub-directory-2 (vfs/add-directory system root-directory "sub-directory-2")
fetched-directory (vfs/get-node system sub-directory-1)
directory-contents (vfs/get-directory-contents system root-directory)
_ (println (first directory-contents))
dir (vfs/directory-reader system root-directory 8192)]
(let [fs-name (uuid!)
fs (vfs/create-filesystem system fs-name)
root-directory (vfs/get-node system {:qid-path (:rnode fs)})
sub-directory-1 (vfs/add-directory system root-directory "sub-directory-1")
_ (vfs/add-directory system sub-directory-1 "sub-directory-2")
fetched-directory (vfs/get-node system sub-directory-1)
dir-contents (vfs/get-directory-contents system root-directory)
subdir-contents (vfs/get-directory-contents system root-directory)
_ (println (first dir-contents))
dir (vfs/directory-reader system root-directory 8192)]
(println "Dir:" dir)
(testing "Directory is successfully inserted and retrievable"
(is (uuid= (:path sub-directory-1)
(:path fetched-directory))))
(is (uuid= (:qid-path sub-directory-1)
(:qid-path fetched-directory))))

(testing "Directory contents are enumerable"
(is (= 2 (count directory-contents)))))))
(is (= 1 (count dir-contents))))

(testing "Directories can be nested"
(is (= 1 (count subdir-contents)))))))

0 comments on commit 822e557

Please sign in to comment.