From: Wolfgang Bumiller <w.bumiller@proxmox.com>
To: Dominik Csapak <d.csapak@proxmox.com>
Cc: pve-devel@lists.proxmox.com
Subject: Re: [pve-devel] [PATCH cluster v10 1/5] add CFS_IPC_GET_GUEST_CONFIG_PROPERTIES method
Date: Wed, 16 Nov 2022 10:50:38 +0100 [thread overview]
Message-ID: <20221116095038.vrvn43aeq33vrame@casey.proxmox.com> (raw)
In-Reply-To: <20221115130248.1007325-2-d.csapak@proxmox.com>
On Tue, Nov 15, 2022 at 02:02:26PM +0100, Dominik Csapak wrote:
> for getting multiple properties from the in memory config of the
> guests in one go. Keep the existing IPC call as is for backward
> compatibility and add this as separate, new one.
>
> It basically behaves the same as
> CFS_IPC_GET_GUEST_CONFIG_PROPERTY, but takes a list of properties
> instead and returns multiple properties per guest.
>
> The old way of getting a single property is now also done by
> the new function, since it basically performs identically.
>
> Here a short benchmark:
>
> Setup:
> PVE in a VM with cpu type host (12700k) and 4 cores
> 10000 typical configs with both 'lock' and 'tags' set at the end
> and fairly long tags ('test-tag1,test-tag2,test-tag3')
> (normal vm with a snapshot, ~1KiB)
>
> i let it run 100 times each, times in ms
>
> old code:
>
> total time time per iteration
> 1054.2 10.2
>
> new code:
>
> num props total time time per iter function
> 2 1332.2 13.2 get_properties
> 1 1051.2 10.2 get_properties
> 2 2082.2 20.2 get_property (2 calls to get_property)
> 1 1034.2 10.2 get_property
>
> so a call with the new code for one property is the same as with the
> old code, and adding a second property only adds a bit of additional
> time (in this case ~30%)
>
> Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
> ---
Sort-of
Acked-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
but I do have a bit of a maintainability-complaint and potential actual
issue (see below).
> changes from v9:
> * line_len, prop_len -> size_t
> * document min/max
> * remove setting of null byte in loop (it's already split at the null byte)
> * improved the loop for skipping whitespace at the beginning
> data/src/cfs-ipc-ops.h | 2 +
> data/src/server.c | 63 ++++++++++++++
> data/src/status.c | 184 ++++++++++++++++++++++++++++-------------
> data/src/status.h | 3 +
> 4 files changed, 194 insertions(+), 58 deletions(-)
>
> diff --git a/data/src/status.c b/data/src/status.c
> index 9bceaeb..47cb42e 100644
> --- a/data/src/status.c
> +++ b/data/src/status.c
> @@ -804,25 +804,55 @@ cfs_create_vmlist_msg(GString *str)
> return 0;
> }
>
> -// checks the conf for a line starting with '$prop:' and returns the value
> -// afterwards, whitout initial whitespace(s), we only deal with the format
> -// restricion imposed by our perl VM config parser, main reference is
> +// checks if a config line starts with the given prop. if yes, writes a '\0'
> +// at the end of the value, and returns the pointer where the value starts
Please add:
// `line[line_len]` is guaranteed to be `\0`
keep reading for why ;-)
> +char *
> +_get_property_value_from_line(char *line, size_t line_len, const char *prop, size_t prop_len)
> +{
> + if (line_len <= prop_len + 1) return NULL;
> +
> + if (line[prop_len] == ':' && memcmp(line, prop, prop_len) == 0) { // found
> + char *v_start = &line[prop_len + 1];
> + char *v_end = &line[line_len - 1];
nit: in most C code an start and end pointers are exclusive on the end side
(iow. end should point to the first invalid address) it's a bit
confusing doing it this way and may lead to confusion...
> +
> + // drop initial value whitespaces here already
> + while (v_end > v_start && *v_start && isspace(*v_start)) v_start++;
(((that's fine, but I find 'v_start < v_end' much easier to parse)))
> +
> + if (!*v_start) return NULL;
> +
this is where the v_end tripped me up a bit:
- if there's no value, v_start == v_end and the loop won't run
> + while (v_end > v_start && isspace(*v_end)) v_end--;
> + v_end[1] = '\0';
which makes this read as "write to 1 past the end"
which *seems* fine at first given that we split the lines by replacing
'\n' with '\0', but then there's another case to think about:
The original data just came from a `memdb_read()` which just gives us a
"binary blob" and may not be newline-terminated.
However, the *caller* guarantees that in this case, we simply ignore the
final line.
BUT: do we do the same in perl?
> +
> + return v_start;
> + }
> +
> + return NULL;
> +}
> +
> +// checks the conf for lines starting with the given props and
> +// writes the pointers into the correct positions into the 'found' array
> +// afterwards, without initial whitespace(s), we only deal with the format
> +// restriction imposed by our perl VM config parser, main reference is
> // PVE::QemuServer::parse_vm_config this allows to be very fast and still
> // relatively simple
> -// main restrictions used for our advantage is the properties match reges:
> +// main restrictions used for our advantage is the properties match regex:
> // ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) from parse_vm_config
> // currently we only look at the current configuration in place, i.e., *no*
> -// snapshort and *no* pending changes
> -static char *
> -_get_property_value(char *conf, int conf_size, const char *prop, int prop_len)
> +// snapshot and *no* pending changes
> +//
> +// min..max is the char range of the first character of the given props,
> +// so that we can return early when checking the line
> +void
> +_get_property_values(char **found, char *conf, int conf_size, const char **props, uint8_t num_props, char min, char max)
> {
> const char *const conf_end = conf + conf_size;
> char *line = conf;
> - size_t remaining_size;
> + size_t remaining_size = conf_size;
> + int count = 0;
^ I'd prefer an uint8_t here and call it `prop_count` as it's strictly
to count towards the above `uint8_t num_props`, so `int` makes little
sense, and the generic name `count` with type `uint8_t` is also a bit
awkward ;-)
>
> char *next_newline = memchr(conf, '\n', conf_size);
> if (next_newline == NULL) {
> - return NULL; // valid property lines end with \n, but none in the config
> + return; // valid property lines end with \n, but none in the config
> }
> *next_newline = '\0';
>
> @@ -830,41 +860,32 @@ _get_property_value(char *conf, int conf_size, const char *prop, int prop_len)
> if (!line[0]) goto next;
>
> // snapshot or pending section start, but nothing found yet -> not found
> - if (line[0] == '[') return NULL;
> - // properties start with /^[a-z]/, so continue early if not
> - if (line[0] < 'a' || line[0] > 'z') goto next;
> -
> - int line_len = strlen(line);
> - if (line_len <= prop_len + 1) goto next;
> -
> - if (line[prop_len] == ':' && memcmp(line, prop, prop_len) == 0) { // found
> - char *v_start = &line[prop_len + 1];
> -
> - // drop initial value whitespaces here already
> - while (*v_start && isspace(*v_start)) v_start++;
> -
> - if (!*v_start) return NULL;
> -
> - char *v_end = &line[line_len - 1];
> - while (v_end > v_start && isspace(*v_end)) v_end--;
> - v_end[1] = '\0';
> -
> - return v_start;
> + if (line[0] == '[') return;
> + // continue early if line does not begin with the min/max char of the properties
> + if (line[0] < min || line[0] > max) goto next;
> +
> + size_t line_len = strlen(line);
This is only fine because we skip the final line if it's not
`\n`-terminated (as it's otherwise not guaranteed to be `\0`-terminated)
But we don't even need to re-scan the line, since we already did that,
and should just be able to use:
line_len = next_newline - line;
no?
> + for (uint8_t i = 0; i < num_props; i++) {
> + char * value = _get_property_value_from_line(line, line_len, props[i], strlen(props[i]));
> + if (value != NULL) {
> + count += (found[i] != NULL) & 0x1; // count newly found lines
> + found[i] = value;
> + }
> + }
> + if (count == num_props) {
> + return; // found all
> }
> next:
> line = next_newline + 1;
> remaining_size = conf_end - line;
> - if (remaining_size <= prop_len) {
> - return NULL;
> - }
> next_newline = memchr(line, '\n', remaining_size);
> if (next_newline == NULL) {
> - return NULL; // valid property lines end with \n, but none in the config
> + return; // valid property lines end with \n, but none in the config
> }
> *next_newline = '\0';
> }
>
> - return NULL; // not found
> + return;
> }
>
> static void
next prev parent reply other threads:[~2022-11-16 9:50 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-15 13:02 [pve-devel] [PATCH cluster/guest-common/qemu-server/container/wt/manager v10 0/5] add tags to ui Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH cluster v10 1/5] add CFS_IPC_GET_GUEST_CONFIG_PROPERTIES method Dominik Csapak
2022-11-16 9:50 ` Wolfgang Bumiller [this message]
2022-11-15 13:02 ` [pve-devel] [PATCH cluster v10 2/5] Cluster: add get_guest_config_properties Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH cluster v10 3/5] datacenter.cfg: add option for tag-style Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH cluster v10 4/5] datacenter.cfg: add tag rights control to the datacenter config Dominik Csapak
2022-11-15 15:17 ` Fabian Grünbichler
2022-11-16 7:48 ` Thomas Lamprecht
2022-11-16 8:47 ` Dominik Csapak
2022-11-16 8:51 ` Fabian Grünbichler
2022-11-16 8:54 ` Thomas Lamprecht
2022-11-16 9:04 ` Dominik Csapak
2022-11-16 9:10 ` Thomas Lamprecht
2022-11-16 9:31 ` Fabian Grünbichler
2022-11-16 9:38 ` Dominik Csapak
2022-11-16 9:40 ` Thomas Lamprecht
2022-11-16 9:51 ` Fabian Grünbichler
2022-11-16 13:56 ` Thomas Lamprecht
2022-11-15 13:02 ` [pve-devel] [PATCH cluster v10 5/5] datacenter.cfg: add 'ordering' to 'tag-style' config Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH guest-common v10 1/1] GuestHelpers: add 'assert_tag_permissions' Dominik Csapak
2022-11-15 15:34 ` Fabian Grünbichler
2022-11-15 13:02 ` [pve-devel] [PATCH qemu-server v10 1/1] api: update: check for tags permissions with 'assert_tag_permissions' Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH container v10 1/1] check_ct_modify_config_perm: " Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH widget-toolkit v10 1/2] add tag related helpers Dominik Csapak
2022-11-16 13:48 ` [pve-devel] applied: " Thomas Lamprecht
2022-11-15 13:02 ` [pve-devel] [PATCH widget-toolkit v10 2/2] Toolkit: add override for Ext.dd.DragDropManager Dominik Csapak
2022-11-16 13:49 ` [pve-devel] applied: " Thomas Lamprecht
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 01/13] api: /cluster/resources: add tags to returned properties Dominik Csapak
2022-11-16 8:02 ` Thomas Lamprecht
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 02/13] api: add /ui-options api call Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 03/13] ui: call '/ui-options' and save the result in PVE.UIOptions Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 04/13] ui: parse and save tag infos from /ui-options Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 05/13] ui: add form/TagColorGrid Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 06/13] ui: add PVE.form.ListField Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 07/13] ui: dc/OptionView: add editors for tag settings Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 08/13] ui: add form/Tag Dominik Csapak
2022-11-16 14:57 ` Thomas Lamprecht
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 09/13] ui: add form/TagEdit.js Dominik Csapak
2022-11-16 15:00 ` Thomas Lamprecht
2022-11-16 15:02 ` Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 10/13] ui: {lxc, qemu}/Config: show Tags and make them editable Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 11/13] ui: tree/ResourceTree: show Tags in tree Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 12/13] ui: add tags to ResourceGrid and GlobalSearchField Dominik Csapak
2022-11-15 13:02 ` [pve-devel] [PATCH manager v10 13/13] ui: implement tag ordering from datacenter.cfg Dominik Csapak
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=20221116095038.vrvn43aeq33vrame@casey.proxmox.com \
--to=w.bumiller@proxmox.com \
--cc=d.csapak@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/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.