Skip to content

Archive append support#2611

Open
natoscott wants to merge 12 commits into
performancecopilot:mainfrom
natoscott:pmi-append-mode
Open

Archive append support#2611
natoscott wants to merge 12 commits into
performancecopilot:mainfrom
natoscott:pmi-append-mode

Conversation

@natoscott

Copy link
Copy Markdown
Member

Provides a mechanism whereby libpcp_import can append to an existing PCP archive.

Adds pre-existing PMI interfaces to the pcp/import.h header that were missing. Similar to recent work in MMV, a pmAtomValue interface is also added so tools that have values in binary form already do not pay the cost of string conversions and parsing for every value on every sample.

Additional commits improve the PMI documentation (man page synopsis sections for Python), provide python typing information to the PMI library, and cleanup a QA makefile.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds PMI append mode and atom-value handle writes, refactors import value allocation, documents Python usage and typings, introduces high-resolution write/result APIs, updates headers/exports, and adds QA tests exercising create/append/fallback behaviors.

Changes

PCP log import append mode, atom-value handle, and documentation updates

Layer / File(s) Summary
Public API headers and exports
src/include/pcp/import.h, src/include/pcp/libpcp.h, src/libpcp/src/exports.in
Adds PMI_INHERIT/PMI_APPEND, declares pmiWrite2/pmiHighResWrite/pmiPutHighResResult/pmiPutAtomValueHandle, and declares/exports __pmLogOpenAppend.
libpcp archive append opener
src/libpcp/src/logutil.c
Implements __pmLogOpenAppend() to open existing archives for append, validate metadata, load end time, and position files at EOF for writing.
libpcp_import context and metric handling
src/libpcp_import/src/private.h, src/libpcp_import/src/archive.c, src/libpcp_import/src/import.c
Adds CONTEXT_APPEND; updates pmiStart() to accept flags and set append/inherit behavior; check_context_append() reloads metadata and seeds last_stamp; check_metric() validates and skips rewriting existing descriptors during append.
Atom-value handle API and value allocation refactor
src/libpcp_import/src/import.c, src/libpcp_import/src/stuff.c, src/libpcp_import/src/exports
Adds pmiPutAtomValueHandle() that forwards to a shared _pmi_stuff_atomvalue; introduces _pmi_alloc_vp and _pmi_alloc_valblock to centralize pmValue selection and heap allocation; refactors stuffing logic accordingly.
Man pages and Python type annotations
man/man3/pmi*.3, src/python/pcp/pmi.py
Adds "Python SYNOPSIS" across PMI manpages; documents pmiWrite2/pmiHighResWrite and pmiPutHighResResult; pmistart.3 documents flags semantics; Python module receives type hints for public API and helpers.
QA tests and build integration
qa/src/check_import_append.c, qa/1693, qa/src/check_import.c, qa/src/GNUlocaldefs, qa/src/.gitignore, qa/group, qa/src/test_pmi.python
Adds three-phase append C test and QA script qa/1693, extends existing tests to exercise atom-value handle and pmiWrite(0) regression, and updates QA build targets and ignore rules.

"A rabbit scampers through logs at night,
Appending timestamps till morning light,
Atoms and writes in tidy rows,
Python docs and tests in tow,
🐇📦✨"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Archive append support' accurately describes the primary change, which adds append functionality to libpcp_import for existing PCP archives.
Description check ✅ Passed The description clearly relates to the changeset by explaining the append mechanism, missing PMI interfaces, pmAtomValue support, Python documentation improvements, and QA makefile cleanup.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/python/pcp/pmi.py (1)

389-398: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix pmiWrite to handle sec=0 when usec is omitted (avoid passing None to pmiWrite2).

When sec == 0 and usec is omitted (usec=None), the condition if sec and not usec: doesn’t run, so LIBPCP_IMPORT.pmiWrite2(sec, usec) is called with usec=None. Since pmiWrite2.argtypes = [c_longlong, c_int], this raises TypeError at runtime.

Proposed fix
-        if sec and not usec:
+        if usec is None:
             if isinstance(sec, datetime):
                 sec = float((sec - self._epoch).total_seconds())
             if isinstance(sec, float):
                 ts = modf(sec)
                 sec = int(ts[1])
                 usec = int(ts[0] * 1000000)
             else:
                 usec = 0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/python/pcp/pmi.py` around lines 389 - 398, The bug is that when sec == 0
and usec is None the branch `if sec and not usec:` is skipped and
`pmiWrite2(sec, usec)` is called with usec==None causing a TypeError; update the
condition to explicitly check for a provided sec (e.g., `if sec is not None and
usec is None:`) so the conversion logic that handles datetime (using
`self._epoch` and `modf`) and the fallback `usec = 0` are executed for sec==0 as
well, ensuring `LIBPCP_IMPORT.pmiWrite2(sec, usec)` is always called with an
integer usec.
src/libpcp_import/src/import.c (1)

342-354: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject PMI_APPEND | PMI_INHERIT or define a hard precedence.

This branch still clones the previous context when PMI_INHERIT is set, even after putting the new context into append mode. The append path described for src/libpcp_import/src/archive.c also reloads metric and indom metadata from the target archive, so this combination can seed a second, potentially unrelated metadata/handle set before append initialization runs. That risks duplicate descriptors or handles pointing at the wrong metric indexes during append.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/libpcp_import/src/import.c` around lines 342 - 354, Detect and handle the
conflicting PMI_APPEND | PMI_INHERIT case in the pmiStart path: before setting
current->state and before running the inheritance block that uses old_current,
check if ((flags & PMI_APPEND) && (flags & PMI_INHERIT)) and either (A) reject
the call with a clear error/return (e.g., return PM_ERR with a message) or (B)
enforce a hard precedence by clearing one flag (e.g., prefer append: flags &=
~PMI_INHERIT) so the subsequent inheritance block (the code referencing
old_current and cloning metadata) is skipped; implement the chosen behavior
immediately after flags are received and ensure the rest of the function
(current->state, current->archive, and the if ((flags & PMI_INHERIT) &&
old_current != NULL) block) acts consistently with that decision.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@qa/group`:
- Line 2212: Update the test mapping for identifier 1670 in qa/group so the
entry includes the local sweep group; locate the line "1670 libpcp_import" and
change it to include "local" alongside the existing group (e.g., "1670 local
libpcp_import") following the same spacing/order style used by other entries so
the standard local sweep will run this test.

In `@src/libpcp_import/src/archive.c`:
- Around line 195-211: The code currently treats a successful
__pmLogLookupDesc(acp, pmid, &existing) as meaning all metadata is present;
instead, when __pmLogLookupDesc returns 0 you must compare the returned existing
descriptor and its namelist against current->metric[m].desc and namelist to
ensure compatibility and that any new aliases are present; only if descriptors
are identical/compatible and the existing namelist already contains the current
namelist set current->metric[m].meta_done = 1, otherwise call
__pmLogPutDesc(acp, &current->metric[m].desc, 1, namelist) (and set *needti and
meta_done appropriately) so new alias entries are persisted and incompatible
re-registrations are detected/handled.

In `@src/libpcp_import/src/import.c`:
- Around line 891-899: pmiPutAtomValueHandle currently only validates the
handle; first check that the atom pointer is not NULL and return a suitable
error via current->last_sts (e.g. PMI_ERR_BADARG) if it is, and if atom->type ==
PM_TYPE_STRING also validate that atom->cp is not NULL (again set and return
current->last_sts = PMI_ERR_BADARG) before calling _pmi_stuff_atomvalue; this
prevents _pmi_stuff_atomvalue from dereferencing atom or doing strlen(atom->cp)
on a NULL pointer.

In `@src/libpcp/src/logutil.c`:
- Around line 411-417: Before trusting the loaded temporal index, validate the
`.index` label using __pmLogChkLabel on lcp->tifp (the same check __pmLogOpen
does) and only call __pmLogLoadIndex if __pmLogChkLabel succeeds; if the check
fails, call __pmFclose on lcp->mdfp and lcp->tifp, set them to NULL, and return
an error (as is done on other failures) so lcp->endtime cannot be seeded from a
stale or mismatched .index. Ensure you reference __pmLogChkLabel,
__pmLogLoadIndex, __pmFclose and lcp->tifp in the change and preserve the
existing cleanup pattern.

---

Outside diff comments:
In `@src/libpcp_import/src/import.c`:
- Around line 342-354: Detect and handle the conflicting PMI_APPEND |
PMI_INHERIT case in the pmiStart path: before setting current->state and before
running the inheritance block that uses old_current, check if ((flags &
PMI_APPEND) && (flags & PMI_INHERIT)) and either (A) reject the call with a
clear error/return (e.g., return PM_ERR with a message) or (B) enforce a hard
precedence by clearing one flag (e.g., prefer append: flags &= ~PMI_INHERIT) so
the subsequent inheritance block (the code referencing old_current and cloning
metadata) is skipped; implement the chosen behavior immediately after flags are
received and ensure the rest of the function (current->state, current->archive,
and the if ((flags & PMI_INHERIT) && old_current != NULL) block) acts
consistently with that decision.

In `@src/python/pcp/pmi.py`:
- Around line 389-398: The bug is that when sec == 0 and usec is None the branch
`if sec and not usec:` is skipped and `pmiWrite2(sec, usec)` is called with
usec==None causing a TypeError; update the condition to explicitly check for a
provided sec (e.g., `if sec is not None and usec is None:`) so the conversion
logic that handles datetime (using `self._epoch` and `modf`) and the fallback
`usec = 0` are executed for sec==0 as well, ensuring
`LIBPCP_IMPORT.pmiWrite2(sec, usec)` is always called with an integer usec.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 9da0a39b-e55c-4866-b2da-9302dda7cacf

📥 Commits

Reviewing files that changed from the base of the PR and between abeb82e and ec641ac.

⛔ Files ignored due to path filters (3)
  • qa/1418.out is excluded by !**/*.out
  • qa/1670.out is excluded by !**/*.out
  • qa/369.out is excluded by !**/*.out
📒 Files selected for processing (32)
  • man/man3/pmiaddinstance.3
  • man/man3/pmiaddmetric.3
  • man/man3/pmiend.3
  • man/man3/pmigethandle.3
  • man/man3/pmiputlabel.3
  • man/man3/pmiputmark.3
  • man/man3/pmiputresult.3
  • man/man3/pmiputtext.3
  • man/man3/pmiputvalue.3
  • man/man3/pmiputvaluehandle.3
  • man/man3/pmisethostname.3
  • man/man3/pmisettimezone.3
  • man/man3/pmisetversion.3
  • man/man3/pmistart.3
  • man/man3/pmiunits.3
  • man/man3/pmiwrite.3
  • qa/1670
  • qa/group
  • qa/src/.gitignore
  • qa/src/GNUlocaldefs
  • qa/src/check_import.c
  • qa/src/check_import_append.c
  • src/include/pcp/import.h
  • src/include/pcp/libpcp.h
  • src/libpcp/src/exports.in
  • src/libpcp/src/logutil.c
  • src/libpcp_import/src/archive.c
  • src/libpcp_import/src/exports
  • src/libpcp_import/src/import.c
  • src/libpcp_import/src/private.h
  • src/libpcp_import/src/stuff.c
  • src/python/pcp/pmi.py

Comment thread qa/group Outdated
Comment thread src/libpcp_import/src/archive.c
Comment thread src/libpcp_import/src/import.c
Comment thread src/libpcp/src/logutil.c Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/libpcp/src/logutil.c`:
- Around line 411-418: The early-return after __pmLogChkLabel failure in
__pmLogOpenAppend (which currently calls __pmLogFreeLabel, __pmFclose on
lcp->mdfp and lcp->tifp and returns sts) must be changed to use the shared
cleanup path: remove the direct closes/return and instead jump to a common
failure label that calls __pmLogClose(acp) and logFreeMeta(lcp) (so lcp->label
and lcp->name/meta are freed) before returning sts; apply the same change to the
other early-return branches in __pmLogOpenAppend to ensure all error exits
funnel through the same cleanup sequence.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 16472fcd-c22f-433d-89a4-eea88554bcc4

📥 Commits

Reviewing files that changed from the base of the PR and between ad79e75 and e1187d2.

📒 Files selected for processing (1)
  • src/libpcp/src/logutil.c

Comment thread src/libpcp/src/logutil.c Outdated
@natoscott natoscott force-pushed the pmi-append-mode branch 8 times, most recently from 548a7ec to b119458 Compare June 16, 2026 03:08
natoscott and others added 11 commits June 19, 2026 18:42
Rename the second argument of pmiStart() from the implicit boolean
'inherit' to an explicit 'flags' field.  Named constants are now
provided in import.h:

  PMI_INHERIT (0x1) - existing behaviour: inherit metric definitions
                      from the current context into the new one
  PMI_APPEND  (0x2) - open an existing archive for appending instead
                      of creating a new one

pmiStart() with PMI_APPEND opens the named archive if it already
exists and positions all file handles at end-of-file, loading the
existing metadata so that subsequent pmiWrite() calls append new
records after the last existing record.  If the archive does not
yet exist the flag is silently ignored and a new archive is created,
making PMI_APPEND safe for unconditional use in timer-driven
collectors (e.g. sadc) on first invocation.

Add QA test 1693 to exercise the append mode.

Signed-off-by: Nathan Scott <nathans@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
pmiWrite2(int64_t sec, int usec) and pmiHighResWrite(int64_t sec, int nsec)
were already implemented and exported from the shared library but were
missing from the public import.h header, making them unusable by callers
without forward-declaring them manually.

Add declarations for both and deprecate pmiWrite(int, int) with a comment:
its 32-bit seconds argument is not Y2038-safe and callers should migrate to
pmiHighResWrite() for nanosecond-resolution timestamps or pmiWrite2() for
microsecond resolution.

Signed-off-by: Nathan Scott <nathans@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
logutil.c: rework __pmLogOpenAppend() to use __pmLogFindOpen() for
volume discovery.  Previously we iterated using lcp->numti (temporal
index count) as a starting hint; this bypassed the canonical readdir +
__pmLogAddVolume path.  Now:

 - __pmLogFindOpen() performs the directory scan, correctly setting
   lcp->name, lcp->minvol and lcp->maxvol via __pmLogAddVolume.
 - .meta and .index handles from __pmLogFindOpen (read mode) are used
   to validate the archive label and load the temporal index for
   lcp->endtime, then closed and reopened in r+ mode for writing.
 - The highest data volume (lcp->maxvol) is opened in r+ mode so its
   label is validated with __pmLogChkLabel before appending, matching
   the consistency checking done by __pmLogChangeVol in the read path.
 - acp->ac_flags |= PM_CTXFLAG_LAST_VOLUME signals that we are at the
   most recent volume, following the __pmLogOpen convention.

import.h: expose pmiWrite2, pmiHighResWrite and pmiPutHighResResult as
the preferred Y2038-safe interfaces.  pmiWrite(int,int) is marked
deprecated.

pmiwrite.3: document pmiWrite, pmiWrite2 and pmiHighResWrite on one
page; note pmiWrite as deprecated and pmiHighResWrite as preferred.

pmiputresult.3: document pmiPutResult and pmiPutHighResResult together;
note pmiPutHighResResult as the preferred nanosecond-resolution variant.

Signed-off-by: Nathan Scott <nathans@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add pmiPutAtomValueHandle(int handle, pmAtomValue *atom) as a binary
counterpart to pmiPutValueHandle, passing values directly via the
pmAtomValue union rather than as strings requiring parsing.

Refactor stuff.c to extract _pmi_alloc_vp and _pmi_alloc_valblock
static helpers, eliminating the duplicated result/vset/vp setup and
pmValueBlock allocation that both _pmi_stuff_value and the new
_pmi_stuff_atomvalue share.

Update pmiputvaluehandle.3 and exercise the new function in
qa/src/check_import.c covering the INSITU path (U32), DPTR path
(64-bit), bad-handle and duplicate-value error cases.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Nathan Scott <nathans@redhat.com>
Add a Python SYNOPSIS section to each libpcp_import man page that has
a Python binding in src/python/pcp/pmi.py.  The Python API wraps the C
library via the pmi.pmiLogImport class; methods are called on an
instance.  Multi-line call signatures use the same continuation-indent
style as the existing Perl SYNOPSIS sections.

pmiputresult.3 gains a Python-only synopsis (Perl has no binding for
pmiPutResult/pmiPutHighResResult).  pmisetversion.3 gains both Perl and
Python synopses, fixing a pre-existing omission.  pmiusecontext.3 and
pmierrstr.3 are left without a Python synopsis as pmi.pmiLogImport
handles context switching internally and surfaces errors as exceptions.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Nathan Scott <nathans@redhat.com>
Annotate all method signatures in the pmiLogImport class with PEP 484
type hints, compatible with the project's Python 3.6 minimum.

Return types reflect actual Python-level values (int status, pmID,
pmInDom, pmUnits, None).  String parameters are annotated as str since
bytes encoding is an internal detail.  pmiPutValue/pmiGetHandle inst
parameters are Optional[str] to reflect the None-for-singular-metric
convention.  pmiWrite sec is Union[int, float, datetime] matching its
three-way dispatch.  Imports Optional and Union from typing.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Nathan Scott <nathans@redhat.com>
pmiPutAtomValueHandle: validate atom is non-NULL before passing to
_pmi_stuff_atomvalue, returning PM_ERR_ARG to avoid a segfault on
PM_TYPE_STRING metrics where atom->cp would be dereferenced.

archive.c _pmi_do_desc: when a descriptor for this PMID already exists
in the archive, verify it is compatible before skipping the write.
A package upgrade may have corrected an incorrect type, semantics,
instance domain or units for a metric, in which case the old archive
cannot be extended with new data.  Return PM_ERR_LOGCHANGETYPE,
PM_ERR_LOGCHANGESEM, PM_ERR_LOGCHANGEINDOM or PM_ERR_LOGCHANGEUNITS
as appropriate so the caller has a precise diagnosis.

qa/group: add local group to qa/1670 so the standard local sweep
picks up the new append-mode coverage.

Signed-off-by: Nathan Scott <nathans@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The condition 'if sec and not usec' fails when sec==0 because 0 is
falsy, leaving usec as None and causing pmiWrite2(0, None) to raise
TypeError against its c_int argtypes.  Change to 'if usec is None'
so the datetime/float dispatch and the usec=0 fallback always run
when usec was not supplied by the caller.

Add a pmiWrite(0) call at the start of qa/src/test_pmi.python to
cover this path, and update qa/708.out accordingly.

Signed-off-by: Nathan Scott <nathans@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add pmiSetVolumeSize(size_t max_bytes, void (*on_rotate)(const char *))
to libpcp_import.  After each successful pmiHighResWrite() or pmiWrite()
call, if the current data volume file size meets or exceeds max_bytes the
library closes the current volume, opens the next numbered volume (writing
a new label), and invokes the caller's callback with the path of the
just-closed volume so compression or other post-processing can be arranged.
Passing max_bytes=0 disables rotation (the default).

Guard: pmiSetVolumeSize() rejects a threshold at or below the on-disk
label size for the configured archive version.  Accepting a sub-label
threshold would cause a rotation cascade since every new volume's label
immediately exceeds the threshold.  The check uses the public pmapi.h
field-width constants to avoid a dependency on the file-static
__pmLabel_v2/v3 types.

Also: replace the magic number 100000 in _pmi_put_result() with the
named constant PMI_FLUSH_INTERVAL throughout archive.c.

Also: pair consecutive int fields in pmi_context (private.h) to eliminate
four bytes of alignment padding before each pointer on 64-bit platforms.
The struct is private to libpcp_import so there is no ABI constraint.

QA: check_volsize.c exercises rotation, callback, size-bound and label-size
    guard; wired into qa/1693 (the existing PMI_APPEND test) with a
    pmlogcheck step to verify multi-volume archive integrity.

Signed-off-by: Nathan Scott <nathans@redhat.com>
PCP v3 archives have a 'zoneinfo' label field for the full Olson
database timezone identifier (e.g. "Australia/Brisbane"), which gives
tools DST-correct replay without ambiguity.  pmiSetTimezone() only
sets the POSIX abbreviated form ("AEST-10") and was incorrectly
clearing zoneinfo when applying it to the label.

Add pmiSetZoneinfo(const char *value) which sets the zoneinfo field
independently, modelled on pmiSetTimezone().  Passing NULL auto-detects
the local Olson name via __pmZoneinfo() (libpcp tz.c), which handles
both the /etc/localtime symlink case and the recursive file-content
matching fallback.

Signed-off-by: Nathan Scott <nathans@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Three sources of repeated metadata writes in PMI_APPEND mode:

Indoms: check_indom() had no dedup check so every append session
re-wrote all indom records regardless of whether membership had
changed.  For timer-driven collectors like sadc this caused O(N×S)
.meta growth where N is the number of processes and S is the number
of sessions per day.

Fix: compare the registered indom against the most recent entry in
hashindom (populated by __pmLogLoadMeta on append open).  For v3
archives use pmaDeltaInDom() — the same helper pmlogger uses — to
write a compact TYPE_INDOM_DELTA record when membership changes, and
update the hash with the full indom afterwards so the next comparison
starts from the correct state.  For v2 archives use pmaSameInDom()
and fall back to full indom writes.  Link -lpcp_archive for access
to pmaDeltaInDom() and pmaSameInDom().

Help text: _pmi_put_text() reset meta_done=0 each session via
pmiStart inherit, causing all help text to be re-written on every
append.  Fix: check __pmLogLookupText() before writing; skip if
content is unchanged.

Signed-off-by: Nathan Scott <nathans@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant