Module: VCAP::Services::Base::AsyncJob::Snapshot
- Includes:
- Error
- Included in:
- VCAP::Services::Base::AsyncJob::Serialization::SerializationJob, SnapshotJob, Provisioner
- Defined in:
- lib/base/job/snapshot.rb
Defined Under Namespace
Classes: BaseCreateSnapshotJob, BaseDeleteSnapshotJob, BaseRollbackSnapshotJob, SnapshotJob
Constant Summary collapse
- SNAPSHOT_KEY_PREFIX =
"vcap:snapshot".freeze
- SNAPSHOT_ID =
"maxid".freeze
- FILTER_KEYS =
%w(snapshot_id date size name).freeze
- MAX_NAME_LENGTH =
512
Class Attribute Summary collapse
-
.redis ⇒ Object
readonly
Returns the value of attribute redis.
Class Method Summary collapse
- .redis_connect ⇒ Object
-
.redis_init ⇒ Object
initialize necessary keys.
Instance Method Summary collapse
- #client ⇒ Object
- #delete_snapshot(service_id, snapshot_id) ⇒ Object
-
#filter_keys(snapshot) ⇒ Object
filter internal keys of a given snapshot object, return a new snapshot object in canonical format.
- #fmt_time ⇒ Object
-
#new_snapshot_id ⇒ Object
Generate a new unique id for a snapshot.
- #save_snapshot(service_id, snapshot) ⇒ Object
-
#service_snapshots(service_id) ⇒ Object
Get all snapshots related to a service instance.
-
#service_snapshots_count(service_id) ⇒ Object
Return total snapshots count.
-
#snapshot_details(service_id, snapshot_id) ⇒ Object
Get detail information for a single snapshot.
-
#snapshot_filepath(base_dir, service_name, service_id, snapshot_id) ⇒ Object
Get the snapshot file path that service should save the dump file to.
-
#update_name(service_id, snapshot_id, name) ⇒ Object
Update the name of given snapshot.
Methods included from Error
#failure, #internal_fail, #parse_msg, #success, #timeout_fail
Class Attribute Details
.redis ⇒ Object (readonly)
Returns the value of attribute redis.
18 19 20 |
# File 'lib/base/job/snapshot.rb', line 18 def redis @redis end |
Class Method Details
.redis_connect ⇒ Object
20 21 22 23 24 |
# File 'lib/base/job/snapshot.rb', line 20 def redis_connect @redis = ::Redis.new(Config.redis_config) redis_init end |
.redis_init ⇒ Object
initialize necessary keys
27 28 29 |
# File 'lib/base/job/snapshot.rb', line 27 def redis_init @redis.setnx("#{SNAPSHOT_KEY_PREFIX}:#{SNAPSHOT_ID}", 1) end |
Instance Method Details
#client ⇒ Object
32 33 34 |
# File 'lib/base/job/snapshot.rb', line 32 def client Snapshot.redis end |
#delete_snapshot(service_id, snapshot_id) ⇒ Object
112 113 114 115 |
# File 'lib/base/job/snapshot.rb', line 112 def delete_snapshot(service_id , snapshot_id) return unless service_id && snapshot_id client.hdel(redis_key(service_id), snapshot_id) end |
#filter_keys(snapshot) ⇒ Object
filter internal keys of a given snapshot object, return a new snapshot object in canonical format
61 62 63 64 |
# File 'lib/base/job/snapshot.rb', line 61 def filter_keys(snapshot) return unless snapshot.is_a? Hash snapshot.select {|k,v| FILTER_KEYS.include? k.to_s} end |
#fmt_time ⇒ Object
118 119 120 121 |
# File 'lib/base/job/snapshot.rb', line 118 def fmt_time() # UTC time in ISO 8601 format. Time.now.utc.strftime("%FT%TZ") end |
#new_snapshot_id ⇒ Object
Generate a new unique id for a snapshot
67 68 69 |
# File 'lib/base/job/snapshot.rb', line 67 def new_snapshot_id client.incr(redis_key(SNAPSHOT_ID)).to_s end |
#save_snapshot(service_id, snapshot) ⇒ Object
105 106 107 108 109 110 |
# File 'lib/base/job/snapshot.rb', line 105 def save_snapshot(service_id , snapshot) return unless service_id && snapshot sid = snapshot[:snapshot_id] || snapshot["snapshot_id"] msg = Yajl::Encoder.encode(snapshot) client.hset(redis_key(service_id), sid, msg) end |
#service_snapshots(service_id) ⇒ Object
Get all snapshots related to a service instance
38 39 40 41 42 |
# File 'lib/base/job/snapshot.rb', line 38 def service_snapshots(service_id) return unless service_id res = client.hgetall(redis_key(service_id)) res.values.map{|v| Yajl::Parser.parse(v)} end |
#service_snapshots_count(service_id) ⇒ Object
Return total snapshots count
46 47 48 49 |
# File 'lib/base/job/snapshot.rb', line 46 def service_snapshots_count(service_id) return unless service_id client.hlen(redis_key(service_id)) end |
#snapshot_details(service_id, snapshot_id) ⇒ Object
Get detail information for a single snapshot
53 54 55 56 57 58 |
# File 'lib/base/job/snapshot.rb', line 53 def snapshot_details(service_id, snapshot_id) return unless service_id && snapshot_id res = client.hget(redis_key(service_id), snapshot_id) raise ServiceError.new(ServiceError::NOT_FOUND, "snapshot #{snapshot_id}") unless res Yajl::Parser.parse(res) end |
#snapshot_filepath(base_dir, service_name, service_id, snapshot_id) ⇒ Object
Get the snapshot file path that service should save the dump file to. the snapshot path structure looks like <base_dir>snapshots<service-name><aa><bb><cc><aabbcc-rest-of-instance-guid>snapshot_id<service specific data>
73 74 75 |
# File 'lib/base/job/snapshot.rb', line 73 def snapshot_filepath(base_dir, service_name, service_id, snapshot_id) File.join(base_dir, "snapshots", service_name, service_id[0,2], service_id[2,2], service_id[4,2], service_id, snapshot_id.to_s) end |
#update_name(service_id, snapshot_id, name) ⇒ Object
Update the name of given snapshot. This function is not protected by redis lock so a optimistic lock is applied to prevent concurrent update.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/base/job/snapshot.rb', line 81 def update_name(service_id, snapshot_id, name) return unless service_id && snapshot_id && name verify_input_name(name) key = redis_key(service_id) # NOTE: idealy should watch on combination of (service_id, snapshot_id) # but current design doesn't support such fine-grained watching. client.watch(key) snapshot = client.hget(redis_key(service_id), snapshot_id) return nil unless snapshot snapshot = Yajl::Parser.parse(snapshot) snapshot["name"] = name res = client.multi do save_snapshot(service_id, snapshot) end unless res raise ServiceError.new(ServiceError::REDIS_CONCURRENT_UPDATE) end true end |