This patch implements the virDomainSaveJob method for the
test driver as a proof of concept. First of all it adds a
inJob flag to the testDom and testNet objects. This is to
make sure that operations which may change an objects run
state are rejected, if a background job is active.
Then it merely implements the virDomainSaveJob method as
per the previous description. Actually it doesn't really
do any save operation, this impl just illustrates the way
progress updates propagate back to the caller, and the use
of cancellation.
test.c | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 116 insertions(+), 3 deletions(-)
Dan.
diff -r 356d3624723c src/test.c
--- a/src/test.c Fri Jan 04 18:22:17 2008 -0500
+++ b/src/test.c Fri Jan 04 18:24:56 2008 -0500
@@ -72,6 +72,28 @@ typedef enum {
VIR_DOMAIN_RENAME_RESTART= 4/* restart under an new unique name */
} virDomainRestart;
+typedef enum {
+ TEST_JOB_INACTIVE = 0,
+ TEST_JOB_DOMAIN_START = 1,
+ TEST_JOB_DOMAIN_SAVE = 2,
+ TEST_JOB_DOMAIN_RESTORE = 3,
+ TEST_JOB_DOMAIN_CORE = 4,
+ TEST_JOB_NETWORK_START = 5,
+} testJobType;
+
+typedef struct _testJob testJob;
+typedef struct _testJob *testJobPtr;
+
+struct _testJob {
+ int type;
+ union {
+ struct {
+ int domidx;
+ char *path;
+ } save;
+ } data;
+};
+
struct _testDev {
char name[20];
int mode;
@@ -82,6 +104,7 @@ typedef struct _testDev *testDevPtr;
#define MAX_DEVICES 10
struct _testDom {
+ int inJob;
int active;
int config;
int id;
@@ -102,6 +125,7 @@ typedef struct _testDom *testDomPtr;
typedef struct _testDom *testDomPtr;
struct _testNet {
+ int inJob;
int active;
int config;
int running;
@@ -209,6 +233,20 @@ static const virNodeInfo defaultNodeInfo
/* To be called after GET_DOMAIN */
#define RELEASE_DOMAIN() \
pthread_mutex_unlock(&privconn->lock)
+
+#define CHECK_DOMAIN_JOB_INACTIVE(dom, ret) \
+ if (privdom->inJob) { \
+ testError((dom)->conn, (dom), NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); \
+ RELEASE_DOMAIN(); \
+ return (ret); \
+ }
+
+#define CHECK_NETWORK_JOB_INACTIVE(net, ret) \
+ if (privnet->inJob) { \
+ testError((net)->conn, NULL, (net), VIR_ERR_INVALID_ARG, __FUNCTION__); \
+ RELEASE_NETWORK(); \
+ return (ret); \
+ }
static void
@@ -1234,6 +1272,7 @@ static int testDestroyDomain (virDomainP
static int testDestroyDomain (virDomainPtr domain)
{
GET_DOMAIN(domain, -1);
+ CHECK_DOMAIN_JOB_INACTIVE(domain, -1);
if (privdom->config) {
privdom->info.state = VIR_DOMAIN_SHUTOFF;
@@ -1249,6 +1288,7 @@ static int testResumeDomain (virDomainPt
static int testResumeDomain (virDomainPtr domain)
{
GET_DOMAIN(domain, -1);
+ CHECK_DOMAIN_JOB_INACTIVE(domain, -1);
if (privdom->info.state != VIR_DOMAIN_PAUSED) {
testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "domain not
paused");
@@ -1264,6 +1304,7 @@ static int testPauseDomain (virDomainPtr
static int testPauseDomain (virDomainPtr domain)
{
GET_DOMAIN(domain, -1);
+ CHECK_DOMAIN_JOB_INACTIVE(domain, -1);
if (privdom->info.state == VIR_DOMAIN_SHUTOFF ||
privdom->info.state == VIR_DOMAIN_PAUSED) {
@@ -1280,6 +1321,7 @@ static int testShutdownDomain (virDomain
static int testShutdownDomain (virDomainPtr domain)
{
GET_DOMAIN(domain, -1);
+ CHECK_DOMAIN_JOB_INACTIVE(domain, -1);
if (privdom->info.state == VIR_DOMAIN_SHUTOFF) {
testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR, "domain not
running");
@@ -1298,6 +1340,7 @@ static int testRebootDomain (virDomainPt
static int testRebootDomain (virDomainPtr domain, virDomainRestart action)
{
GET_DOMAIN(domain, -1);
+ CHECK_DOMAIN_JOB_INACTIVE(domain, -1);
if (!action)
action = VIR_DOMAIN_RESTART;
@@ -1369,6 +1412,7 @@ static int testDomainSave(virDomainPtr d
char *xml;
int fd, len;
GET_DOMAIN(domain, -1);
+ CHECK_DOMAIN_JOB_INACTIVE(domain, -1);
xml = testDomainDumpXMLLocked(domain, privdom, 0);
@@ -1418,6 +1462,69 @@ static int testDomainSave(virDomainPtr d
return 0;
}
+static void testDomainSaveWorker(virJobPtr job, void *data)
+{
+ testJobPtr jobInfo = data;
+ int countdown = 50;
+ virJobInitialize(job, countdown);
+
+ do {
+ sleep(1);
+
+ if (virJobFinishCancel(job))
+ return;
+
+ virJobUpdateRel(job, 1, -1, 2);
+ } while (countdown--);
+
+ if (jobInfo)
+ jobInfo = jobInfo;
+
+ virJobFinishSuccess(job);
+}
+
+static virJobPtr testDomainSaveJob(virDomainPtr domain,
+ const char *path)
+{
+ virJobPtr job;
+ testJobPtr privjob;
+ GET_DOMAIN(domain, NULL);
+ CHECK_DOMAIN_JOB_INACTIVE(domain, NULL);
+
+ privjob = malloc(sizeof(*privjob));
+ if (privjob == NULL) {
+ testError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY, "job");
+ RELEASE_DOMAIN();
+ return (NULL);
+ }
+ memset(privjob, 0, sizeof(*privjob));
+
+ privjob->type = TEST_JOB_DOMAIN_SAVE;
+ privjob->data.save.domidx = domidx;
+ privjob->data.save.path = strdup(path);
+ if (privjob->data.save.path == NULL) {
+ testError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY, "job");
+ goto cleanup;
+ }
+
+ job = virJobCreate(domain->conn,
+ domain->conn->driver->jobDriver,
+ testDomainSaveWorker,
+ NULL,
+ privjob,
+ VIR_JOB_BOUNDED);
+
+ RELEASE_DOMAIN();
+
+ return job;
+
+ cleanup:
+ if (privjob->data.save.path) free(privjob->data.save.path);
+ free(privjob);
+ RELEASE_DOMAIN();
+ return (NULL);
+}
+
static int testDomainRestore(virConnectPtr conn,
const char *path)
@@ -1490,6 +1597,7 @@ static int testDomainCoreDump(virDomainP
{
int fd;
GET_DOMAIN(domain, -1);
+ CHECK_DOMAIN_JOB_INACTIVE(domain, -1);
if ((fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR)) < 0) {
testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
@@ -1680,6 +1788,7 @@ static virDomainPtr testDomainDefineXML(
static int testDomainCreate(virDomainPtr domain) {
GET_DOMAIN(domain, -1);
+ CHECK_DOMAIN_JOB_INACTIVE(domain, -1);
if (privdom->info.state != VIR_DOMAIN_SHUTOFF) {
testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
@@ -1697,6 +1806,7 @@ static int testDomainCreate(virDomainPtr
static int testDomainUndefine(virDomainPtr domain) {
GET_DOMAIN(domain, -1);
+ CHECK_DOMAIN_JOB_INACTIVE(domain, -1);
if (privdom->info.state != VIR_DOMAIN_SHUTOFF) {
testError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
@@ -1979,6 +2089,7 @@ static virNetworkPtr testNetworkDefine(v
static int testNetworkUndefine(virNetworkPtr network) {
GET_NETWORK(network, -1);
+ CHECK_NETWORK_JOB_INACTIVE(network, -1);
if (privnet->running) {
testError(network->conn, NULL, network, VIR_ERR_INTERNAL_ERROR,
@@ -1995,6 +2106,7 @@ static int testNetworkUndefine(virNetwor
static int testNetworkStart(virNetworkPtr network) {
GET_NETWORK(network, -1);
+ CHECK_NETWORK_JOB_INACTIVE(network, -1);
if (privnet->running) {
testError(network->conn, NULL, network, VIR_ERR_INTERNAL_ERROR,
@@ -2011,6 +2123,7 @@ static int testNetworkStart(virNetworkPt
static int testNetworkDestroy(virNetworkPtr network) {
GET_NETWORK(network, -1);
+ CHECK_NETWORK_JOB_INACTIVE(network, -1);
if (privnet->config) {
privnet->running = 0;
@@ -2098,7 +2211,7 @@ static virDriver testDriver = {
VIR_DRV_TEST,
"Test",
LIBVIR_VERSION_NUMBER,
- NULL, /* jobDriver */
+ &defaultJobDriver, /* jobDriver */
testOpen, /* open */
testClose, /* close */
NULL, /* supports_feature */
@@ -2127,7 +2240,7 @@ static virDriver testDriver = {
testSetMemory, /* domainSetMemory */
testGetDomainInfo, /* domainGetInfo */
testDomainSave, /* domainSave */
- NULL, /* domainSaveJob */
+ testDomainSaveJob, /* domainSaveJob */
testDomainRestore, /* domainRestore */
NULL, /* domainRestoreJob */
testDomainCoreDump, /* domainCoreDump */
@@ -2161,7 +2274,7 @@ static virDriver testDriver = {
static virNetworkDriver testNetworkDriver = {
"Test",
- NULL, /* jobDriver */
+ &defaultJobDriver, /* jobDriver */
testOpenNetwork, /* open */
testCloseNetwork, /* close */
testNumNetworks, /* numOfNetworks */
--
|=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=|
|=- Perl modules:
http://search.cpan.org/~danberr/ -=|
|=- Projects:
http://freshmeat.net/~danielpb/ -=|
|=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|