[libvirt] Job Control, Google Summer of Code

2014-05-20 Thread Tucker DiNapoli
Hello everyone,
  My name is Tucker DiNapoli and I'm going to be working on libvirt this
summer for the google summer of code. My project is to implement job
control in the storage driver. In order to do that I am first going to
create a unified api for job control in libvirt (as it is currently
implemented seperately in both the qemu and libxl drivers). I'm currently
working on the api for job control and I have some ideas that I'll post on
the mailing list soon. If anyone has any ideas or requests re job control
I'd be happy to hear them. I'm on the #virt irc channel as tuckerD, I look
forward to working on libvrt this summer.
  Tucker Dinapoli
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] Job Control API [RFC]

2014-05-21 Thread Tucker DiNapoli
  My name is Tucker DiNapoli and I am working on implementing job control
for
the storage driver for the google summer of code, the first step in doing
this
is creating and implementing a unified api for job control.

Currently there are several places where various aspects of job control are
implemented. The qemu and libxl drivers both contain internal
implementations
for job control on domain level jobs, with the qemu driver containing
support
for asynchronous jobs. There is also code in the libvirt.c file for running
block jobs and for querying domain jobs for information.

I would like for the job control api to be as independent of different
drivers
as possible since it will need to be used with storage drivers as well as
different virtualization drivers.

I imagine most of the api will revolve around a job object, and I think it's
important to decide what exactly should go in this job object.

This is a response from my first post on the mailing list and I think this
is a
good idea.

>>I'd _really_ like to see a common notion of a 'job id' that EVERY job
>>(whether domain-level, like migration; or block-level, like
>>commit/pull/rebase; or storage-level, like your new proposed storage
>>jobs) shares a common job namespace.  The job id is a positive integer.
>> Existing APIs will have to be retrofitted into the new job id notion;
>>any action that starts a long-running job that currently returns 0 on
>>success could be changed to return a positive job id; or we may need a
>>new API that queries the notion of the 'current job' (the job most
>>recently started) or even to set the 'current job' to a different job
>>id.  We'll need new API for querying a job by id, and to be most
>>portable, we should do job reporting via virTypedParameter
>>(virDomainGetJobInfo and virDomainGetBlockJobInfo are hardcoded into
>>returning a struct, so they are non-extensible; virDomainGetJobStats
>>almost did it right, except that the user has to call it twice, once to
>>learn how large to allocate, and again to pass in pre-allocated memory -
>>the ideal API would allocate the memory on a single call).

Currently there are separate types for block job info and job info, if
possible
I would like to merge these into a common job info type, and perhaps make
this
a part of the job object itself.

Currently (in libxl and qemu) jobs are a part of the domain struct, I think
that jobs should be moved out of the domain struct instead using the idea of
job ids for domains to keep track of currently running jobs. I'm still new
to
libvirt so it this doesn't make sense and the idea of keeping job objects
attached to domains makes sense that's fine.

I think at the minimum each job object should contain: the id of the thread
running the job, the type of job, the job id, a condition variable to
coordinate jobs, and information about the job, either as a separate job
info
object or as part of the job object itself. The job should also contain a
reference to the domain or storage it is associated with.

There are a few basic functions that should definitely be part of the api:
initialize a job, free a job, start a job, end a job, abort a job and get
info
on a job. It would be nice to be able to suspend a job and to change the
currently running job as well. That's what I can come up with, but I don't
have
much experience in libvirt so if there are other features that make sense
they
can be added as well.

Finally (as far as I can think of right now) is the idea of parallel
jobs. Currently the qemu driver allows some jobs to be run in parallel by
allowing a job to be run asynchronously, this async job has a mask of job
types
associated with it that determine what types of regular jobs can be run
during
it. However I would like to allow an arbitrary number of jobs to be run at
once
(I'm not sure how useful this would be, but it seems best not to impose hard
limits on things). The easiest way to deal with this is to just ignore it
and
put the burden of synchronizing jobs on the drivers. This is obviously a bad
solution. Another way would be the way it is currently done it the qemu
driver,
have a mask of job types associated with each domain/storage which is
updated
when a job is started or ended which dictates what types of jobs can be
started. Regardless of how this is done it will require support from the
driver/domain/storage that each job is associated with.

Tucker DINapoli
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [RFC] Atomic Operations

2014-06-04 Thread Tucker DiNapoli
I'm working on job control which involves a lot of locking and unlocking,
often for operations that could be done atomically. I use the existing
atomic integer operations in viratomic.h where possible, but there are a
lot of parameters involved in jobs (such as time, thread id's, progress
information, etc) which don't fit in an integer.

I have several ideas of ways to update the existing integer atomic
operations to support more types. The easiest way (at least regarding code)
would be to use an existing atomic operations library. My suggestion would
be the libatomic_ops library, which is licensed under an MIT style license
and could be added to the source tree as a git submodule (similar to the
way gnulib is) or a specific version could be used and the library source
itself added to the git repository. The library can be found at
https://github.com/ivmai/libatomic_ops/ .

The other way of augmenting atomic operations would be to extend the
existing viratomic.h file to support additional types. Personally I have
experience working with GCC atomic operations and could implement that
myself, but I wouldn't be able to implement the windows versions.

Again I think the easiest and most maintainable way of supporting atomic
operations is via an external library, but I am not sure of the feasibility
of adding another dependency to libvirt. In general atomic operations are
an optimization, but they can help make multithreaded programming easier
and I think libvirt would be enhanced by having more comprehensive support
for atomic operations.

Tucker DiNapoli
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

[libvirt] [PATCH] Initial implementation of new job control api

2014-06-18 Thread Tucker DiNapoli
This is my initial definition of a new internal job control api. I am
working on this as a part of the google summer of code. These patches
contain the core job control api and deal only with managing individual
jobs. I am currently working on writing code using this api to manage
jobs in domains, in such a way that I will be able to replace the
current job control code in qemu and libxl. Ultimately I will use this
to implement job control in the storage driver which is my ultimate
goal for the summer of code.



---
 src/Makefile.am  |   1 +
 src/util/virjobcontrol.c | 574 +++
 src/util/virjobcontrol.h | 342 
 3 files changed, 917 insertions(+)
 create mode 100644 src/util/virjobcontrol.c
 create mode 100644 src/util/virjobcontrol.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 2b9ac61..77de0e7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -118,6 +118,7 @@ UTIL_SOURCES =  
\
util/virinitctl.c util/virinitctl.h \
util/viriptables.c util/viriptables.h   \
util/viriscsi.c util/viriscsi.h \
+   util/virjobcontrol.h util/virjobcontrol.c   \
util/virjson.c util/virjson.h   \
util/virkeycode.c util/virkeycode.h \
util/virkeyfile.c util/virkeyfile.h \
diff --git a/src/util/virjobcontrol.c b/src/util/virjobcontrol.c
new file mode 100644
index 000..04a5246
--- /dev/null
+++ b/src/util/virjobcontrol.c
@@ -0,0 +1,574 @@
+/*
+ * virjobcontrol.c Core implementation of job control
+ *
+ * Copyright (C) 2014 Tucker DiNapoli
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Author: Tucker DiNapoli
+ */
+
+#include 
+
+#include "virjobcontrol.h"
+#include "viralloc.h"
+#include "virtime.h"
+#include "virlog.h"
+VIR_LOG_INIT("virjobcontrol");
+
+VIR_ENUM_IMPL(virJob, 4,
+  "none",
+  "query",
+  "modify",
+  "destroy",
+);
+/*
+   No files other then this and virjobcontrol.c should need to
+   have access to the core implmentation of jobs. The code in these
+   files is intended to serve as a base for job control independent of
+   drivers.
+*/
+
+#define LOCK_JOB(job)   \
+virMutexLock(&job->lock)
+#define UNLOCK_JOB(job) \
+virMutexUnlock(&job->lock)
+#define LOCK_JOB_INFO(job)  \
+virMutexLock(&job->info->lock)
+#define UNLOCK_JOB_INFO(job)\
+virMutexUnlock(&job->info->lock)
+#define GET_CURRENT_TIME(time)  \
+if (virTimeMillisNow(&time) < 0) {  \
+return -1;  \
+}
+
+
+#define CHECK_FLAG_ATOMIC(job, flag) (virAtomicIntGet(&job->flags) & 
VIR_JOB_FLAG_##flag)
+#define CHECK_FLAG(job, flag) (job->flags & VIR_JOB_FLAG_##flag)
+#define SET_FLAG_ATOMIC(job, flag) (virAtomicIntOr(&job->flags, 
VIR_JOB_FLAG_##flag))
+#define SET_FLAG(job, flag) (job->flags |= VIR_JOB_FLAG_##flag)
+#define UNSET_FLAG_ATOMIC(job, flag) (virAtomicIntAnd(&job->flags, 
(~VIR_JOB_FLAG_##flag)))
+#define UNSET_FLAG(job, flag) (job->flags &= (~VIR_JOB_FLAG_##flag))
+#define CLEAR_FLAGS_ATOMIC(job) (virAtomicIntSet(&job->flags, 
VIR_JOB_FLAG_NONE))
+#define CLEAR_FLAGS(job) (job->flags = VIR_JOB_FLAG_NONE)
+
+typedef struct _jobHashEntry {
+virJobID id;
+virJobObjPtr job;
+struct _jobHashEntry *next;
+} jobHashEntry;
+
+typedef struct _jobHash {
+jobHashEntry **table;
+size_t size;
+size_t num_entries;
+virRWLock lock;
+} jobHash;
+
+/* Using this incures a cost on every call to a job control function
+   that uses the job control hash table, but it means that no one using
+   job control needs to call an initialization function to use it.
+
+   The other option would be to have a function:
+   virJobControlInit(void)
+   {
+ return virOnce(job_once, jobControlInit);
+   }
+   and require anyone using job control to call it.
+ */
+static struct _jo