All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Daniel P. Berrange" <berrange@redhat.com>
To: Max Reitz <mreitz@redhat.com>
Cc: "Paolo Bonzini" <pbonzini@redhat.com>,
	qemu-devel@nongnu.org, "Andreas Färber" <afaerber@suse.de>,
	"Markus Armbruster" <armbru@redhat.com>
Subject: Re: [Qemu-devel] [PATCH v1 01/10] qdict: implement a qdict_crumple method for un-flattening a dict
Date: Mon, 7 Mar 2016 15:06:29 +0000	[thread overview]
Message-ID: <20160307150629.GD13034@redhat.com> (raw)
In-Reply-To: <56DAF82F.8060401@redhat.com>

On Sat, Mar 05, 2016 at 04:15:59PM +0100, Max Reitz wrote:
> On 03.03.2016 12:01, Daniel P. Berrange wrote:
> > On Wed, Mar 02, 2016 at 05:13:59PM +0100, Max Reitz wrote:
> >> On 19.02.2016 17:47, Daniel P. Berrange wrote:
> >>> The qdict_flatten() method will take a dict whose elements are
> >>> further nested dicts/lists and flatten them by concatenating
> >>> keys.
> >>>
> >>> The qdict_crumple() method aims todo the reverse, taking a flat
> >>> qdict, and turning it into a set of nested dicts/lists. It will
> >>> apply nesting based on the key name, with a '.' indicating a
> >>> new level in the hierarchy. If the keys in the nested structure
> >>> are all numeric, it will create a list, otherwise it will create
> >>> a dict.
> >>>
> >>> If the keys are a mixture of numeric and non-numeric, or the
> >>> numeric keys are not in strictly ascending order, an error will
> >>> be reported.
> 
> [...]
> 
> >>> +            if (!child) {
> >>> +                goto error;
> >>> +            }
> >>> +
> >>> +            qdict_put_obj(tmp2, entry->key, child);
> >>> +        } else {
> >>> +            qobject_incref(entry->value);
> >>> +            qdict_put_obj(tmp2, entry->key, entry->value);
> >>> +        }
> >>> +
> >>> +        entry = next;
> >>> +    }
> >>> +    QDECREF(tmp1);
> >>> +
> >>> +    /* Step 3: detect if we need to turn our dict into list */
> >>
> >> You could use qdict_array_entries(tmp2, "") > 0 for this.
> >>
> >> If you do want to make { "0": 42, "2": 23 } and { "0": 42, "x": 23 }
> >> errors (my qdict_unflatten() just kept those QDicts), then you'd have to
> >> check on qdict_array_entries() error whether the QDict contained an
> >> integer key, but that would still be simpler than the following loop and
> >> the check in step 4.
> > 
> > If I use qdict_array_entries() then it does 2 O(N) iterations
> > of the input qdict, and to check the errors, I'll have todo
> > yet another iteration.  My inlined code here does everything
> > in a single O(N) iteration instead of 3. I think that's
> > compelling enough to reason to not use that function.
> 
> O(3N) = O(N) :-)
> 
> Making qdict_array_entries() O(N) (pretending that O(N) and O(2N) were
> different things) for this case is trivial: Just omit the second loop if
> "" has been passed as the subqdict.
> 
> So then you'd end up with "O(2N)", if you do the error checking.
> 
> So you are right, there is a reason not to use qdict_array_entries(),
> but I'd personally still use it. I only have very limited knowledge of
> the whole qemu code base, but it doesn't appear to me as if QDict
> functions are ever used in a hot path or as if QDicts ever contain a
> large number of elements (with large being more than, say, 1000),
> especially not the kind of QDicts you'd want to crumple.
> 
> Because of that, I chose to use these existing functions, even while
> knowing that they are probably not optimal for this case.
> 
> You did propose removing qdict_array_entries() and qdict_array_split()
> in favor of just using this function in their stead (see my reply
> below), so if we do so, reusing them would obviously not be ideal any
> more. In that case, I'd still put this into its own static function if
> possible.
> 
> tl;dr: I don't think runtime complexity is an issue here, but if we are
> going to drop qdict_array_entries() and qdict_array_split() anyway, then
> using them is a bad idea, obviously. It would then still be nice to put
> this into an own function.

So looking at the current usage of qdict_flatten,  qdict_extract_subqdict,
qdict_array_split and qdict_array_entries, it is basically only the block
layer.

The root cause of this usage all stems from that fact that historically
the block layer was driven off QemuOpts CLI args which are a flat data
structure. Over time we've tried to bolt on recursive data structure
support, but the main APIs are still accepting QDicts whose contents are
flat. Increasingly I see the internal code is based on QAPI which is an
inherantly nested data structure, as a result the block layer is getting
more & more places where it has to process the flat data structure to
extract nested bits (qdict_extract_subqdict, qdict_array_entries and
qdict_array_split). Conversely when fed data coming from QMP it has to
flatten the data structure with qdict_flatten.

With this new qdict_crumple() method (or equivalently you qdict_unflatten)
it strikes me we can significantly simplify the block layer to always use
a nested QDict internally. All that would be required is to call the
qdict_crumple() method in the places which have the flat QemuOpts derived
QDict. At that point we would potentially be able to delete all of
qdict_flatten, qdict_extract_subqdict, qdict_array_split and
qdict_array_entries

Of course I'm not suggesting we do that for 2.6, but it actually doesn't
look like it would be that hard todo this conversion.

> > The only user of qdict_array_entries() and qdict_array_split()
> > is the block quorum driver. From a brief look at that code
> > I think it could probably be changed to just call this new
> > qdict_crumple() method, and those 2 inefficient functions
> > could be deleted, so we don't have duplication of code.
> 
> I'm not sure. First, you do not want to crumple recursively there, so
> you'd have to re-flatten all the QList elements after you have crumpled
> them. Could be solved by adding a "bool recurse" parameter to this function.
> 
> Second, yes, qdict_array_entries() is used by quorum. However, it does
> (no longer) use qdict_array_split(); the users of that are
> util/qemu-config.c and blockdev.c. Replacing those with a non-recursing
> call to qdict_crumple() should be trivial, but quorum is going to be a
> bit more difficult. You could make it just call qdict_crumple(), get the
> size of the resulting list and then discard it, but that seems a bit
> over the top.
> 
> All in all, I think you're right in that this function can replace the
> (potentially) worse qdict_array_split() function (if the caller can stop
> it from recursing), but I don't know whether we can get rid of
> qdict_array_entries() so easily.

Yeah, that would require the big block layer conversion to always use a
nested QDict and never use a flat QDict.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

  reply	other threads:[~2016-03-07 15:06 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-19 16:47 [Qemu-devel] [PATCH v1 00/10] Provide a QOM-based authorization API Daniel P. Berrange
2016-02-19 16:47 ` [Qemu-devel] [PATCH v1 01/10] qdict: implement a qdict_crumple method for un-flattening a dict Daniel P. Berrange
2016-02-19 17:01   ` Eric Blake
2016-02-19 17:08     ` Daniel P. Berrange
2016-03-02 16:13   ` Max Reitz
2016-03-03 11:01     ` Daniel P. Berrange
2016-03-05 15:15       ` Max Reitz
2016-03-07 15:06         ` Daniel P. Berrange [this message]
2016-03-07 15:49           ` Eric Blake
2016-02-19 16:47 ` [Qemu-devel] [PATCH v1 02/10] qapi: allow QmpInputVisitor to auto-cast types Daniel P. Berrange
2016-02-19 16:47 ` [Qemu-devel] [PATCH v1 03/10] qom: support arbitrary non-scalar properties with -object Daniel P. Berrange
2016-02-19 16:47 ` [Qemu-devel] [PATCH v1 04/10] util: add QAuthZ object as an authorization base class Daniel P. Berrange
2016-02-19 16:47 ` [Qemu-devel] [PATCH v1 05/10] util: add QAuthZSimple object type for a simple access control list Daniel P. Berrange
2016-02-19 16:47 ` [Qemu-devel] [PATCH v1 06/10] acl: delete existing ACL implementation Daniel P. Berrange
2016-02-19 16:47 ` [Qemu-devel] [PATCH v1 07/10] qemu-nbd: add support for ACLs for TLS clients Daniel P. Berrange
2016-02-19 16:47 ` [Qemu-devel] [PATCH v1 08/10] nbd: allow an ACL to be set with nbd-server-start QMP command Daniel P. Berrange
2016-02-19 16:47 ` [Qemu-devel] [PATCH v1 09/10] chardev: add support for ACLs for TLS clients Daniel P. Berrange
2016-02-19 16:47 ` [Qemu-devel] [PATCH v1 10/10] vnc: allow specifying a custom ACL object name Daniel P. Berrange

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160307150629.GD13034@redhat.com \
    --to=berrange@redhat.com \
    --cc=afaerber@suse.de \
    --cc=armbru@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.