Class: Gel::DB::SDBM

Inherits:
Gel::DB show all
Includes:
AutoTransaction
Defined in:
lib/gel/db.rb

Constant Summary collapse

SDBM_MAX_STORE_SIZE =

arbitrary on PBLKSIZ-N

1000 - 1
SAFE_DELIMITER =
'---'

Instance Method Summary collapse

Methods included from AutoTransaction

#nested?, #owned?, #read?, #write?

Methods inherited from Gel::DB

new

Constructor Details

#initialize(root, name) ⇒ SDBM

Returns a new instance of SDBM.



152
153
154
# File 'lib/gel/db.rb', line 152

def initialize(root, name)
  @sdbm = ::SDBM.new("#{root}/#{name}")
end

Instance Method Details

#[](key) ⇒ Object

Retrieve the value from SDBM and handle for when we split over multiple stores. It is safe to assume that the value stored will be a marshaled value or a integer implying the amount of extra stores to retrieve the data string form. A marshaled store would have special starting delimiter that is not a decimal. If a number is not found at start of string then simply load it as a string and you get a value that is then marshaled.



181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/gel/db.rb', line 181

def [](key)
  value = @sdbm[key.to_s]
  return nil unless value

  if value =~ /\A~(\d+)\z/
    value = $1.to_i.times.map do |idx|
      @sdbm["#{key}#{SAFE_DELIMITER}#{idx}"]
    end.join
  end

  return Marshal.load(value)
end

#[]=(key, value) ⇒ Object

SDBM has an arbitrary limit on the size of a string it stores, so we simply split any string over multiple stores for the edge case when it reaches this. It’s optimised to take advantage of the common case where this is not needed. When the edge case is hit, the first value in the storage will be the amount of extra values stored to hold the split string. This amount is determined by string size split by the arbitrary limit imposed by SDBM



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/gel/db.rb', line 203

def []=(key, value)
  return unless value && key

  dump = Marshal.dump(value)
  count = dump.length / SDBM_MAX_STORE_SIZE

  if count > 0
    count += 1
    @sdbm["#{key.to_s}"] = "~#{count}"
    count.times.map do |idx|
      @sdbm["#{key.to_s}#{SAFE_DELIMITER}#{idx}"] = dump.slice!(0, SDBM_MAX_STORE_SIZE)
    end
  else
    @sdbm[key.to_s] = dump
  end
end

#each_key(&block) ⇒ Object



164
165
166
# File 'lib/gel/db.rb', line 164

def each_key(&block)
  @sdbm.each_key(&block)
end

#key?(key) ⇒ Boolean

Returns:

  • (Boolean)


168
169
170
# File 'lib/gel/db.rb', line 168

def key?(key)
  !!@sdbm[key.to_s]
end

#readingObject



160
161
162
# File 'lib/gel/db.rb', line 160

def reading
  yield
end

#writingObject



156
157
158
# File 'lib/gel/db.rb', line 156

def writing
  yield
end