Class: StrokeDB::SkiplistStore

Inherits:
Store show all
Includes:
Enumerable
Defined in:
lib/stores/skiplist_store/skiplist_store.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Enumerable

#each_consecutive_pair, #group_by, #map_with_index, #trigger_partition

Methods inherited from Store

#remote_server, #sync!

Methods included from ChainSync

#sync_chains

Constructor Details

#initialize(opts = {}) ⇒ SkiplistStore



6
7
8
9
10
11
12
13
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 6

def initialize(opts={})
  opts = opts.stringify_keys
  @chunk_storage = opts['storage']
  @cut_level = opts['cut_level'] || 4
  @index_store = opts['index']
  autosync! unless opts['noautosync']
  raise "Missing chunk storage" unless @chunk_storage
end

Instance Attribute Details

#chunk_storageObject

Returns the value of attribute chunk_storage.



4
5
6
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 4

def chunk_storage
  @chunk_storage
end

#cut_levelObject

Returns the value of attribute cut_level.



4
5
6
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 4

def cut_level
  @cut_level
end

#index_storeObject

Returns the value of attribute index_store.



4
5
6
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 4

def index_store
  @index_store
end

Instance Method Details

#autosync!Object



132
133
134
135
136
137
138
139
140
141
142
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 132

def autosync!
  @autosync_mutex ||= Mutex.new
  @autosync = nil if @autosync && !@autosync.status
  at_exit { stop_autosync! }
  @autosync ||= Thread.new do 
    until @stop_autosync
      @autosync_mutex.synchronize { chunk_storage.sync_chained_storages! }
      sleep(1)
    end
  end
end

#documentObject



120
121
122
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 120

def document
  find(uuid) || StoreInfo.create!(self,:kind => 'skiplist', :uuid => uuid)
end

#each(options = {}) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 84

def each(options = {})
  return nil unless m = @chunk_storage.find('MASTER')  # no master chunk yet
  after = options[:after_timestamp]
  include_versions = options[:include_versions]
  m.each do |node|
    chunk = @chunk_storage.find(node.value)
    next unless chunk
    next if after && chunk.timestamp <= after

    chunk.each do |node| 
      next if after && (node.timestamp <= after)
      if uuid_match = node.key.match(/^#{UUID_RE}$/) || (include_versions && uuid_match = node.key.match(/#{UUID_RE}./) )
        yield Document.from_raw(self, node.value) 
      end
    end
  end
end

#empty?Boolean



124
125
126
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 124

def empty?
  !@chunk_storage.find('MASTER')
end

#exists?(uuid, version = nil) ⇒ Boolean



40
41
42
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 40

def exists?(uuid, version=nil)
  !!find(uuid, version, :no_instantiation => true)
end

#find(uuid, version = nil, opts = {}) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 15

def find(uuid, version=nil, opts = {})
  uuid_version = uuid + (version ? ".#{version}" : "")
  master_chunk = @chunk_storage.find('MASTER')
  return nil unless master_chunk  # no master chunk yet
  chunk_uuid = master_chunk.find_nearest(uuid_version, nil)
  return nil unless chunk_uuid # no chunks in master chunk yet
  chunk = @chunk_storage.find(chunk_uuid)
  return nil unless chunk

  raw_doc = chunk.find(uuid_version)

  if raw_doc
    return raw_doc if opts[:no_instantiation]
    doc = Document.from_raw(self, raw_doc.freeze)
    doc.extend(VersionedDocument) if version
    return doc
  end
  nil
end

#full_dumpObject



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 67

def full_dump
  puts "Full storage dump:"
  m = @chunk_storage.find('MASTER')
  puts "No master!" unless m
  m.each do |node|
    puts "[chunk: #{node.key}]"
    chunk = @chunk_storage.find(node.value)
    if chunk
      chunk.each do |node|
        puts "    [doc: #{node.key}] => {uuid: #{node.value['__uuid__']}, version: #{node.value['version']}, previous_version: #{node.value['previous_version']}"
      end
    else
      puts "    nil! (but in MASTER somehow?...)"
    end
  end
end

#head_version(uuid) ⇒ Object



44
45
46
47
48
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 44

def head_version(uuid)
  raw_doc = find(uuid, nil, :no_instantiation => true)
  return raw_doc['version'] if raw_doc
  nil
end

#inspectObject



128
129
130
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 128

def inspect
  "#<Skiplist store #{uuid}#{empty? ? " (empty)" : ""}>"
end

#next_timestampObject



105
106
107
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 105

def next_timestamp
  @timestamp = timestamp.next
end

#save!(doc) ⇒ Object



50
51
52
53
54
55
56
57
58
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 50

def save!(doc)
  master_chunk = find_or_create_master_chunk
  next_timestamp

  insert_with_cut(doc.uuid, doc, master_chunk) unless doc.is_a?(VersionedDocument)
  insert_with_cut("#{doc.uuid}.#{doc.version}", doc, master_chunk)

  update_master_chunk!(doc, master_chunk)
end

#save_as_head!(doc) ⇒ Object



60
61
62
63
64
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 60

def save_as_head!(doc)
  master_chunk = find_or_create_master_chunk
  insert_with_cut(doc.uuid, doc, master_chunk)
  update_master_chunk!(doc, master_chunk)
end

#search(*args) ⇒ Object



35
36
37
38
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 35

def search(*args)
  return [] unless @index_store
  @index_store.find(*args)
end

#stop_autosync!Object



144
145
146
147
148
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 144

def stop_autosync!
  if @autosync_mutex
    @autosync_mutex.synchronize { @stop_autosync = true; chunk_storage.sync_chained_storages! }
  end
end

#timestampObject



102
103
104
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 102

def timestamp
  @timestamp ||= (lts = find_or_create_master_chunk.timestamp) ? LTS.from_raw(lts) : LTS.zero(uuid)
end

#uuidObject



109
110
111
112
113
114
115
116
117
118
# File 'lib/stores/skiplist_store/skiplist_store.rb', line 109

def uuid
  return @uuid if @uuid
  master_chunk = @chunk_storage.find('MASTER')
  unless master_chunk
    @uuid = Util.random_uuid
  else
    @uuid = master_chunk.store_uuid
  end
  @uuid
end