Class: PEROBS::DynamoDB

Inherits:
DataBase show all
Defined in:
lib/perobs/DynamoDB.rb

Overview

This class implements an Amazon DynamoDB storage engine for PEROBS.

Constant Summary collapse

INTERNAL_ITEMS =
%w( config item_counter )

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from DataBase

#check_option, #close, #deserialize, #open, #serialize

Constructor Details

#initialize(db_name, options = {}) ⇒ DynamoDB

Create a new DynamoDB object.

Parameters:

  • db_name (String)

    name of the DB directory

  • options (Hash) (defaults to: {})

    options to customize the behavior. Currently only the following options are supported: :serializer : Can be :json and :yaml :aws_id : AWS credentials ID :aws_key : AWS credentials key :aws_region : AWS region to host the data



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/perobs/DynamoDB.rb', line 51

def initialize(db_name, options = {})
  # :marshal serialization results in a binary format that cannot easily
  # be stored in DynamoDB. We fall back to :yaml.
  if options[:serializer] == :marshal
    options[:serializer] = :yaml
  end

  super(options)

  if options.include?(:aws_id) && options.include?(:aws_key)
    Aws.config[:credentials] = Aws::Credentials.new(options[:aws_id],
                                                    options[:aws_key])
  end
  if options.include?(:aws_region)
    Aws.config[:region] = options[:aws_region]
  end

  @dynamodb = Aws::DynamoDB::Client.new
  @table_name = db_name
  @config = nil
  # The number of items currently stored in the DB.
  @item_counter = nil
  if create_table(@table_name)
    @config = { 'serializer' => @serializer }
    put_hash('config', @config)
    @item_counter = 0
    dynamo_put_item('item_counter', @item_counter.to_s)
  else
    @config = get_hash('config')
    if @config['serializer'] != @serializer
      raise ArgumentError, "DynamoDB #{@table_name} was created with " +
        "serializer #{@config['serializer']} but was now opened with " +
        "serializer #{@serializer}."
    end
    @item_counter = dynamo_get_item('item_counter').to_i
  end

  # Read the existing DB config.
end

Instance Attribute Details

#item_counterObject (readonly)

Returns the value of attribute item_counter.



41
42
43
# File 'lib/perobs/DynamoDB.rb', line 41

def item_counter
  @item_counter
end

Class Method Details

.delete_db(table_name) ⇒ Object



99
100
101
102
103
# File 'lib/perobs/DynamoDB.rb', line 99

def DynamoDB::delete_db(table_name)
  dynamodb = Aws::DynamoDB::Client.new
  dynamodb.delete_table(:table_name => table_name)
  dynamodb.wait_until(:table_not_exists, table_name: table_name)
end

Instance Method Details

#check(id, repair) ⇒ TrueClass/FalseClass

Check if the stored object is syntactically correct.

Parameters:

  • id (Integer)

    Object ID

  • repair (TrueClass/FalseClass)

    True if an repair attempt should be made.

Returns:

  • (TrueClass/FalseClass)

    True if the object is OK, otherwise false.



210
211
212
213
214
215
216
217
218
219
# File 'lib/perobs/DynamoDB.rb', line 210

def check(id, repair)
  begin
    get_object(id)
  rescue => e
    PEROBS.log.error "Cannot read object with ID #{id}: #{e.message}"
    return false
  end

  true
end

#check_db(repair = false) ⇒ Object

Basic consistency check.

Parameters:

  • repair (TrueClass/FalseClass) (defaults to: false)

    True if found errors should be repaired.



190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/perobs/DynamoDB.rb', line 190

def check_db(repair = false)
  unless (item_counter = dynamo_get_item('item_counter')) &&
         item_counter == @item_counter
    PEROBS.log.error "@item_counter variable (#{@item_counter}) and " +
      "item_counter table entry (#{item_counter}) don't match"
  end
  item_counter = 0
  each_item { item_counter += 1 }
  unless item_counter == @item_counter
    PEROBS.log.error "Table contains #{item_counter} items but " +
      "@item_counter is #{@item_counter}"
  end
end

#clear_marksObject

This method must be called to initiate the marking process.



152
153
154
155
156
# File 'lib/perobs/DynamoDB.rb', line 152

def clear_marks
  each_item do |id|
    dynamo_mark_item(id, false)
  end
end

#delete_databaseObject

Delete the entire database. The database is no longer usable after this method was called.



93
94
95
96
97
# File 'lib/perobs/DynamoDB.rb', line 93

def delete_database
  dynamodb = Aws::DynamoDB::Client.new
  dynamodb.delete_table(:table_name => @table_name)
  dynamodb.wait_until(:table_not_exists, table_name: @table_name)
end

#delete_unmarked_objectsInteger

Permanently delete all objects that have not been marked. Those are orphaned and are no longer referenced by any actively used object.

Returns:

  • (Integer)

    Count of the deleted objects.



161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/perobs/DynamoDB.rb', line 161

def delete_unmarked_objects
  deleted_objects_count = 0
  each_item do |id|
    unless dynamo_is_marked?(id)
      dynamo_delete_item(id)
      deleted_objects_count += 1
      @item_counter -= 1
    end
  end
  dynamo_put_item('item_counter', @item_counter.to_s)

  deleted_objects_count
end

#get_hash(name) ⇒ Hash

Load the Hash with the given name.

Parameters:

  • name (String)

    Name of the hash.

Returns:

  • (Hash)

    A Hash that maps String objects to strings or numbers.



122
123
124
125
126
127
128
# File 'lib/perobs/DynamoDB.rb', line 122

def get_hash(name)
  if (item = dynamo_get_item(name))
    JSON.parse(item)
  else
    ::Hash.new
  end
end

#get_object(id) ⇒ Hash

Load the given object from the filesystem.

Parameters:

  • id (Integer)

    object ID

Returns:

  • (Hash)

    Object as defined by PEROBS::ObjectBase or nil if ID does not exist



147
148
149
# File 'lib/perobs/DynamoDB.rb', line 147

def get_object(id)
  (item = dynamo_get_item(id.to_s)) ? deserialize(item) : nil
end

#include?(id) ⇒ Boolean

Return true if the object with given ID exists

Parameters:

  • id (Integer)

Returns:

  • (Boolean)


107
108
109
# File 'lib/perobs/DynamoDB.rb', line 107

def include?(id)
  !dynamo_get_item(id.to_s).nil?
end

#is_marked?(id) ⇒ Boolean

Check if the object is marked.

Parameters:

  • id (Integer)

    ID of the object to check

Returns:

  • (Boolean)


183
184
185
# File 'lib/perobs/DynamoDB.rb', line 183

def is_marked?(id)
  dynamo_is_marked?(id.to_s)
end

#mark(id) ⇒ Object

Mark an object.

Parameters:

  • id (Integer)

    ID of the object to mark



177
178
179
# File 'lib/perobs/DynamoDB.rb', line 177

def mark(id)
  dynamo_mark_item(id.to_s, true)
end

#put_hash(name, hash) ⇒ Object

Store a simple Hash as a JSON encoded file into the DB directory. numbers.

Parameters:

  • name (String)

    Name of the hash. Will be used as file name.

  • hash (Hash)

    A Hash that maps String objects to strings or



115
116
117
# File 'lib/perobs/DynamoDB.rb', line 115

def put_hash(name, hash)
  dynamo_put_item(name, hash.to_json)
end

#put_object(obj, id) ⇒ Object

Store the given object into the cluster files.

Parameters:

  • obj (Hash)

    Object as defined by PEROBS::ObjectBase



132
133
134
135
136
137
138
139
140
141
# File 'lib/perobs/DynamoDB.rb', line 132

def put_object(obj, id)
  id_str = id.to_s
  unless dynamo_get_item(id_str)
    # The is no object with this ID yet. Increase the item counter.
    @item_counter += 1
    dynamo_put_item('item_counter', @item_counter.to_s)
  end

  dynamo_put_item(id.to_s, serialize(obj))
end