1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-28 14:50:08 +03:00

Feature #3805: Implement one.document.lock in the core

This commit is contained in:
Carlos Martín 2015-05-12 12:48:59 +02:00
parent e8d5fc6f69
commit 9f21f40272
10 changed files with 405 additions and 1 deletions

View File

@ -69,6 +69,31 @@ public:
return type;
};
/**
* Tries to get the DB lock. This is a mutex requested by external
* applications, not related to the internal mutex lock. The object
* must be locked (internal memory mutex) before this method is called
*
* @param owner String to identify who requested the lock
*
* @return 0 if the lock was granted, -1 if the object is already locked
*/
int lock_db(const string& owner)
{
return PoolObjectSQL::lock_db(owner);
};
/**
* Unlocks the DB lock for external applications. The object must be locked
* (internal memory mutex) before this method is called
*
* @param owner String to identify who requested the lock
*/
void unlock_db(const string& owner)
{
return PoolObjectSQL::unlock_db(owner);
};
private:
// -------------------------------------------------------------------------
// Friends

View File

@ -117,6 +117,9 @@ public:
other_m(0),
other_a(0),
obj_template(0),
locked(false),
lock_owner(""),
lock_expires(0),
table(_table)
{
pthread_mutex_init(&mutex,0);
@ -707,6 +710,40 @@ protected:
return 0;
};
/**
* Tries to get the DB lock. This is a mutex requested by external
* applications, not related to the internal mutex lock. The object
* must be locked (internal memory mutex) before this method is called
*
* @param owner String to identify who requested the lock
*
* @return 0 if the lock was granted, -1 if the object is already locked
*/
int lock_db(const string& owner);
/**
* Unlocks the DB lock for external applications. The object must be locked
* (internal memory mutex) before this method is called
*
* @param owner String to identify who requested the lock
*/
void unlock_db(const string& owner);
/**
* Prints the lock info into a string in XML format
* @param xml the resulting XML string
* @return a reference to the generated string
*/
string& lock_db_to_xml(string& xml) const;
/**
* Rebuilds the lock info from the xml. ObjectXML::update_from_str
* must be called before this method
*
* @return 0 on success, -1 otherwise
*/
int lock_db_from_xml();
/**
* The object's unique ID
*/
@ -773,12 +810,32 @@ protected:
*/
Template * obj_template;
/**
* Flag for the DB lock
*/
bool locked;
/**
* Owner of the DB lock
*/
string lock_owner;
/**
* Expiration time for the DB lock
*/
time_t lock_expires;
private:
/**
* Characters that can not be in a name
*/
static const string INVALID_NAME_CHARS;
/**
* Expiration time for the lock stored in the DB
*/
static const int LOCK_DB_EXPIRATION;
/**
* The PoolSQL, friend to easily manipulate its Objects
*/

View File

@ -268,6 +268,14 @@ protected:
*/
void success_response(const string& val, RequestAttributes& att);
/**
* Builds an XML-RPC response updating retval. After calling this function
* the xml-rpc execute method should return
* @param val to be returned to the client
* @param att the specific request attributes
*/
void success_response(bool val, RequestAttributes& att);
/**
* Builds an XML-RPC response updating retval. After calling this function
* the xml-rpc excute method should return

View File

@ -0,0 +1,122 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs */
/* */
/* 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. */
/* -------------------------------------------------------------------------- */
#ifndef REQUEST_MANAGER_LOCK_H_
#define REQUEST_MANAGER_LOCK_H_
#include "Request.h"
#include "Nebula.h"
using namespace std;
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class RequestManagerLock: public Request
{
protected:
RequestManagerLock(const string& method_name,
const string& help)
:Request(method_name, "A:sis", help)
{
auth_op = AuthRequest::MANAGE;
};
~RequestManagerLock(){};
/* -------------------------------------------------------------------- */
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
virtual int lock_db(PoolObjectSQL * object, const string& owner) = 0;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class RequestManagerUnlock: public Request
{
protected:
RequestManagerUnlock(const string& method_name,
const string& help)
:Request(method_name, "A:sis", help)
{
auth_op = AuthRequest::MANAGE;
};
~RequestManagerUnlock(){};
/* -------------------------------------------------------------------- */
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
virtual void unlock_db(PoolObjectSQL * object, const string& owner) = 0;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class DocumentLock : public RequestManagerLock
{
public:
DocumentLock():
RequestManagerLock("DocumentLock",
"Tries to acquire the object's lock")
{
Nebula& nd = Nebula::instance();
pool = nd.get_docpool();
auth_object = PoolObjectSQL::DOCUMENT;
};
~DocumentLock(){};
int lock_db(PoolObjectSQL * object, const string& owner)
{
return static_cast<Document*>(object)->lock_db(owner);
};
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class DocumentUnlock : public RequestManagerUnlock
{
public:
DocumentUnlock():
RequestManagerUnlock("DocumentUnlock",
"Unlocks the object")
{
Nebula& nd = Nebula::instance();
pool = nd.get_docpool();
auth_object = PoolObjectSQL::DOCUMENT;
};
~DocumentUnlock(){};
void unlock_db(PoolObjectSQL * object, const string& owner)
{
return static_cast<Document*>(object)->unlock_db(owner);
};
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
#endif

View File

@ -191,6 +191,7 @@ string& Document::to_xml(string& xml) const
ostringstream oss;
string template_xml;
string perm_str;
string lock_str;
oss << "<DOCUMENT>"
<< "<ID>" << oid << "</ID>"
@ -201,6 +202,7 @@ string& Document::to_xml(string& xml) const
<< "<NAME>" << name << "</NAME>"
<< "<TYPE>" << type << "</TYPE>"
<< perms_to_xml(perm_str)
<< lock_db_to_xml(lock_str)
<< obj_template->to_xml(template_xml)
<< "</DOCUMENT>";
@ -232,6 +234,9 @@ int Document::from_xml(const string& xml)
// Permissions
rc += perms_from_xml();
// Lock info
rc += lock_db_from_xml();
// Get associated classes
ObjectXML::get_nodes("/DOCUMENT/TEMPLATE", content);

View File

@ -22,6 +22,8 @@
const string PoolObjectSQL::INVALID_NAME_CHARS = "&|:\\\";/'#{}$<>";
const int PoolObjectSQL::LOCK_DB_EXPIRATION = 120;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -481,3 +483,67 @@ bool PoolObjectSQL::name_is_valid(const string& obj_name,
return true;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int PoolObjectSQL::lock_db(const string& owner)
{
if (locked && time(0) < lock_expires)
{
return -1;
}
locked = true;
lock_expires = time(0) + LOCK_DB_EXPIRATION;
lock_owner = owner;
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void PoolObjectSQL::unlock_db(const string& owner)
{
// Check if owner == lock_owner?
locked = false;
lock_expires = 0;
lock_owner = "";
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string& PoolObjectSQL::lock_db_to_xml(string& xml) const
{
ostringstream oss;
int locked_int = locked ? 1 : 0;
oss << "<LOCK>"
<< "<LOCKED>" << locked_int << "</LOCKED>"
<< "<OWNER><![CDATA[" << lock_owner << "]]></OWNER>"
<< "<EXPIRES>" << lock_expires << "</EXPIRES>"
<< "</LOCK>";
xml = oss.str();
return xml;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int PoolObjectSQL::lock_db_from_xml()
{
int rc = 0;
int locked_int;
rc += xpath(locked_int, "/*/LOCK/LOCKED", 0);
rc += xpath(lock_owner, "/*/LOCK/OWNER", "");
rc += xpath(lock_expires, "/*/LOCK/EXPIRES", 0);
locked = locked_int;
return rc;
}

View File

@ -573,6 +573,23 @@ void Request::success_response(const string& val, RequestAttributes& att)
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void Request::success_response(bool val, RequestAttributes& att)
{
vector<xmlrpc_c::value> arrayData;
arrayData.push_back(xmlrpc_c::value_boolean(true));
arrayData.push_back(xmlrpc_c::value_boolean(val));
arrayData.push_back(xmlrpc_c::value_int(SUCCESS));
xmlrpc_c::value_array arrayresult(arrayData);
*(att.retval) = arrayresult;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string Request::object_name(PoolObjectSQL::ObjectType ob)
{
switch (ob)

View File

@ -27,6 +27,7 @@
#include "RequestManagerChmod.h"
#include "RequestManagerClone.h"
#include "RequestManagerRename.h"
#include "RequestManagerLock.h"
#include "RequestManagerVirtualNetwork.h"
#include "RequestManagerVirtualMachine.h"
@ -368,6 +369,10 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr doc_info(new DocumentInfo());
xmlrpc_c::methodPtr secg_info(new SecurityGroupInfo());
// Lock Methods
xmlrpc_c::methodPtr doc_lock(new DocumentLock());
xmlrpc_c::methodPtr doc_unlock(new DocumentUnlock());
// PoolInfo Methods
xmlrpc_c::methodPtr hostpool_info(new HostPoolInfo());
xmlrpc_c::methodPtr datastorepool_info(new DatastorePoolInfo());
@ -706,7 +711,9 @@ void RequestManager::register_xml_methods()
RequestManagerRegistry.addMethod("one.document.chown", doc_chown);
RequestManagerRegistry.addMethod("one.document.chmod", doc_chmod);
RequestManagerRegistry.addMethod("one.document.clone", doc_clone);
RequestManagerRegistry.addMethod("one.document.rename", doc_rename);
RequestManagerRegistry.addMethod("one.document.rename", doc_rename);
RequestManagerRegistry.addMethod("one.document.lock", doc_lock);
RequestManagerRegistry.addMethod("one.document.unlock", doc_unlock);
RequestManagerRegistry.addMethod("one.documentpool.info",docpool_info);

View File

@ -0,0 +1,96 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs */
/* */
/* 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. */
/* -------------------------------------------------------------------------- */
#include "RequestManagerLock.h"
using namespace std;
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
void RequestManagerLock::request_execute(xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
int oid = xmlrpc_c::value_int(paramList.getInt(1));
string owner = xmlrpc_c::value_string(paramList.getString(2));
PoolObjectSQL * object;
string error_str;
int rc;
if ( basic_authorization(oid, att) == false )
{
return;
}
object = pool->get(oid,true);
if ( object == 0 )
{
failure_response(NO_EXISTS,
get_error(object_name(auth_object),oid),
att);
return;
}
rc = lock_db(object, owner);
pool->update(object);
object->unlock();
success_response((rc == 0), att);
return;
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
void RequestManagerUnlock::request_execute(xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
int oid = xmlrpc_c::value_int(paramList.getInt(1));
string owner = xmlrpc_c::value_string(paramList.getString(2));
PoolObjectSQL * object;
string error_str;
if ( basic_authorization(oid, att) == false )
{
return;
}
object = pool->get(oid,true);
if ( object == 0 )
{
failure_response(NO_EXISTS,
get_error(object_name(auth_object),oid),
att);
return;
}
unlock_db(object, owner);
pool->update(object);
object->unlock();
success_response(oid, att);
return;
}

View File

@ -46,6 +46,7 @@ source_files=[
'RequestManagerProxy.cc',
'RequestManagerVdc.cc',
'RequestManagerDatastore.cc',
'RequestManagerLock.cc',
]
# Build library