use the NullValue holder to solve the problem with default advice solutions
Implementation is simple, but the implications might be tricky
This commit is contained in:
parent
72c01e12c9
commit
d0e7f9b77d
2 changed files with 8 additions and 11 deletions
|
|
@ -86,6 +86,7 @@
|
|||
//#include "proc/asset/struct-scheme.hpp"
|
||||
//#include "lib/hash-indexed.hpp"
|
||||
//#include "lib/util.hpp"
|
||||
#include "lib/null-value.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
#include "lib/advice/binding.hpp"
|
||||
|
||||
|
|
@ -210,8 +211,7 @@ namespace advice {
|
|||
|
||||
/* == policy definitions == */ ////TODO: extract into policy classes
|
||||
|
||||
AD const& handleMissingSolution() const { return AD(); } /////////////////////TODO either return value or build a registry of defaults
|
||||
void deregistrate() { /* NOP */ }
|
||||
void deregistrate() { /* NOP */ }
|
||||
|
||||
|
||||
public:
|
||||
|
|
@ -314,7 +314,7 @@ namespace advice {
|
|||
|
||||
/* == policy definitions == */ ////TODO: extract into policy classes
|
||||
|
||||
AD const& handleMissingSolution() const { return AD(); } /////////////////////TODO singleton or registry for default advice. See TiddlyWiki for discussion
|
||||
AD const& handleMissingSolution() const { return NullValue<AD>::get(); } ///< @warning might segfault when used during shutdown
|
||||
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ In a more elaborate scheme, the advised entity could provide a signal to be invo
|
|||
&rarr; AdviceImplementation
|
||||
</pre>
|
||||
</div>
|
||||
<div title="AdviceImplementation" modifier="Ichthyostega" modified="201006010358" created="201004100056" tags="impl draft img" changecount="55">
|
||||
<div title="AdviceImplementation" modifier="Ichthyostega" modified="201006020227" created="201004100056" tags="impl draft img" changecount="56">
|
||||
<pre>[<img[Advice solution|uml/fig141573.png]]
|
||||
|
||||
|
||||
|
|
@ -585,13 +585,10 @@ The decision for the initial implementation is to use the first variant and just
|
|||
Behind the scenes, hidden within the {{{advice.cpp}}} implementation file, the ~AdviceSystem is maintained as singleton. According to a general lifecycle policy within Lumiera, no significant logic is allowed to execute in the shutdown phase of the application, once the {{{main()}}} has exited. Thus, any advice related operations might throw {{{error::Logic}}} after that point. The {{{~AdviceSystem()}}} also is a good place to free any buffers holding incorporated advice data, after having freed the index datastructure referring to these buffer storage, of course.
|
||||
|
||||
!!!!handling of default advice
|
||||
Basically, the behaviour when requesting non-existing advice may be configured by policy. But the default policy is to return ref to a default constructed instance of the advice type in that case. Just the (implementation related) problem is that we return advice by {{{const&}}}, not by value, so we're bound to create and manage this piece of default advice during the lifetime of the ~AdviceSystem. The way the ~AdviceSystem is accessed (only through the frontend of {{{advice::Request}}} and {{{advice::Provision}}} objects, in conjunction with the desire to control this behaviour by policy, creates a tricky implementation situation. Here we might also consider to use some separate kind of singleton bundle just for these default advice data (e.g. a templated version of //Meyer's Singleton...//), but this would create yet another difficult to define relation between the lifecycle of the ~AdviceSystem and such a singleton bundle.
|
||||
<<<
|
||||
{{red{WIP ... solution idea}}}: //let the handling-function for missing advice create an {{{advice::Provision<AD>}}}, with the same binding as the current request,//
|
||||
i.e. fabricate the missing solution on-the-fly, setting a default constructed piece of advice data.
|
||||
__pro__: simple to implement, avoids to re-create for this special case some of the functionality the index already provides
|
||||
__con__: difficult to check and verify, loads additional data into the index table, the first request failure gets as expensive as an advice provision, how to fabricate a reliably matching solution is not obvious in case we allow variables in the binding pattern.
|
||||
<<<
|
||||
Basically, the behaviour when requesting non-existing advice may be configured by policy. But the default policy is to return ref to a default constructed instance of the advice type in that case. Just the (implementation related) problem is that we return advice by {{{const&}}}, not by value, so we're bound to create and manage this piece of default advice during the lifetime of the ~AdviceSystem. The way the ~AdviceSystem is accessed (only through the frontend of {{{advice::Request}}} and {{{advice::Provision}}} objects, in conjunction with the desire to control this behaviour by policy, creates a tricky implementation situation.
|
||||
* regarding the lifecycle (and also from the logical viewpoint) it would be desirable to handle this "default" or "no solution" case similar to accessing an existing solution. But unfortunately doing so would require a fully typed context; thus basically on inserting a new request, when returning from the index search without a dedicated solution, we'd need to fabricate a fallback solution to insert it into the provision index, while still holding the index lock. At that point it is not determined if we ever need that fallback solution. Alternatively we could consider to fabricate this fallback solution on first unsuccessful advice fetch. But this seems sill worse, as it turns an (possibly even lock free) ptr access into an index operation. Having a very cheap advice access seems like an asset.
|
||||
* on the other hand, using some separate kind of singleton bundle just for these default advice data (e.g. a templated version of //Meyer's Singleton...//), the fallback solution can be settled independent from the ~AdviceSystem, right in the {{{advice.hpp}}} and using static memory, but the downside is now the fallback solution might be destroyed prior to shutdown of the ~AdviceSystem, as it lives in another compilation unit.
|
||||
Thus the second approach looks favourable, but we should //note the fact that it is hard to secure this possible access to an already destroyed solution,// unless we decline using the advice feature after the end of {{{main()}}}. Such a policy seems to be reasonable anyway, as the current implementation also has difficulties to prevent accessing an already destroyed {{{advice::Provision}}}, being incorporated in the ~AdviceSystem, but accessed through a direct pointer in the {{{advice::Request}}}.
|
||||
|
||||
!!!index datastructure
|
||||
It is clear by now that the implementation datastrucutre has to serve as a kind of //reference count.// Within this datastructure, any constructed advice solution needs to be reflected somehow, to prevent us from discarding an advice provision still accessible. Allowing lock-free access to the advice solution (planned feature) adds an special twist, because in this case we can't even tell for sure if an overwritten old solution is actually gone (or if its still referred from some thread's cached memeory). This could be addressed with an transactional approach (which might be good anyway) &mdash; but I tend to leave this special concern asside for now.
|
||||
|
|
|
|||
Loading…
Reference in a new issue