### Understanding Ohm Internals through Logging #### Benefits # Ohm is actually a very thin wrapper for Redis, and most of the design # patterns implemented in Ohm are based on the prescribed patterns for using # Redis. # # If you take a little time to grok the internals of Ohm and Redis, the more # effective you will be in weilding it efficiently. #### Keys # # Most key-value stores have standardized on a structured design pattern for # organizing data. Let's fire up a console: # # >> irb -r ohm -r logger # # Ohm.redis.client.logger = Logger.new(STDOUT) # # class Post < Ohm::Model # attribute :title # end # # Post.create(:title => "Grokking Ohm") # # After executing `Post.create(...)`, you'll see a lot of output from the # logger. Let's go through every line in detail. #### Post.create # *Generate a new `Post:id`.* INCR Post:id # *Lock `Post:2` # (see [SETNX](http://code.google.com/p/redis/wiki/SetnxCommand) # for an explanation of the locking design pattern). SETNX Post:2:_lock 1285060009.409451 # *Add the newly generated ID 2 to the `Post:all` SET.* SADD Post:all 2 # *Start transaction.* MULTI # *Delete HASH `Post:2`.* DEL Post:2 # *Set the attributes.* HMSET Post:2 title "Grokking Ohm" # *End transaction.* EXEC # *Release the lock.* DEL Post:2:_lock #### Sets and Lists # Let's do a little `SET` and `LIST` manipulation and see what Ohm does. # Here's the code for this section: # # class User < Ohm::Model # collection :posts, Post # end # # class Post < Ohm::Model # attribute :title # reference :user, User # # list :comments, Comment # end # # class Comment < Ohm::Model # end #### User.create # *Generate a new ID for the `User`.* INCR User:id # *Lock User:9.* SETNX User:9:_lock 1285061032.174834 # *Add this new user to the SET User:all.* SADD User:all 9 # *Release the lock.* DEL User:9:_lock #### Post.create(:title => "Foo", :user => User.create) # *Generate an ID for this Post* INCR Post:id # *Lock Post:3* SETNX Post:3:_lock 1285061032.180314 # *Add the ID 3 to the SET Post:all* SADD Post:all 3 # *Start transaction* MULTI # *Remove existing Post:3 HASH* DEL Post:3 # *Assign the attributes to Post:3* HMSET Post:3 title Foo user_id 9 # *End transaction* EXEC # *Add the ID of this post to the SET index (more on this below)* SADD Post:user_id:OQ== 3 # *Book keeping for Post:3 indices* SADD Post:3:_indices Post:user_id:OQ== # *Release lock* DEL Post:3:_lock #### post.comments << Comment.create # *Generate an ID for this comment* INCR Comment:id # *Lock Comment:1* SETNX Comment:1:_lock 1285061034.335855 # *Add this comment to the SET Comment:all* SADD Comment:all 1 # *Release lock* DEL Comment:1:_lock # *Append the comment to the LIST Post:3:comments* RPUSH Post:3:comments 1 #### Understanding indexes # reference :user, User # # is actually more or less the same as: # # attribute :user_id # index :user_id # # def user # User[user_id] # end # # def user_id=(user_id) # self.user_id = user_id # end # # To further explain the [example above](#section-29), let's # run through the commands that was issued. Remember that # we had a *user_id* of *9* and a *post_id* of *3*. # *OQ== is Base64 of *9*, with newlines removed. The post_id 3 is added # effectively to Post:user_id:9, if we ignore the encoding.* SADD Post:user_id:OQ== 3 # *Just keep track that Post:user_id:OQ== was created* SADD Post:3:_indices Post:user_id:OQ== # *Get all *posts* with user_id *9** SMEMBERS Post:user_id:OQ== #### What's next? # We tackled a fair bit amount regarding Ohm internals. More or less this is # the foundation of everything else found in Ohm, and other code are just # built around the same fundamental concepts. # # If there's anything else you want to know, you can hang out on #ohm at # irc.freenode.net, or you can visit the # [Ohm google group](http://groups.google.com/group/ohm-ruby).