Class: Blodsband::Riak::List::Element

Inherits:
Object
  • Object
show all
Defined in:
lib/blodsband/riak/list.rb

Overview

The list element.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#keyObject (readonly)

The key in Riak for this element.



49
50
51
# File 'lib/blodsband/riak/list.rb', line 49

def key
  @key
end

#listObject (readonly)

The Blodsband::Riak::List this element belongs to.



53
54
55
# File 'lib/blodsband/riak/list.rb', line 53

def list
  @list
end

Class Method Details

.create(list, value) ⇒ Blodsband::Riak::Element

Create an element.

Parameters:

  • list (Blodsband::Riak::List)

    the list the element shall belong to.

  • value (Object)

    the value to put in the element.

Returns:

  • (Blodsband::Riak::Element)

    a new (unsaved) element with the given value.



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/blodsband/riak/list.rb', line 82

def self.create(list, value)
  rval = Element.new
  rval.instance_eval do
    @list = list
    @key = rand(1 << 256).to_s(36)
    @value = value
    class << @value
      include Response
    end
    @value.instance_eval do
      @meta = (@meta || {}).merge("list-key" => list.key)
    end
  end
  rval.save
  rval
end

.find(list, key) ⇒ Blodsband::Riak::Element

Find an element.

Parameters:

  • list (Blodsband::Riak::List)

    the list the element belongs to.

  • key (String)

    the key for this element.

Returns:

  • (Blodsband::Riak::Element)

    the element at the given key.



63
64
65
66
67
68
69
70
# File 'lib/blodsband/riak/list.rb', line 63

def self.find(list, key)
  rval = Element.new
  rval.instance_eval do
    @list = list
    @key = key
  end
  rval
end

Instance Method Details

#append(value) ⇒ Object

Append a value after this element in the list.

Parameters:

  • value (Object)

    the value to append.

Returns:

  • (Object)

    the value appended.



193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/blodsband/riak/list.rb', line 193

def append(value)
  if exists?
    while !list.append_element_after(self, Element.create(list, value))
      list.reload
      reload
      raise ActorDeletedError.new(self, to_s) unless exists?
      raise ActorDeletedError.new(list, list.to_s) unless list.exists?
    end
  else
    raise ActorDeletedError.new(self, to_s)
  end
end

#deleteObject

Delete this element.



175
176
177
178
179
180
181
182
183
184
# File 'lib/blodsband/riak/list.rb', line 175

def delete
  if exists?
    while !list.delete_element(self)
      list.reload
      reload
      break unless exists?
      raise ActorDeletedError.new(list, list.to_s) unless list.exists?
    end
  end
end

#exists?true, false

Returns whether the element exists.

Returns:

  • (true, false)

    whether the element exists.



102
103
104
105
# File 'lib/blodsband/riak/list.rb', line 102

def exists?
  reload
  !key.nil? && !value.nil?
end

#nextString

Returns the key to the next element in the list.

Returns:

  • (String)

    the key to the next element in the list.



237
238
239
# File 'lib/blodsband/riak/list.rb', line 237

def next
  value.meta["list-next"]
end

#next_elementBlodsband::Riak::List::Element

Returns the next element or nil.

Returns:



246
247
248
# File 'lib/blodsband/riak/list.rb', line 246

def next_element
  Element.find(list, self.next)
end

#prepend(value) ⇒ Object

Prepend a value before this element in the list.

Parameters:

  • value (Object)

    the value to prepend.

Returns:

  • (Object)

    the value inserted.



159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/blodsband/riak/list.rb', line 159

def prepend(value)
  if exists?
    while !list.prepend_element_before(self, Element.create(list, value))
      list.reload
      reload
      raise ActorDeletedError.new(self, to_s) unless exists?
      raise ActorDeletedError.new(list, list.to_s) unless list.exists?
    end
  else
    raise ActorDeletedError.new(self, to_s)
  end
end

#previousString

Returns the key to the previous element in the list.

Returns:

  • (String)

    the key to the previous element in the list.



255
256
257
# File 'lib/blodsband/riak/list.rb', line 255

def previous
  value.meta["list-previous"]
end

#previous_elementBlodsband::Riak::List::Element

Returns the previous element or nil.

Returns:



264
265
266
# File 'lib/blodsband/riak/list.rb', line 264

def previous_element
  Element.find(list, self.previous)
end

#reloadObject

Make sure this element is reloaded from Riak.



228
229
230
# File 'lib/blodsband/riak/list.rb', line 228

def reload
  @value = nil
end

#saveObject

Save this element.

Raises:



213
214
215
216
217
218
219
220
221
# File 'lib/blodsband/riak/list.rb', line 213

def save
  curr = @value
  @value = list.bucket.cas(key, value, value.vclock)
  if @value.nil?
    raise ConcurrentUpdateError.new(self, to_s) 
  else
    #STDERR.puts("#{$$} succeeded saving #{curr} (#{curr.meta})")
  end
end

#set_pointers(list_version, previous_key, next_key) ⇒ Object



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/blodsband/riak/list.rb', line 271

def set_pointers(list_version, previous_key, next_key)
  begin
    list_doc = list.bucket.get(list.key)
    if list_doc.nil? || list_doc["version"] == list_version
      if previous_key.nil?
        value.meta.delete("list-previous")
      elsif previous_key != ":unchanged"
        value.meta["list-previous"] = previous_key 
      end
      if next_key.nil?
        value.meta.delete("list-next")
      elsif next_key != ":unchanged"
        value.meta["list-next"] = next_key 
      end
      save
    end
  rescue ConcurrentUpdateError => e
    retry if exists?
  end
end

#to_sString

Returns a String representation of the element.

Returns:

  • (String)

    a String representation of the element.



110
111
112
113
114
115
116
# File 'lib/blodsband/riak/list.rb', line 110

def to_s
  if exists?
    "#{self.previous} => #{self.class}:#{key}@#{list.key} #{value.inspect} => #{self.next}"
  else
    "#{self.class}:#{key}@#{list.key}"
  end
end

#valueObject

Returns the value of this element.

Returns:

  • (Object)

    the value of this element.



148
149
150
# File 'lib/blodsband/riak/list.rb', line 148

def value
  @value ||= list.bucket.get(key, :unique => true)
end

#value=(o) ⇒ Object

Note:

Does not lock the parent list, since changing the element value is independent of structural list changes. Instead both this and structural list changes just retry on ConcurrentUpdateError.

Returns the new value.

Parameters:

  • o (Object)

    the new value to set in this element.

Returns:

  • (Object)

    the new value.



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/blodsband/riak/list.rb', line 127

def value=(o)
  begin
    old_value = value
    @value = value.copy_to(o)
    value.instance_eval do
      @meta = old_value.meta
    end
    save
    value
  rescue ConcurrentUpdateError => e
    if !exists?
      raise ActorDeletedError.new(self, to_s)
    else
      retry
    end
  end
end