Module: Ccp::Kvs::Tokyo::StateMachine

Includes:
TokyoCabinet
Included in:
Cabinet
Defined in:
lib/ccp/kvs/tokyo/state_machine.rb

Constant Summary collapse

CLOSED =

state machine

1
READABLE =
2
WRITABLE =
3
LOCKED_BY =
proc{|c| Array(c).select{|i| i !~ %r{/ruby/[^/]+/gems/}}[0,5].join("\n") || c rescue c}

Instance Method Summary collapse

Instance Method Details

#__close__(locker = nil) ⇒ Object



52
53
54
55
56
# File 'lib/ccp/kvs/tokyo/state_machine.rb', line 52

def __close__(locker = nil)
  @db.close
  CONNECTIONS[@db.path] = nil
  STDERR.puts "UNLOCK: #{@source} by [#{LOCKED_BY[locker || caller]}]" if @debug
end

#C!(locker = nil) ⇒ Object



62
63
64
65
66
67
68
69
# File 'lib/ccp/kvs/tokyo/state_machine.rb', line 62

def C!(locker = nil)
  case state
  when CLOSED   ; # NOP
  when READABLE,
       WRITABLE ; __close__(locker); @state = CLOSED
  else          ; raise "unknown state: #{state}"
  end
end

#close(locker = nil) ⇒ Object



58
59
60
# File 'lib/ccp/kvs/tokyo/state_machine.rb', line 58

def close(locker = nil)
  C!(locker)
end

#locker_infoObject



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/ccp/kvs/tokyo/state_machine.rb', line 20

def locker_info
  if CONNECTIONS[@source]
    return LOCKED_BY[CONNECTIONS[@source]]
  end

  target = File.basename(@source)
  CONNECTIONS.each_pair do |file, reason|
    return LOCKED_BY[reason] if File.basename(file) == target
  end

  if CONNECTIONS.any?
    return CONNECTIONS.inspect
  else
    return 'no brockers. maybe locked by other systems?'
  end
end

#open(mode, locker = nil) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/ccp/kvs/tokyo/state_machine.rb', line 37

def open(mode, locker = nil)
  Pathname(@source.to_s).parent.mkpath

  # open and mark filename for threading error
  if @db.open(@source.to_s, mode)
    locker ||= (caller rescue "???")
    STDERR.puts "LOCK: #{@source} by [#{LOCKED_BY[locker]}]" if @debug
    CONNECTIONS[@db.path.to_s] = locker
  elsif threading_error?
    raise Tokyo::Locked, "%s is locked by [%s]" % [@source, locker_info]
  else
    tokyo_error!("%s#open(%s,%s): " % [self.class, @source, mode])
  end
end

#R(locker = nil, &block) ⇒ Object



89
90
91
92
93
94
95
96
# File 'lib/ccp/kvs/tokyo/state_machine.rb', line 89

def R(locker = nil, &block)
  case state
  when CLOSED   ; begin; R!(locker); yield; ensure; close(locker); end
  when READABLE ; yield
  when WRITABLE ; yield
  else          ; raise "unknown state: #{state}"
  end
end

#R!(locker = nil) ⇒ Object



71
72
73
74
75
76
77
78
# File 'lib/ccp/kvs/tokyo/state_machine.rb', line 71

def R!(locker = nil)
  case state
  when CLOSED   ; open(HDB::OREADER, locker); @state = READABLE
  when READABLE ; # NOP
  when WRITABLE ; # NOP
  else          ; raise "unknown state: #{state}"
  end
end

#stateObject



16
17
18
# File 'lib/ccp/kvs/tokyo/state_machine.rb', line 16

def state
  @state || CLOSED
end

#touchObject



108
109
110
# File 'lib/ccp/kvs/tokyo/state_machine.rb', line 108

def touch
  W() {}
end

#W(locker = nil, &block) ⇒ Object



98
99
100
101
102
103
104
105
106
# File 'lib/ccp/kvs/tokyo/state_machine.rb', line 98

def W(locker = nil, &block)
  case state
  when CLOSED   ; begin; W!(locker); yield; ensure; close(locker); end
  when READABLE ; raise "reopen from read to write is not permitted"
    # TODO: close -> W -> close -> R ???
  when WRITABLE ; yield
  else          ; raise "unknown state: #{state}"
  end
end

#W!(locker = nil) ⇒ Object



80
81
82
83
84
85
86
87
# File 'lib/ccp/kvs/tokyo/state_machine.rb', line 80

def W!(locker = nil)
  case state
  when CLOSED   ; open(HDB::OCREAT | HDB::OWRITER, locker); @state = WRITABLE
  when READABLE ; C!(locker); W!(locker)
  when WRITABLE ; # NOP
  else          ; raise "unknown state: #{state}"
  end
end