dsabanin/subversion-clj — pull request #10 by temochka (2014-08-22 04:45:24+00:00)
Title: Remove heuristics used for a node type detection.

I was able to remove that heuristic check and generally make accessing revisions more efficient. On my tests the new code runs up to 2.5 times faster depending on a test. I used a pretty busy Subversion PHP repo with approximately 5000 commits for benchmarking. I compared the results using a diff tool and the only differences were directories false-positively recognized as files by the old code.

Here are benchmark results:

```
## Before

"Spitting a repo one by one commit."
"Elapsed time: 5243.014 msecs"
"Spitting a repo in batches."
"Elapsed time: 1682.344 msecs"
"Spitting a repo by reading all commits at once."
"Elapsed time: 1686.641 msecs"

## After

"Spitting a repo one by one commit."
"Elapsed time: 3080.742 msecs"
"Spitting a repo in batches."
"Elapsed time: 606.464 msecs"
"Spitting a repo by reading all commits at once."
"Elapsed time: 556.598 msecs"
```

And here is the benchmark:

``` clojure
(require '[subversion-clj.core :as svn :reload :all])
(import '[org.tmatesoft.svn.core.io SVNRepository])
(import '[java.io FileOutputStream])

;;; A busy SVN repository with ~5000 revisions, mostly PHP and binary files
(def repo-uri "file:///repo/")
(def repo (svn/repo-for repo-uri))
(def batch-size 100)

(defn spit-one-by-one [^SVNRepository repo filename]
(with-open [w (clojure.java.io/writer filename :append false)]
(let [max-rev (.getLatestRevision repo)]
(doseq [i (range 1 max-rev)]
(let [rev (svn/revision-for repo i)]
(.write w (str rev "\n\n")))))))

(defn spit-in-batches [^SVNRepository repo filename]
(with-open [w (clojure.java.io/writer filename :append false)]
(let [max-rev (.getLatestRevision repo)]
(doseq [i (range 1 max-rev batch-size)]
(let [revs (svn/revisions-for repo nil i (min (+ i batch-size) max-rev))]
(doseq [rev revs]
(.write w (str rev "\n\n"))))))))

(defn spit-all [^SVNRepository repo filename]
(with-open [w (clojure.java.io/writer filename :append false)]
(doseq [rev (svn/revisions-for repo nil 1 (.getLatestRevision repo))]
(.write w (str rev "\n\n")))))

(def benchmark-1 (partial spit-one-by-one repo))
(def benchmark-2 (partial spit-in-batches repo))
(def benchmark-3 (partial spit-all repo))

(def dev-null-stream (-> "/dev/null" FileOutputStream.))

;;; Warmup
(repeatedly 5 (benchmark-1 dev-null-stream))
(repeatedly 5 (benchmark-2 dev-null-stream))
(repeatedly 5 (benchmark-3 dev-null-stream))

(prn "Spitting a repo one by one commit.")
(time (benchmark-1 "benchmark-1.txt"))

(prn "Spitting a repo in batches.")
(time (benchmark-2 "benchmark-2.txt"))

(prn "Spitting a repo by reading all commits at once.")
(time (benchmark-3 "benchmark-3.txt"))
```

Could you please take a look and make sure I didn’t miss something?