Class: BitClust::Database

Inherits:
Object show all
Includes:
NameUtils, DRb::DRbUndumped
Defined in:
lib/bitclust/server.rb,
lib/bitclust/database.rb

Overview

Abstract class for BitClust DB. Each entry is written in a file.

Has subclass MethodDatabase (Ruby stuff) and FunctionDatabase (C stuff).

Direct Known Subclasses

FunctionDatabase, MethodDatabase

Constant Summary

Constants included from NameUtils

NameUtils::CHAR_TO_MARK, NameUtils::CHAR_TO_NAME, NameUtils::CLASS_NAME_RE, NameUtils::CLASS_PATH_RE, NameUtils::CONST_PATH_RE, NameUtils::CONST_RE, NameUtils::GVAR_RE, NameUtils::LIBNAME_RE, NameUtils::MARK_TO_CHAR, NameUtils::MARK_TO_NAME, NameUtils::METHOD_NAME_RE, NameUtils::METHOD_SPEC_RE, NameUtils::MID, NameUtils::NAME_TO_CHAR, NameUtils::NAME_TO_MARK, NameUtils::TYPEMARK_RE

Instance Method Summary collapse

Methods included from NameUtils

build_method_id, classid2name, classname2id, classname?, decodeid, decodename_fs, decodename_url, display_typemark, encodeid, encodename_fs, encodename_rdocurl, encodename_url, functionname?, gvarname?, html_filename, libid2name, libname2id, libname?, method_spec?, methodid2classid, methodid2libid, methodid2mname, methodid2specparts, methodid2specstring, methodid2typechar, methodid2typemark, methodid2typename, methodname?, split_method_id, split_method_spec, typechar2mark, typechar2name, typechar?, typemark2char, typemark2name, typemark?, typename2char, typename2mark, typename?

Constructor Details

#initialize(prefix) ⇒ Database

Returns a new instance of Database.



46
47
48
49
50
51
# File 'lib/bitclust/database.rb', line 46

def initialize(prefix)
  @prefix = prefix
  @properties = nil
  @in_transaction = false
  @properties_dirty = false
end

Instance Method Details

#atomic_write_open(rel, &block) ⇒ Object



191
192
193
194
195
196
197
# File 'lib/bitclust/database.rb', line 191

def atomic_write_open(rel, &block)
  tmppath = realpath(rel) + '.writing'
  fopen(tmppath, 'wb', &block)
  File.rename tmppath, realpath(rel)
ensure
  File.unlink tmppath  rescue nil
end

#dummy?Boolean

Returns:

  • (Boolean)


53
54
55
# File 'lib/bitclust/database.rb', line 53

def dummy?
  not @prefix
end

#encodingObject



131
132
133
# File 'lib/bitclust/database.rb', line 131

def encoding
  propget('encoding')
end

#entries(rel) ⇒ Object



144
145
146
147
148
149
150
151
# File 'lib/bitclust/database.rb', line 144

def entries(rel)
  Dir.entries(realpath(rel))\
      .reject {|ent| /\A[\.=]/ =~ ent }\
      .map {|ent| decodeid(ent) }
      .sort
rescue Errno::ENOENT
  return []
end

#exist?(rel) ⇒ Boolean

Direct File Access Layer: BitClust internal use only

Returns:

  • (Boolean)


139
140
141
142
# File 'lib/bitclust/database.rb', line 139

def exist?(rel)
  return false unless @prefix
  File.exist?(realpath(rel))
end

#foreach_line(rel, &block) ⇒ Object



187
188
189
# File 'lib/bitclust/database.rb', line 187

def foreach_line(rel, &block)
  File.foreach(realpath(rel), &block)
end

#load_properties(rel) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/bitclust/database.rb', line 157

def load_properties(rel)
  h = {} #: Hash[String, String]
  fopen(realpath(rel), 'r:UTF-8') {|f|
    while line = f.gets
      k, v = line.strip.split('=', 2)
      break unless k
      h[k] = v || raise
    end
    h['source'] = f.read
  }
  h
rescue Errno::ENOENT
  return {}
end

#makepath(rel) ⇒ Object



153
154
155
# File 'lib/bitclust/database.rb', line 153

def makepath(rel)
  FileUtils.mkdir_p realpath(rel)
end

#propertiesObject

Properties



108
109
110
111
112
113
114
115
# File 'lib/bitclust/database.rb', line 108

def properties
  @properties ||=
      begin
        h = load_properties('properties')
        h.delete 'source' if h['source'] and h['source'].strip.empty?
        h
      end
end

#propget(key) ⇒ Object



121
122
123
# File 'lib/bitclust/database.rb', line 121

def propget(key)
  properties()[key] # steep:ignore
end

#propkeysObject



117
118
119
# File 'lib/bitclust/database.rb', line 117

def propkeys
  properties().keys
end

#propset(key, value) ⇒ Object



125
126
127
128
129
# File 'lib/bitclust/database.rb', line 125

def propset(key, value)
  check_transaction
  properties()[key] = value # steep:ignore
  @properties_dirty = true
end

#read(rel) ⇒ Object



183
184
185
# File 'lib/bitclust/database.rb', line 183

def read(rel)
  File.read(realpath(rel))
end

#save_properties(rel, h) ⇒ Object



172
173
174
175
176
177
178
179
180
181
# File 'lib/bitclust/database.rb', line 172

def save_properties(rel, h)
  source = h.delete('source')
  atomic_write_open(rel) {|f|
    h.each do |key, val|
      f.puts "#{key}=#{val}"
    end
    f.puts
    f.puts source
  }
end

#transactionObject

Transaction



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/bitclust/database.rb', line 61

def transaction
  @in_transaction = true
  yield
  return if dummy?
  if @properties_dirty
    save_properties 'properties', (@properties || raise)
    @properties_dirty = false
  end
  if dirty?
    commit
    # 更新完了の合図として properties の mtime を進める(bitclust#275)。
    # server の自動リロード(ReloadableRequestHandler)は properties の
    # mtime で新鮮さを判定するため、init 直後〜update 完了前の途中状態を
    # 読んでしまったプロセスも、ここで mtime が進むことで次のリクエスト
    # から完成した DB を読み直して収束できる
    touch_properties
  end
ensure
  @in_transaction = false
end