I think extending pmiStart to be ..
pmiStart(char *archive, int inherit)
Start a new archive context, with the basename for the external
archive being "archive". If inherit is true, then the new
context will inherit any and all metadata (metrics, instance
domains and instances) from the current context, otherwise the
new context is created with no metadata ... if this is the first
call to pmiStart the metadata will be empty independent of the
value of inherit.
After the pmiStart() call, any metadata changes are private to
the current context (unless another pmiStart() call is made, at
which time the current metadata state in the current context may
be inherited into the new context).
Since no physical files will be created until the first call to
pmiWrite() or pmiPutRecord(), archive could be NULL to create a
convenience context that is populated with metadata to be
inherited by subsequent contexts.
... addresses all of the variation Greg was asking for (the "invalidate"
is not needed, as this is the same as calling pmiStart with inherit
being false, and passing NULL as the archive name would already have
worked in the way Greg was suggesting).
And there is no collision in symbols between the Perl wrapper and
libpcp_import, so the routine names are now pmiFooBar in both places.
I'm well into coding this, so if anyone else has major objections,
suggestions or amendments, the time for speaking up is drawing to a
close.
On Tue, 2010-07-06 at 12:10 +1000, Greg Banks wrote:
> Ken McDonell wrote:
> >
> > OK. pmiSetArchive() has been replaced by pmiStart(char *archive) since
> > we now have a mandatory call to pmiStart() for each context (formerly
> > called streams) and this needs an archive basename that cannot be
> > defaulted.
> >
> > The hostname and timezone will default to the local host, but can be
> > explicitly set after pmiStart() by calling pmiSetHostname() or
> > pmiSetTimezone().
> >
>
> Sounds good.
> >
> >
> >> I think it would be a good idea to carefully define and document the
> >> semantics of calling pmiChangeStream() while partway through a sequence
> >> of pmiPutValue() calls, i.e. what happens to the partly constructed
> >> pmResult.
> >>
> >
> > It is preserved ... the partial pmResult state is maintainedsts =
> > pmiAddMetric("my.metric.foo", 1, 2, 3, 4, pmiUnits(0,0,0,0,0,0));
> sts = pmiAddMetric("my.metric.foo", 1, 2, 3, 4, pmiUnits(0,0,0,0,0,0));
> per context
> > and kept until pmiWrite() is called.
> >
> > Which leads me to another thought where we may have a disconnect ... I
> > was assuming the set of metrics and instance domains and instances was
> > private per context. I realize that this may not be what you're
> > expecting.
> > [...]
> > Thoughts?
> >
>
> I think it's quite likely that the set of instances will be different
> between different contexts, even if the metrics remain the same; imagine
> a metric whose instance domain is the disks on a system. As for metrics
> and indoms, the most general assumption would be to make them
> per-context, but reduces convenience in more common cases. Tough call.
> Perhaps you can compromise and allow the metadata to be either global or
> per-context at the application writer's choice?
>
> One way might be to have pmiStart() inherit any metadata from the
> context which is current when it's called. This is slightly more useful
> if it's possible to create a context which has no associated fsts =
> pmiAddMetric("my.metric.foo", 1, 2, 3, 4, pmiUnits(0,0,0,0,0,0));
> ile but
> just holds metadata, e.g. by passing a NULL archive name to pmiStart();
> and if pmiUse() can be made to deliberately invalidate the current context.
>
> With that arrangement, the app writer can choose to have identical
> metadata by doing:
>
> metadata = pmiStart(NULL) // create a context whose only
> purpose is to hold
> pmiAddMetric("foo.bar", ...) // metrics and instances
> pmiAddInstance(123, "mumble", 2)
> pmiAddInstance(123, "fratz", 3)
> one = pmiStart("one") // `one' copies metrics and
> instances from `metadata'
> pmiUse(metadata)
> two = pmiStart("two") // `two' ditto
> pmiUse(one)
> pmiAddValue("foo.bar", "mumble", ...)
> pmiUse(two)
> pmiAddValue("foo.bar", "mumble", ...)
>
> or she may instead choose to have completely diffrerent metadata by doing:
>
> pmiUse(-1) // ensure there is no current
> context
> one = pmiStart("one") // no current context, so `one'
> starts with
> // no metrics and no instances
> pmiAddMetric("foo.bar", ...)
> pmiAddInstance(123, "mumble", 2)
> pmiAddInstance(123, "fratz", 3) // these metrics and instances
> are for `one' only
> pmiUse(-1)
> two = pmiStart("two") // `two' also starts with no
> metrics or instances
> pmiAddMetric("baz.quux", ...)
> pmiAddInstance(123, "fnarp", 2) // these metrics and ists =
> pmiAddMetric("my.metric.foo", 1, 2, 3, 4, pmiUnits(0,0,0,0,0,0));
> nstances
> are for `two' only
> pmiUse(one)
> pmiAddValue("foo.bar", "mumble", ...)
> pmiUse(two)
> pmiAddValue("baz.quux", "fnarp", ...)
>
> or she may instead choose to have identical metrics but different
> instances by doing:
>
> metadata = pmiStart(NULL)
> pmiAddMetric("foo.bar", ...) // we want to use this metric
> for all contexts
> one = pmiStart("one") // `one' copies metrics and (no)
> instances from `metadata'
> pmiAddInstance(123, "mumble", 2)
> pmiAddInstance(123, "fratz", 3) // these instances go into `one'
> only
> pmiUse(metadata)
> two = pmiStart("two") // `two' copies metrics and (no)
> instances from `metadata'
> pmiAddInstance(123, "mumble", 2) // this instance goes into `two'
> only
> pmiUse(one)
> pmiAddValue("foo.bar", "mumble", ...)
> pmiUse(two)
> pmiAddValue("foo.bar", "mumble", ...)
>
> For complete generality you might also need a call to forget all the
> metadata from the current context.
>
> Keeping the partial pmResults per-context makes sense to me. That way
> an app can build a single time slice across multiple archives
> breadth-first, which may be the most convenient way if the inpsts =
> pmiAddMetric("my.metric.foo", 1, 2, 3, 4, pmiUnits(0,0,0,0,0,0));
> ut data is
> organised like that.
> >
> >> ...
> >>
> >>>>> $import = PCP::IMPORT->new('');
> >>>>>
> >>>>>
> >>>>>
> >>>> I don't see any point to having this object; if I understand the API
> >>>> above it will have no state and just serves as a subroutine scoping
> >>>> mechanism.
> >>>>
> >>>>
> >>> There is a heap of state that has to be held across calls to
> >>> libpcp_import routines (metadata, partial pmResult, ...).
> >>>
> >> Sure, but all that state is in the C library right?
> >>
> >sts = pmiAddMetric("my.metric.foo", 1, 2, 3, 4, pmiUnits(0,0,0,0,0,0));
> > Correct, so I'll just lose the object abstraction. I assume trimming
> > the pmi prefix off the routine names for the Perl wrapper routines is a
> > bad idea, as this leads to potential name clashes with names that are
> > not prefixed PCP::IMPORT::, e.g. Start(), End(), Write() etc. Is there
> > a convention to follow here? My initial though was pmiFooBar() ->
> > pmi_foo_bar() for the Perl wrapper, but I really don't care so if there
> > some preferred naming regime point me in the right direction and I'll
> > follow that.
> >
> >
> I'm not really a Perl expert, but if I understand the Exporter behaviour
> correctly then your concern about name clashes is well founded. A brief
> perusal of the Perl modules on this system shows examples with names
> like fooBar() and even FooBar(), sometimes in order to reflect the
> underlying C names. So you could use the C names in Perl without
> mapping, and just throw them all into a module PCP::Import, so app code
> looks like
>
>
> use PCP:Import;
> my $metadata = pmiStart(); # archive name = undef
> pmiAddMetric("foo.bar", ...);
> pmiAddInstance(123, "mumble", 2);
> pmiAddInstance(123, "fratz", 3);
> my $one = pmiStart("one");
> pmiUse($metadata);
> my $two = pmiStart("two");
> pmiUse($one);
> pmiAddValue("foo.bar", "mumble", ...);
> pmiUse($two);
> pmiAddValue("foo.bar", "mumble", ...) ;
>
|