jntivg
Last Updated: February 25, 2016
·
2.989K
· runexec
81609937c20aeab3598aea56f1f4f022

CouchDB: MVCC in Action

CouchDB's Multi-Version Concurrency Control allows us to pull revisions of our data with the attribute _rev. CouchDB B+tree data storage system is both concurrent and immutable. This means the data can only be appended, but it prevents written data from being erased or corrupted.

For those who can't wait to get to the bottom

=> (def revid (last (drop-last @*revisions*)))    
#'lotus.server/revid    
=> revid    
"2-734d21eb1adef6eebafb330faf6efdee"    
=> (println "Pay attention to :title and :_rev")    
Pay attention to :title and :_rev    
=> (couch/get-document "lotus-messages" docid :rev revid)    
{:_id "98e9e777406b81074d4f876d3c006c18",    
 :_rev "2-734d21eb1adef6eebafb330faf6efdee",    
 :date "May 1st 1123",    
 :tags "example,db",    
 :title "Updated!",    
 :body "Body"}    
=> (couch/get-document "lotus-messages" docid :rev (last @*revisions*))    
{:_id "98e9e777406b81074d4f876d3c006c18",    
 :_rev "3-f9461e55954c7bda3532f686b9ab1461",    
 :date "May 1st 1123",    
 :tags "example,db",    
 :title "Ryan Kelker MVCC in Action",    
 :body "Body"}    

The Howto    endorse

=> (def ^:dynamic *revisions* (atom []));; vec to preserve revision order    
#'lotus.server/*revisions*    
=> (defn add-revision [rev-id]    
           (let [uniq? (every? #(false? (= % rev-id)) @*revisions*)]    
             (if uniq? (do (swap! *revisions* conj rev-id) true) false)))    
#'lotus.server/add-revision    
=> (defn new-post [post]    
                 (add-revision (:_rev    
                                (couch/update-document    
                                 "lotus-messages"    
                                 post))))    
#'lotus.server/new-post    
=> (require '[com.ashafa.clutch :as couch])    
nil    
=> (def db (couch/couch "lotus-messages"))    
#'lotus.server/db    
=> (try (couch/create! db) (catch Exception e "Failed"))    
#<CouchDB com.ashafa.clutch.CouchDB@2a09a892>    
=> (meta *1)    
{:result #cemerick.url.URL{:protocol "http",    
                           ### trim ###    
                           instance_start_time "1349052478481280",    
                           :doc_count 0}}    
=> (defstruct blog-post :date :tags :title :body)    
#'lotus.server/blog-post    
=> (def bpost (struct blog-post "May 1st 1123" "example,db" "Example Title" "Body"))    
#'lotus.server/bpost    
=> bpost    
{:date "May 1st 1123", :tags "example,db", :title "Example Title", :body "Body"}    
=> (def docid    
                 (:_id (couch/put-document    
                        "lotus-messages"    
                        (assoc bpost    
                          :title    
                          "New Post Example"))))    
#'lotus.server/docid    
=> docid    
"98e9e777406b81074d4f876d3c006c18"    
=> (couch/get-document "lotus-messages" docid)    
{:_id "98e9e777406b81074d4f876d3c006c18",    
 :_rev "1-aaaaaef03f0528a04e84cd28005df701",    
 :date "May 1st 1123",    
 :tags "example,db",    
 :title "New Post Example",    
 :body "Body"}    

=> (def mydoc (couch/get-document "lotus-messages" docid))    
#'lotus.server/mydoc    
=> (def update-doc (assoc mydoc :title "Updated!"))    
#'lotus.server/update-doc    
=> (new-post update-doc)    
true    
=> (println "Notice the _rev value!")    
Notice the _rev value!    
=> (couch/get-document "lotus-messages" docid)    
{:_id "98e9e777406b81074d4f876d3c006c18",    
 :_rev "2-734d21eb1adef6eebafb330faf6efdee",    
 :date "May 1st 1123",    
 :tags "example,db",    
 :title "Updated!",    
 :body "Body"}    
=> (last @*revisions*)    
"2-734d21eb1adef6eebafb330faf6efdee"    
=> (println "Get the second revision of this document")    
Get the second revision of this document    
=> (def mydoc (couch/get-document    
                           "lotus-messages"    
                           docid    
                           :rev (last @*revisions*)))    
#'lotus.server/mydoc    
=> mydoc    
{:_id "98e9e777406b81074d4f876d3c006c18",    
 :_rev "2-734d21eb1adef6eebafb330faf6efdee",    
 :date "May 1st 1123",    
 :tags "example,db",    
 :title "Updated!",    
 :body "Body"}    
=> (println "Update and get the second revision, and not the 3rd")    
Update and get the second revision, and not the 3rd    
=> (last @*revisions*)    
"3-f9461e55954c7bda3532f686b9ab1461"    
=> (def revid (last (drop-last @*revisions*)))    
#'lotus.server/revid    
=> revid    
"2-734d21eb1adef6eebafb330faf6efdee"    
=> (println "Pay attention to :title and :_rev")    
Pay attention to :title and :_rev    
=> (couch/get-document "lotus-messages" docid :rev revid)    
{:_id "98e9e777406b81074d4f876d3c006c18",    
 :_rev "2-734d21eb1adef6eebafb330faf6efdee",    
 :date "May 1st 1123",    
 :tags "example,db",    
 :title "Updated!",    
 :body "Body"}    
=> (couch/get-document "lotus-messages" docid :rev (last @*revisions*))    
{:_id "98e9e777406b81074d4f876d3c006c18",    
 :_rev "3-f9461e55954c7bda3532f686b9ab1461",    
 :date "May 1st 1123",    
 :tags "example,db",    
 :title "Ryan Kelker MVCC in Action",    
 :body "Body"}    

(A friendly argument I make if you need more details http://pastie.org/4897168)

Say Thanks
Respond