diff --git a/include/Image.h b/include/Image.h index 0cc7bf1c8e..4206f48b93 100644 --- a/include/Image.h +++ b/include/Image.h @@ -292,14 +292,24 @@ public: return cloning_ops; } - int dec_cloning() + int dec_cloning(int img_id) { - return --cloning_ops; + if ( img_clone_collection.del_collection_id(img_id) == 0 ) + { + cloning_ops--; + } + + return cloning_ops; } - int inc_cloning() + int inc_cloning(int img_id) { - return ++cloning_ops; + if ( img_clone_collection.add_collection_id(img_id) == 0 ) + { + cloning_ops++; + } + + return cloning_ops; } /** @@ -553,6 +563,11 @@ private: */ ObjectCollection vm_collection; + /** + * Stores a collection with the Images cloning this image + */ + ObjectCollection img_clone_collection; + // ************************************************************************* // DataBase implementation (Private) // ************************************************************************* diff --git a/include/ImageManager.h b/include/ImageManager.h index 48fa547c6c..91e02129e8 100644 --- a/include/ImageManager.h +++ b/include/ImageManager.h @@ -107,8 +107,9 @@ public: /** * Closes any cloning operation on the image, updating the state if needed * @param iid image id of the image to be released + * @param clone_img_id image id of the image that was being cloned */ - void release_cloning_image(int iid); + void release_cloning_image(int iid, int clone_img_id); /** * Enables the image diff --git a/install.sh b/install.sh index 116dd0ebf3..b8f8aad8c3 100755 --- a/install.sh +++ b/install.sh @@ -1001,6 +1001,7 @@ ONEDB_MIGRATOR_FILES="src/onedb/2.0_to_2.9.80.rb \ src/onedb/3.6.0_to_3.7.80.rb \ src/onedb/3.7.80_to_3.8.0.rb \ src/onedb/3.8.0_to_3.8.1.rb \ + src/onedb/3.8.1_to_3.9.80.rb \ src/onedb/fsck.rb \ src/onedb/onedb.rb \ src/onedb/onedb_backend.rb" diff --git a/share/doc/xsd/image.xsd b/share/doc/xsd/image.xsd index e5dc49fe12..72a5eb7bf2 100644 --- a/share/doc/xsd/image.xsd +++ b/share/doc/xsd/image.xsd @@ -57,6 +57,13 @@ + + + + + + + diff --git a/src/image/Image.cc b/src/image/Image.cc index 3c45772b2b..0d4fb7baa1 100644 --- a/src/image/Image.cc +++ b/src/image/Image.cc @@ -53,7 +53,8 @@ Image::Image(int _uid, cloning_id(-1), ds_id(-1), ds_name(""), - vm_collection("VMS") + vm_collection("VMS"), + img_clone_collection("CLONES") { if (_image_template != 0) { @@ -318,6 +319,7 @@ string& Image::to_xml(string& xml) const string perms_xml; ostringstream oss; string vm_collection_xml; + string clone_collection_xml; oss << "" << @@ -343,6 +345,7 @@ string& Image::to_xml(string& xml) const "" << ds_id << ""<< "" << ds_name << "" << vm_collection.to_xml(vm_collection_xml) << + img_clone_collection.to_xml(clone_collection_xml) << obj_template->to_xml(template_xml) << ""; @@ -427,6 +430,21 @@ int Image::from_xml(const string& xml) ObjectXML::free_nodes(content); + + content.clear(); + + ObjectXML::get_nodes("/IMAGE/CLONES", content); + + if (content.empty()) + { + return -1; + } + + rc += img_clone_collection.from_xml_node(content[0]); + + ObjectXML::free_nodes(content); + + if (rc != 0) { return -1; diff --git a/src/image/ImageManagerActions.cc b/src/image/ImageManagerActions.cc index 2ec9a56781..a6dba546a5 100644 --- a/src/image/ImageManagerActions.cc +++ b/src/image/ImageManagerActions.cc @@ -225,7 +225,7 @@ void ImageManager::release_image(int vm_id, int iid, bool failed) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void ImageManager::release_cloning_image(int iid) +void ImageManager::release_cloning_image(int iid, int clone_img_id) { Image * img; @@ -238,24 +238,18 @@ void ImageManager::release_cloning_image(int iid) return; } + int cloning = img->dec_cloning(clone_img_id); + switch (img->get_state()) { - case Image::CLONE: - img->dec_cloning(); - img->set_state(Image::READY); - - ipool->update(img); - img->unlock(); - break; - case Image::USED: - if ( img->dec_cloning() == 0 && img->get_running() == 0 ) + case Image::CLONE: + + if ( cloning == 0 && img->get_running() == 0 ) { img->set_state(Image::READY); } - ipool->update(img); - img->unlock(); break; case Image::DELETE: @@ -275,6 +269,9 @@ void ImageManager::release_cloning_image(int iid) img->unlock(); break; } + + ipool->update(img); + img->unlock(); } /* -------------------------------------------------------------------------- */ @@ -439,7 +436,7 @@ int ImageManager::delete_image(int iid, const string& ds_data) if ( cloning_id != -1 ) { - release_cloning_image(cloning_id); + release_cloning_image(cloning_id, iid); } return 0; @@ -524,7 +521,7 @@ int ImageManager::clone_image(int new_id, switch(img->get_state()) { case Image::READY: - img->inc_cloning(); + img->inc_cloning(new_id); if (img->isPersistent()) { @@ -541,7 +538,7 @@ int ImageManager::clone_image(int new_id, break; case Image::USED: - img->inc_cloning(); + img->inc_cloning(new_id); ipool->update(img); diff --git a/src/image/ImageManagerDriver.cc b/src/image/ImageManagerDriver.cc index f0c07900cb..da7a6bb1e3 100644 --- a/src/image/ImageManagerDriver.cc +++ b/src/image/ImageManagerDriver.cc @@ -279,7 +279,7 @@ static void clone_action(istringstream& is, NebulaLog::log("ImM", Log::INFO, "Image cloned and ready to use."); - im ->release_cloning_image(cloning_id); + im->release_cloning_image(cloning_id, id); return; @@ -304,7 +304,7 @@ error: image->unlock(); - im ->release_cloning_image(cloning_id); + im->release_cloning_image(cloning_id, id); return; } diff --git a/src/onedb/3.8.1_to_3.9.80.rb b/src/onedb/3.8.1_to_3.9.80.rb new file mode 100644 index 0000000000..2ccf5e7a5d --- /dev/null +++ b/src/onedb/3.8.1_to_3.9.80.rb @@ -0,0 +1,105 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +require 'set' +require "rexml/document" +include REXML + +module Migrator + def db_version + "3.9.80" + end + + def one_version + "OpenNebula 3.9.80" + end + + def up + + ######################################################################## + # Add Cloning Image ID collection to Images + ######################################################################## + + counters = {} + counters[:image] = {} + + # Init image counters + @db.fetch("SELECT oid,body FROM image_pool") do |row| + if counters[:image][row[:oid]].nil? + counters[:image][row[:oid]] = { + :clones => Set.new + } + end + + doc = Document.new(row[:body]) + + doc.root.each_element("CLONING_ID") do |e| + img_id = e.text.to_i + + if counters[:image][img_id].nil? + counters[:image][img_id] = { + :clones => Set.new + } + end + + counters[:image][img_id][:clones].add(row[:oid]) + end + end + + ######################################################################## + # Image + # + # IMAGE/CLONING_OPS + # IMAGE/CLONES/ID + ######################################################################## + + @db.run "CREATE TABLE image_pool_new (oid INTEGER PRIMARY KEY, name VARCHAR(128), body TEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, UNIQUE(name,uid) );" + + @db[:image_pool].each do |row| + doc = Document.new(row[:body]) + + oid = row[:oid] + + n_cloning_ops = counters[:image][oid][:clones].size + + # Rewrite number of clones + doc.root.each_element("CLONING_OPS") { |e| + if e.text != n_cloning_ops.to_s + warn("Image #{oid} CLONING_OPS has #{e.text} \tis\t#{n_cloning_ops}") + e.text = n_cloning_ops + end + } + + # re-do list of Images cloning this one + clones_new_elem = doc.root.add_element("CLONES") + + counters[:image][oid][:clones].each do |id| + clones_new_elem.add_element("ID").text = id.to_s + end + + row[:body] = doc.to_s + + # commit + @db[:image_pool_new].insert(row) + end + + # Rename table + @db.run("DROP TABLE image_pool") + @db.run("ALTER TABLE image_pool_new RENAME TO image_pool") + + return true + end +end diff --git a/src/onedb/fsck.rb b/src/onedb/fsck.rb index 35960a0596..7c9b222b7b 100644 --- a/src/onedb/fsck.rb +++ b/src/onedb/fsck.rb @@ -21,11 +21,11 @@ require 'set' module OneDBFsck def db_version - "3.8.1" + "4.0.0" end def one_version - "OpenNebula 3.8.1" + "OpenNebula 4.0.0" end IMAGE_STATES=%w{INIT READY USED DISABLED LOCKED ERROR CLONE DELETE USED_PERS} @@ -530,8 +530,6 @@ module OneDBFsck counters[:image] = {} counters[:vnet] = {} - cloning_ops = {} - # Initialize all the host counters to 0 @db.fetch("SELECT oid FROM host_pool") do |row| counters[:host][row[:oid]] = { @@ -543,18 +541,26 @@ module OneDBFsck # Init image counters @db.fetch("SELECT oid,body FROM image_pool") do |row| - counters[:image][row[:oid]] = Set.new + if counters[:image][row[:oid]].nil? + counters[:image][row[:oid]] = { + :vms => Set.new, + :clones => Set.new + } + end doc = Document.new(row[:body]) - cloning_ops[row[:oid]] = [] if cloning_ops[row[:oid]].nil? - doc.root.each_element("CLONING_ID") do |e| img_id = e.text.to_i - - cloning_ops[img_id] = [] if cloning_ops[img_id].nil? - cloning_ops[img_id] << row[:oid] + if counters[:image][img_id].nil? + counters[:image][img_id] = { + :vms => Set.new, + :clones => Set.new + } + end + + counters[:image][img_id][:clones].add(row[:oid]) end end @@ -584,7 +590,7 @@ module OneDBFsck if counters[:image][img_id].nil? log_error("VM #{row[:oid]} is using Image #{img_id}, but it does not exist") else - counters[:image][img_id].add(row[:oid]) + counters[:image][img_id][:vms].add(row[:oid]) end end @@ -733,6 +739,8 @@ module OneDBFsck # IMAGE/VMS/ID # # IMAGE/CLONING_OPS + # IMAGE/CLONES/ID + # # IMAGE/CLONING_ID # # IMAGE/STATE @@ -750,8 +758,8 @@ module OneDBFsck persistent = ( doc.root.get_text('PERSISTENT').to_s == "1" ) current_state = doc.root.get_text('STATE').to_s.to_i - rvms = counters[:image][oid].size - n_cloning_ops = cloning_ops[row[:oid]].size + rvms = counters[:image][oid][:vms].size + n_cloning_ops = counters[:image][oid][:clones].size # rewrite running_vms doc.root.each_element("RUNNING_VMS") {|e| @@ -766,7 +774,7 @@ module OneDBFsck vms_new_elem = doc.root.add_element("VMS") - counters[:image][oid].each do |id| + counters[:image][oid][:vms].each do |id| id_elem = vms_elem.elements.delete("ID[.=#{id}]") if id_elem.nil? @@ -783,6 +791,7 @@ module OneDBFsck if ( persistent && rvms > 0 ) n_cloning_ops = 0 + counters[:image][oid][:clones] = Set.new end # Check number of clones @@ -793,6 +802,26 @@ module OneDBFsck end } + # re-do list of Images cloning this one + clones_elem = doc.root.elements.delete("CLONES") + + clones_new_elem = doc.root.add_element("CLONES") + + counters[:image][oid][:clones].each do |id| + id_elem = clones_elem.elements.delete("ID[.=#{id}]") + + if id_elem.nil? + log_error("Image #{id} is missing fom Image #{oid} CLONES id list") + end + + clones_new_elem.add_element("ID").text = id.to_s + end + + clones_elem.each_element("ID") do |id_elem| + log_error("Image #{id_elem.text} is in Image #{oid} CLONES id list, but it should not") + end + + # Check state state = current_state