preload
Adding Commas to Numbers in Ruby Restore of iPhone asks for Password
Jul 13

I was writing a Ruby program today that just needed a very simple way to control multiple web requests to a Sinatra server from querying a remote server at the same time. I would think that Sinatra does have some nice way to do this(and if you know it, please send me the link :) ), but I didn’t have time to dig into it, so I pulled out my old trusty Lockfile class.

The concept is very simple: Open a file, put a random string into it, close it. I use the random string to make sure that my process really did create the file, rather than another process running at the same time. The verify method can be called at any time to check that we still have the lock….well, that we are suppose to have the lock ;) If the file already exists, then you don’t get the lock. If you can’t open the file, then someone else must have just opened it, and again no lock.

Now the source…

#
#  Lockfile.rb  --  Implement a simple lock file method
#

class Lockfile
  attr_accessor  :lockfile

  @lockcode = ""
  def initialize(lckf)
    @lockfile = lckf
    if File.exists?(@lockfile)
      return false
    else
      lck = create
      ## verify that we indeed did get the lock
      if self.verify
        return
      else
        return false
      end
    end
  end

  def verify
    if not File.exists?(@lockfile)
      return false
    end
    if readlock == @lockcode
      return true
    else
      return false
    end
  end

  def release
    if self.verify
      begin
        File.delete(@lockfile)
        @lockcode = ""
      rescue Exception => e
        return false
      end
      return true
    else
      return false
    end
  end

  def create_key(length)
    alpha = [('a'..'z'),('A'..'Z')].map{|i| i.to_a}.flatten
    return (0..length).map{ alpha[rand(alpha.length)]  }.join
  end

  def finalize(id)
    #
    # Ensure lock file is erased when object dies before being released
    #
    File.delete(@lockfile)
  end

  ##-----------------##
  private
  ##-----------------##

  def create
    @lockcode = create_key(80)
    begin
      g = File.open(@lockfile,"w")
      g.write @lockcode
      g.close
    rescue Exception => e
      return false
    end
    return true
  end

  def readlock
    code = ""
    begin
      g = File.open(@lockfile,"r")
      code = g.read
      g.close
    rescue
      return ""
    end
    return code
  end

end

Using the class is pretty simple:

irb(main):085:0>p lockfile
"test.lck"
=> nil
irb(main):086:0> g = Lockfile.new(lockfile)
=> #<Lockfile:0x2d842ec @lockcode="eIRpefAHnAVZDtpiXXAbwblegdkFidHwkyKhJPKdGzRYOuJWRRVYtIXEWZPgyfycODxdeHfLYsPxcepVQ", @lockfile="test.lck">
irb(main):087:0> g.verify
=> true
irb(main):088:0> h = Lockfile.new(lockfile)
=> #<Lockfile:0x2d7ff58 @lockfile="test.lck">
irb(main):089:0> h.verify
=> false
irb(main):090:0> h.release
=> false
irb(main):093:0> g.verify
=> true
irb(main):094:0> g.release
=> true
irb(main):095:0> File.exists?(lockfile)
=> false
irb(main):096:0>

Good luck and have fun programming! :)

SociBook del.icio.us Digg Facebook Google Yahoo Buzz StumbleUpon

Leave a Reply