Skip to content

Conversation

Laczen
Copy link
Contributor

@Laczen Laczen commented Jun 8, 2019

This is an alternative implementation of #16609.

The PR provides:
a. Working with const char names instead of argc, argv list
b. The ability to register settings_handler names containing one or multiple separators
c. The ability to register a handler for each variable
d. Loading of variables belonging to a subtree and by this allowing RAM reduction in the
module/application using settings.

@Laczen Laczen requested review from fnde-ot and rakons June 8, 2019 21:40
@Laczen Laczen added the DNM This PR should not be merged (Do Not Merge) label Jun 8, 2019
@Laczen
Copy link
Contributor Author

Laczen commented Jun 8, 2019

@dbkinder, don't review this yet.

@Laczen Laczen mentioned this pull request Jun 8, 2019
4 tasks
@zephyrbot zephyrbot added area: Settings Settings subsystem area: API Changes to public APIs area: Samples Samples labels Jun 8, 2019
@zephyrbot
Copy link

zephyrbot commented Jun 8, 2019

All checks are passing now.

Review history of this comment for details about previous failed status.
Note that some checks might have not completed yet.

@Laczen Laczen force-pushed the settings_str branch 3 times, most recently from 4127b1f to e3d6442 Compare June 9, 2019 08:28
@Laczen
Copy link
Contributor Author

Laczen commented Jun 9, 2019

@fnde-ot, this would be a breaking change for your custom backend: the load function is changed (the same for #16609).

Copy link
Contributor

@rakons rakons left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I did not analyse all the corner cases for the new way of registration and key searching - request for unit tests for that.

Currently implemented unit tests fails in many places - I have run only fcb/raw and 9 tests fail.

@pdunaj pdunaj self-requested a review June 10, 2019 09:50
@carlescufi carlescufi requested review from Vudentz and jhedberg June 10, 2019 11:12
@rakons
Copy link
Contributor

rakons commented Jun 10, 2019

Just a side note (nitpicking) - should not it be done on a private fork? I understand that now it would be a waste of time and resources to move it, but just for the future...

*
* @return 0 on success, non-zero on failure.
*/
int settings_load_subtree(const char *subtree);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this something I could call on bt_init? What if the application is also calling settings_load by itself then? Would that cause the handler to be called once again? I guess we should clearly state on the documentation this sort of behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you could, the mutex would not stop the handler to be called again. For the documentation it should be clear:
settings_load(): loads all entries,
settings_load_subtree(): loads limited set of entries (subtree is not limited to handler names, it can be a subset of a handler name).

But maybe your are asking something else: I have a handler that I want to call myself, and nobody else, how do I do this ?
Option 1: Add a flag to the set routine and only allow processing of the set routine if this flag is set. Do the loading by: enabling the flag, call settings_load_subtree, disable the flag. This is not thread-safe but might be sufficient.
Option 2: Don't register the settings_handler yet, do the loading by register the handler, call settings_load_subtree, deregister the handler. At the moment this is not yet thread-safe, but this could be converted into one routine and made thread-safe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My question was that if this would cause the handler to be called multiple times, one by load and another by load_subtree that may cause extra loading from no reason, I guess the idea is that each subsystem calls load_substree and load would take care of the remaining settings which most likely are just app specific, this way the more natural sequence would be subsystem blah settings_load_subtree("blah") (marked it as loaded)... -> app settings_load()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, sorry forgot to answer the question: Yes, it would be called several times.

There is no requirement on how to use it, the idea is that it would be needed to call a settings_load_subtree() as a result of a connection request so that only limited RAM would be occupied for storing this information.

Your natural sequence could also be done: using option 2 from above settings_load_handler(&blah_handler): registers blah, loads blah elements, unregister blah (this is the marked as loaded). Do this for each subsystem and finally call settings_load for all app related stuff.

Should I add a settings_load_handler() like defined above ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It depends on how we wish the system to be designed. I believe that the full settings load should be called only once - on system start. And it should be left to the module implementation to decide how we wish to tread incoming data (for example, any CCCD data may be ignored if we do not have an active connection already).

Then when the system works, we can call settings_load_subtree (or load_selected from #16609) whenever needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we even need a settings_load()? Couldn't each module just call settings_load_subtree() when appropriate on init (or on demand)? The app can always have its own subtree (fx. "app/") and use settings_load_subtree().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fnde-ot, completely agree, we could remove the settings_load() completely. Combining this with the remark from @Vudentz in #16676 would open a lot of opportunities. There of course would be
a disadvantage that all entries in the backend are read multiple times, but maybe even this can be avoided (e.g. for the bluetooth system): let us suppose there are multiple subsystems defined (bt/btmesh, bt/ccc, bt/gatt ... these are just examples I'm not a bt expert) each of these would define their own set routines. To load all bt related settings we would define bt_set routines as:

int bt_set(const char *name, ...) {
  char *next;
#ifdef(BTMESH)
  if (settings_name_cmp(name,"btmesh", &next)) {
    return btmesh_set(next, ...);
  }
#endif
#ifdef(BTCCC)
  if (settings_name_cmp(name, "ccc", &next)) {
    return ccc_set(next, ....);
  }
#endif
}

int bt_load() {
  settings_load_subtree("bt", bt_set);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And you cannot agree with my proposal as it requires too much of rework inside modules. I ask you not to go that direction here - separate this idea and offer it in another PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Laczen @rakons, Sounds to me more like a backend problem. On-demand or subtree loading should not require significant changes to existing modules, appart from adding calls to settings_load_subtree(...) in the appropriate init functions.

The multiple-read would not be an issue if the backend properly separated settings from different modules (not a flash expert, but maybe using multiple files or grouping settings from a single module together and reading from a specific offset). But then again, this could require to rethink the way existing backends work, which would be out of scope for this PR.

We can still remove settings_load from this PR and rework the backends in another one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rakons, I cannot agree with your proposal because:
a. The pattern search is to much code and not needed
b. The split up to get a dynamic generated name is not done and is relying on string conversion routines to do the split up. This only works if there is a conversion routine available.

I have accepted doing the rework inside the modules by not introducing the setiings_name_separate(), but there is a very specific reason for this: reducing RAM usage in the case where a dynamic name would be used at the top of some tree where most entries under this would have a fixed part (e.g. bt/ccc/0xfffe/info/data/val1, bt/ccc/0xffe/info/data/val2, bt/ccc/0xffe/id, and the same entries for bt/ccc/0xfffd...).

This however has nothing to do with the discussion above: the proposal has triggered other (new) ideas to make the proposal even simpler (remove registering of handlers and looking up handlers) and it would be a pity not to take these ideas into account.

Copy link
Contributor

@nvlsianpu nvlsianpu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put my comments. I'm also inline with @rakons comments.

@MaureenHelm MaureenHelm self-requested a review June 10, 2019 23:28
@nvlsianpu
Copy link
Contributor

@Laczen @rako @Vudentz We really want to proces this PR quickly - so It would be great to limit its scope only to things we are agreed on them, and not escalate discussion here.

@nvlsianpu
Copy link
Contributor

I wish we can merge it tomorrow.

@Laczen
Copy link
Contributor Author

Laczen commented Jun 11, 2019

@nvlsianpu, I am updating the tests. Everything is ok for fcb, for nffs I get a compilation error (for nrf52_pca10040): #include <nffs/nffs.h> cannot be found -> has something changed here ?

@Laczen
Copy link
Contributor Author

Laczen commented Jun 14, 2019

@rakons, @nvlsianpu, I am doubting if we need to expose settings_name_steq() to the modules/user. settings_name_next() provides all the needed functionality when used in combination with strncmp(). It would also force modules into avoiding using the string comparison multiple times.

@nvlsianpu
Copy link
Contributor

Maybe worth to align settings's client modules to code changes - so It will be visible whether it make sense.

I mean I reali appreciated user experience - which comes from using subtree name explicit - zephyr modules might not use it at all, but for high level application development it might be useful. I think settings_name_steq() might gives good user experience - I would not resign form it in this PR.

Copy link
Contributor

@rakons rakons left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accepting it now - it seems to go in the right direction and I wish not to block it while I am on my leave.

@Laczen
Copy link
Contributor Author

Laczen commented Jun 14, 2019

  • Update the settings users to the new API (also already ported)

done

@jhe, @Vudentz, please review. @Vudentz, I have discovered that "bt/hash" is written twice during startup of an app with bt, even when the handlers for "bt/hash" are disabled, maybe there is something wrong.

@Laczen Laczen requested a review from sjanc as a code owner June 15, 2019 08:12
Laczen added 2 commits June 18, 2019 09:33
The settings module processes the variable name by splitting it up in
a set of variables. This PR removes the splitting up and keeps the
variable name as one string.

It is an alternative to #16609

The possibility is introduced to register handler including a
separator, or to register a handler for each variable.

The ability is introduced to load a subtree from flash or even to load
a single item.

Two ways to operate on variable and settings_handler names are provided:

settings_name_steq(const char *name, const char *key, const char **next)
which checks if name starts with key, returns 1/0 if it does/does not
the remaining part of name is in next.

settings_name_split(const char *name, char *argv, const char **next)
which splits up name in a part before "/"" that is found in argv and
the remaining part that is in next.

A mutex is added to make settings thread-safe

The settings_handlers list is stored in reverse alphabetical order, this
allows registration of e.g. bt and bt/mesh in separate handlers, the bt
handler itself should not contain any handling of bt/mesh.

A settings_deregister() method is added. Settings_handlers can now be
added/removed when required. This saves RAM when settings_handlers are
not needed.

Tests have been updated to reflect changes in the settings api.

Updates after meeting:
1. Removed settings_deregister

2. Changed settings_name_split() in settings_name_next:

int settings_name_next(const char *name, const char **next): returns
the number of characters before the first separator. This can then be
used to read the correct number of characters from name using strncpy
for processing.

3. New functional test added

Update in settings.h: settings_name_next() changed position -> index

Added some comments in settings.h (settings_name_steq())

Updated tests to reflect change to settings_name_next() and pointer
value comparison. The functional test can now also run on qemu_x86.

Corrected some documentation in header.

Changed registration of handlers to be non ordered.

Changed handler lookup to handle non ordered list of handlers, this
improves handler matching in case different length names are compared
and also makes it easier to add rom based handlers as they will not be
ordered.

Signed-off-by: Laczen JMS <laczenjms@gmail.com>
This updates all client modules to const char processing of
setting names.

Update of peripheral_dis sample

Signed-off-by: Laczen JMS <laczenjms@gmail.com>
@nvlsianpu
Copy link
Contributor

I'm doing one more review round (I believe the last on:D)

@Laczen
Copy link
Contributor Author

Laczen commented Jun 18, 2019

Hi @nvlsianpu, I have prepared a new commit that adds the possibility to have rom registered handles without any (extra) API change. It just adds a function SETTINGS_REGISTER_ROM(handler) and the handler needs to be const. Two Kconfig option are added: SETTINGS_RAM_HANDLERS and SETTINGS_ROM_HANDLERS both set to y by default.

I would add this to the PR as a separate commit, so it can be cherrypicked. With this last commit I would stop working on the settings module.

@nvlsianpu
Copy link
Contributor

^^ better open new PR

Copy link
Contributor

@nvlsianpu nvlsianpu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests passes (verified nrf52_10040.)
functional tests LGTM
settings client adaptations looks ok
f. settings_name_steq() is kept (appreciated)
I had just 2 nips which can be fixed even later

err = (data.en1) && (data.en2) && (!data.en3);
zassert_true(err, "wrong data enable found");

/* val3 settings should be inserted in between val1_settings and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just nip: not inserted anymore

return sys_slist_find_and_remove(&settings_handlers, &handler->node);
}

static void test_register_and_loading(void)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nip: looks like this test doesn't ensure storage clearance - it fails therefore in second run in line 222

@nvlsianpu
Copy link
Contributor

@Laczen Can DNM label be removed?

@nvlsianpu
Copy link
Contributor

@jhedberg, @Vudentz Can you look at relevant client modules changes?

Copy link
Member

@jhedberg jhedberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've gone through the Bluetooth-related changes, and they look fine to me. I haven't tested anything however, so it'd be good if someone would find time to do this.

@nvlsianpu
Copy link
Contributor

I've gone through the Bluetooth-related changes, and they look fine to me. I haven't tested anything however, so it'd be good if someone would find time to do this.

Checked that bond info and keys are stored/loaded properly, ccc storage works well as well.

@nvlsianpu nvlsianpu removed the DNM This PR should not be merged (Do Not Merge) label Jun 18, 2019
@nvlsianpu
Copy link
Contributor

@carlescufi This PR can be merged.

@aescolar
Copy link
Member

aescolar commented Jun 18, 2019

@Laczen , @nvlsianpu : about @dbkinder negative review, regarding documentation, is this PR not meant to add/change documentation anymore?

@aescolar aescolar requested a review from dbkinder June 18, 2019 14:43
@Laczen
Copy link
Contributor Author

Laczen commented Jun 18, 2019

@aescolar, I think this negative review was the result of a sample that was missing documentation. This sample was never meant to be merged but to allow discussion. The sample is not there anymore so I am unsure about the negative review.

@carlescufi carlescufi dismissed dbkinder’s stale review June 18, 2019 15:56

not applicable

@carlescufi carlescufi merged commit 8ca8708 into master Jun 18, 2019
@nashif nashif deleted the settings_str branch June 19, 2019 11:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: API Changes to public APIs area: Bluetooth area: native port Host native arch port (native_sim) area: Samples Samples area: Settings Settings subsystem area: Tests Issues related to a particular existing or missing test
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants