3176 lines
108 KiB
Diff
3176 lines
108 KiB
Diff
diff -Naurp pcp-5.0.2.orig/qa/1211.out pcp-5.0.2/qa/1211.out
|
|
--- pcp-5.0.2.orig/qa/1211.out 2019-12-06 15:18:26.000000000 +1100
|
|
+++ pcp-5.0.2/qa/1211.out 2020-02-03 13:23:15.258762963 +1100
|
|
@@ -144,6 +144,9 @@ kernel.uname.nodename
|
|
kernel.uname.release
|
|
kernel.uname.sysname
|
|
kernel.uname.version
|
|
+pmcd.pmlogger.archive
|
|
+pmcd.pmlogger.host
|
|
+pmcd.pmlogger.port
|
|
proc.fd.count
|
|
proc.id.egid
|
|
proc.id.egid_nm
|
|
@@ -267,6 +270,7 @@ List all instance names ...
|
|
030016 pmlogger -P -c config.default 20110930.17.20
|
|
1 minute
|
|
15 minute
|
|
+2950
|
|
5 minute
|
|
cpu0
|
|
cpu1
|
|
@@ -398,10 +402,10 @@ fecd5a4b4c6e1273eaa001287a6dd57b7bbd19f7
|
|
Values fetch for a single-valued query ...
|
|
|
|
d51624d12da45900bfee2fd73f1e23f3ccabb784
|
|
- [Mon Oct 3 09:10:22.959242000 2011] 172598244
|
|
- [Mon Oct 3 09:10:23.300460000 2011] 172598364
|
|
- [Mon Oct 3 09:10:23.802930000 2011] 172598481
|
|
[Mon Oct 3 09:10:24.305845000 2011] 172598559
|
|
+ [Mon Oct 3 09:10:23.802930000 2011] 172598481
|
|
+ [Mon Oct 3 09:10:23.300460000 2011] 172598364
|
|
+ [Mon Oct 3 09:10:22.959242000 2011] 172598244
|
|
|
|
Values fetch with a one-second interval ...
|
|
|
|
@@ -420,15 +424,18 @@ d51624d12da45900bfee2fd73f1e23f3ccabb784
|
|
Values fetch for a multi-valued query ...
|
|
|
|
fecd5a4b4c6e1273eaa001287a6dd57b7bbd19f7
|
|
- [Mon Oct 3 09:10:23.300460000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
|
|
- [Mon Oct 3 09:10:23.300460000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
|
|
- [Mon Oct 3 09:10:23.300460000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
|
|
- [Mon Oct 3 09:10:23.802930000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
|
|
- [Mon Oct 3 09:10:23.802930000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
|
|
- [Mon Oct 3 09:10:23.802930000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
|
|
[Mon Oct 3 09:10:24.305845000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
|
|
[Mon Oct 3 09:10:24.305845000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
|
|
[Mon Oct 3 09:10:24.305845000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
|
|
+ [Mon Oct 3 09:10:23.802930000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
|
|
+ [Mon Oct 3 09:10:23.802930000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
|
|
+ [Mon Oct 3 09:10:23.802930000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
|
|
+ [Mon Oct 3 09:10:23.300460000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
|
|
+ [Mon Oct 3 09:10:23.300460000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
|
|
+ [Mon Oct 3 09:10:23.300460000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
|
|
+ [Mon Oct 3 09:10:22.959242000 2011] 0.000000e+00 59181b1de54ff2b383cfd1cdd8636f86c880b69b
|
|
+ [Mon Oct 3 09:10:22.959242000 2011] 2.000000e-02 ab010c7d45145aa33c8f8fa681a68c9d4102ae19
|
|
+ [Mon Oct 3 09:10:22.959242000 2011] 5.000000e-02 9d418095c9f971ff4fd44d6828ead27f9d021dc3
|
|
|
|
Multi-series lookups from a multi-series query ...
|
|
2db1da4d276d81c42c578c2829e99188ae7cc898
|
|
diff -Naurp pcp-5.0.2.orig/qa/1573 pcp-5.0.2/qa/1573
|
|
--- pcp-5.0.2.orig/qa/1573 1970-01-01 10:00:00.000000000 +1000
|
|
+++ pcp-5.0.2/qa/1573 2020-02-03 13:36:17.288581801 +1100
|
|
@@ -0,0 +1,103 @@
|
|
+#!/bin/sh
|
|
+# PCP QA Test No. 1573
|
|
+# Exercise libpcp_web memory leak without a redis-server.
|
|
+#
|
|
+# Copyright (c) 2020 Red Hat.
|
|
+#
|
|
+
|
|
+seq=`basename $0`
|
|
+echo "QA output created by $seq"
|
|
+
|
|
+# get standard environment, filters and checks
|
|
+. ./common.product
|
|
+. ./common.filter
|
|
+. ./common.check
|
|
+
|
|
+_check_series
|
|
+
|
|
+_cleanup()
|
|
+{
|
|
+ cd $here
|
|
+ if $need_restore
|
|
+ then
|
|
+ need_restore=false
|
|
+ _service pmlogger stop >/dev/null
|
|
+ $sudo rm -rf $PCP_LOG_DIR/pmlogger
|
|
+ $sudo mv $PCP_LOG_DIR/pmlogger.$seq $PCP_LOG_DIR/pmlogger
|
|
+ _restore_config $PCP_ETC_DIR/pcp/pmlogger
|
|
+ _service pcp restart 2>&1 | _filter_pcp_stop | _filter_pcp_start
|
|
+ _wait_for_pmcd
|
|
+ _wait_for_pmlogger
|
|
+ echo === restarting pmproxy
|
|
+ _restore_config $PCP_SYSCONF_DIR/pmproxy
|
|
+ _service pmproxy restart 2>&1 | _filter_pcp_start
|
|
+ _wait_for_pmproxy
|
|
+ fi
|
|
+ $sudo rm -rf $tmp $tmp.*
|
|
+}
|
|
+
|
|
+status=1 # failure is the default!
|
|
+need_restore=false
|
|
+$sudo rm -rf $tmp $tmp.* $seq.full
|
|
+trap "_cleanup; exit \$status" 0 1 2 3 15
|
|
+
|
|
+# real QA test starts here
|
|
+_save_config $PCP_SYSCONF_DIR/pmproxy
|
|
+need_restore=true
|
|
+
|
|
+# only want the primary logger running
|
|
+_save_config $PCP_ETC_DIR/pcp/pmlogger
|
|
+_restore_pmlogger_control
|
|
+
|
|
+#$sudo rm -f $PCP_SYSCONF_DIR/pmproxy/*
|
|
+echo "[pmproxy]" > $tmp.conf
|
|
+echo "pcp.enabled = true" >> $tmp.conf
|
|
+echo "http.enabled = true" >> $tmp.conf
|
|
+echo "redis.enabled = true" >> $tmp.conf
|
|
+echo "[discover]" >> $tmp.conf
|
|
+echo "enabled = true" >> $tmp.conf
|
|
+echo "[pmseries]" >> $tmp.conf
|
|
+echo "enabled = false" >> $tmp.conf
|
|
+$sudo cp $tmp.conf $PCP_SYSCONF_DIR/pmproxy/pmproxy.conf
|
|
+
|
|
+_service pmlogger stop >/dev/null
|
|
+
|
|
+# move aside existing logs so we can measure base memory footprint
|
|
+[ -d $PCP_LOG_DIR/pmlogger.$seq ] && $sudo mv $PCP_LOG_DIR/pmlogger.$seq $PCP_LOG_DIR/pmlogger.$seq.saved
|
|
+$sudo mv $PCP_LOG_DIR/pmlogger $PCP_LOG_DIR/pmlogger.$seq
|
|
+$sudo mkdir -p $PCP_LOG_DIR/pmlogger
|
|
+$sudo chmod 775 $PCP_LOG_DIR/pmlogger
|
|
+$sudo chown $PCP_USER:$PCP_USER $PCP_LOG_DIR/pmlogger
|
|
+
|
|
+_service pmproxy restart 2>&1 | _filter_pcp_stop | _filter_pcp_start
|
|
+_wait_for_pmproxy
|
|
+
|
|
+pmproxy_pid=`_get_pids_by_name -a pmproxy`
|
|
+[ -z "$pmproxy_pid" ] && echo === pmproxy not running && status=1 && exit 1
|
|
+echo === extract initial rss
|
|
+pmproxy_rss1=`pminfo -f proc.memory.rss |
|
|
+ $PCP_AWK_PROG '{ if ($2 == "['$pmproxy_pid'") { print $NF} }'`
|
|
+
|
|
+echo === restarting pmlogger # primary only
|
|
+_service pmlogger restart 2>&1 | _filter_pcp_start
|
|
+_wait_for_pmlogger
|
|
+
|
|
+echo === wait for pmproxy to process filesystem events
|
|
+pmsleep 4.2
|
|
+
|
|
+echo === extract updated rss
|
|
+pmproxy_rss2=`pminfo -f proc.memory.rss |
|
|
+ $PCP_AWK_PROG '{ if ($2 == "['$pmproxy_pid'") { print $NF} }'`
|
|
+
|
|
+echo === checking rss within tolerance
|
|
+_within_tolerance "rss" $pmproxy_rss1 $pmproxy_rss2 10%
|
|
+[ $pmproxy_rss2 -gt 10000 ] && echo "Unexpected pmproxy RSS: $pmproxy_rss2, was initially $pmproxy_rss1"
|
|
+
|
|
+echo "RSS1 for PID $pmproxy_pid is $pmproxy_rss1" >> $here/$seq.full
|
|
+echo "RSS2 for PID $pmproxy_pid is $pmproxy_rss2" >> $here/$seq.full
|
|
+cat $PCP_LOG_DIR/pmproxy/pmproxy.log >>$seq.full
|
|
+echo === see $seq.full for pmproxy rss and logs
|
|
+
|
|
+# success, all done
|
|
+status=0
|
|
+exit
|
|
diff -Naurp pcp-5.0.2.orig/qa/1573.out pcp-5.0.2/qa/1573.out
|
|
--- pcp-5.0.2.orig/qa/1573.out 1970-01-01 10:00:00.000000000 +1000
|
|
+++ pcp-5.0.2/qa/1573.out 2020-02-03 13:23:15.259762953 +1100
|
|
@@ -0,0 +1,8 @@
|
|
+QA output created by 1573
|
|
+=== extract initial rss
|
|
+=== restarting pmlogger
|
|
+=== wait for pmproxy to process filesystem events
|
|
+=== extract updated rss
|
|
+=== checking rss within tolerance
|
|
+=== see 1573.full for pmproxy rss and logs
|
|
+=== restarting pmproxy
|
|
diff -Naurp pcp-5.0.2.orig/qa/1600 pcp-5.0.2/qa/1600
|
|
--- pcp-5.0.2.orig/qa/1600 2019-12-10 17:49:05.000000000 +1100
|
|
+++ pcp-5.0.2/qa/1600 2020-02-03 13:23:15.260762942 +1100
|
|
@@ -82,7 +82,11 @@ _filter_values()
|
|
_filter_label_values()
|
|
{
|
|
sed \
|
|
+ -e "s/^domainname: \"${domainname}\"/domainname: \"DOMAIN\"/g" \
|
|
+ -e "s/^machineid: \"${machineid}\"/machineid: \"MACHINE\"/g" \
|
|
-e "s/^hostname: \"${hostname}\"/hostname: \"HOSTNAME\"/g" \
|
|
+ -e "s/^groupid: $groupid/groupid: GID/g" \
|
|
+ -e "s/^userid: $userid/userid: UID/g" \
|
|
-e "s/changed: false, true/changed: false/g" \
|
|
-e "/metric_label: null/d" \
|
|
#end
|
|
diff -Naurp pcp-5.0.2.orig/qa/1600.out pcp-5.0.2/qa/1600.out
|
|
--- pcp-5.0.2.orig/qa/1600.out 2019-12-10 10:46:20.000000000 +1100
|
|
+++ pcp-5.0.2/qa/1600.out 2020-02-03 13:23:15.260762942 +1100
|
|
@@ -27,15 +27,15 @@ TIMESERIES
|
|
== verify metric labels
|
|
|
|
TIMESERIES
|
|
- inst [100 or "bin-100"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
|
|
- inst [200 or "bin-200"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
|
|
- inst [300 or "bin-300"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
|
|
- inst [400 or "bin-400"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
|
|
- inst [500 or "bin-500"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
|
|
- inst [600 or "bin-600"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
|
|
- inst [700 or "bin-700"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
|
|
- inst [800 or "bin-800"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
|
|
- inst [900 or "bin-900"] labels {"agent":"sample","hostname":"HOST","role":"testing"}
|
|
+ inst [100 or "bin-100"] labels {"agent":"sample","bin":100,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
|
|
+ inst [200 or "bin-200"] labels {"agent":"sample","bin":200,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
|
|
+ inst [300 or "bin-300"] labels {"agent":"sample","bin":300,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
|
|
+ inst [400 or "bin-400"] labels {"agent":"sample","bin":400,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
|
|
+ inst [500 or "bin-500"] labels {"agent":"sample","bin":500,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
|
|
+ inst [600 or "bin-600"] labels {"agent":"sample","bin":600,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
|
|
+ inst [700 or "bin-700"] labels {"agent":"sample","bin":700,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
|
|
+ inst [800 or "bin-800"] labels {"agent":"sample","bin":800,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
|
|
+ inst [900 or "bin-900"] labels {"agent":"sample","bin":900,"domainname":"DOMAIN","groupid":GID,"hostname":"HOST","latitude":-25.28496,"longitude":152.87886,"machineid":"MACHINE","role":"testing","userid":UID}
|
|
== verify metric values
|
|
|
|
TIMESERIES
|
|
@@ -43,15 +43,24 @@ TIMESERIES
|
|
[TIMESTAMP] VALUE
|
|
== verify label names and values
|
|
agent: "mmv", "sample", "pmcd"
|
|
+bin: 100, 200, 300, 400, 500, 600, 700, 800, 900
|
|
changed: false
|
|
clan: "mcdonell"
|
|
cluster: "zero"
|
|
+domainname: "DOMAIN"
|
|
+groupid: GID
|
|
hostname: "HOSTNAME"
|
|
indom_label: 42.001
|
|
+latitude: -25.28496
|
|
+longitude: 152.87886
|
|
+machineid: "MACHINE"
|
|
measure: "speed"
|
|
model: "RGB"
|
|
+registry_label: "string"
|
|
role: "testing"
|
|
+transient: false, true
|
|
units: "metres per second"
|
|
unitsystem: "SI"
|
|
+userid: UID
|
|
== verify archive removal
|
|
== all done
|
|
diff -Naurp pcp-5.0.2.orig/qa/1601.out pcp-5.0.2/qa/1601.out
|
|
--- pcp-5.0.2.orig/qa/1601.out 2019-11-27 16:01:34.000000000 +1100
|
|
+++ pcp-5.0.2/qa/1601.out 2020-02-03 13:23:15.261762932 +1100
|
|
@@ -131,7 +131,7 @@ Using series 01d8bc7fa75aaff98a08aa0b1c0
|
|
{
|
|
"series": "605fc77742cd0317597291329561ac4e50c0dd12",
|
|
"instance": "c3795d8b757506a2901c6b08b489ba56cae7f0d4",
|
|
- "timestamp": 1317633023300.460,
|
|
+ "timestamp": 1317633024305.845,
|
|
"value": "71661"
|
|
},
|
|
{
|
|
@@ -147,7 +147,7 @@ Using series 01d8bc7fa75aaff98a08aa0b1c0
|
|
{
|
|
"series": "605fc77742cd0317597291329561ac4e50c0dd12",
|
|
"instance": "c3795d8b757506a2901c6b08b489ba56cae7f0d4",
|
|
- "timestamp": 1317633023300.460,
|
|
+ "timestamp": 1317633024305.845,
|
|
"value": "71661"
|
|
},
|
|
{
|
|
@@ -163,7 +163,7 @@ Using series 01d8bc7fa75aaff98a08aa0b1c0
|
|
{
|
|
"series": "605fc77742cd0317597291329561ac4e50c0dd12",
|
|
"instance": "c3795d8b757506a2901c6b08b489ba56cae7f0d4",
|
|
- "timestamp": 1317633023300.460,
|
|
+ "timestamp": 1317633024305.845,
|
|
"value": "71661"
|
|
},
|
|
{
|
|
@@ -179,7 +179,7 @@ Using series 01d8bc7fa75aaff98a08aa0b1c0
|
|
{
|
|
"series": "605fc77742cd0317597291329561ac4e50c0dd12",
|
|
"instance": "c3795d8b757506a2901c6b08b489ba56cae7f0d4",
|
|
- "timestamp": 1317633023300.460,
|
|
+ "timestamp": 1317633024305.845,
|
|
"value": "71661"
|
|
},
|
|
{
|
|
diff -Naurp pcp-5.0.2.orig/qa/1661 pcp-5.0.2/qa/1661
|
|
--- pcp-5.0.2.orig/qa/1661 2019-12-10 17:04:20.000000000 +1100
|
|
+++ pcp-5.0.2/qa/1661 2020-02-03 13:23:15.261762932 +1100
|
|
@@ -41,8 +41,7 @@ _restore_pmlogger_control
|
|
echo;echo === restarting pmproxy service to ensure sane starting condition
|
|
_service pmlogger stop 2>&1 | _filter_pcp_stop
|
|
_service pmproxy restart 2>&1 | _filter_pcp_stop | _filter_pcp_start
|
|
-# give pmproxy a chance to startup
|
|
-pmsleep 2; _wait_for_pmproxy
|
|
+_wait_for_pmproxy
|
|
|
|
pmproxy_pid=`_get_pids_by_name -a pmproxy`
|
|
[ -z "$pmproxy_pid" ] && echo === pmproxy not running && status=1 && exit 1
|
|
diff -Naurp pcp-5.0.2.orig/qa/group pcp-5.0.2/qa/group
|
|
--- pcp-5.0.2.orig/qa/group 2019-12-11 14:06:06.000000000 +1100
|
|
+++ pcp-5.0.2/qa/group 2020-02-03 13:23:15.261762932 +1100
|
|
@@ -1688,6 +1688,7 @@ BAD
|
|
1545 pcp2xml python pcp2xxx local
|
|
1546 pmrep python local
|
|
1547 pmrep python local
|
|
+1573 pmproxy libpcp_web pmlogger local
|
|
1588 python pmiostat local
|
|
1598 pmda.statsd local
|
|
1599 pmda.statsd local
|
|
diff -Naurp pcp-5.0.2.orig/src/include/pcp/libpcp.h pcp-5.0.2/src/include/pcp/libpcp.h
|
|
--- pcp-5.0.2.orig/src/include/pcp/libpcp.h 2019-09-24 17:23:36.000000000 +1000
|
|
+++ pcp-5.0.2/src/include/pcp/libpcp.h 2020-02-03 13:23:15.261762932 +1100
|
|
@@ -7,7 +7,7 @@
|
|
* remain fixed across releases, and they may not work, or may
|
|
* provide different semantics at some point in the future.
|
|
*
|
|
- * Copyright (c) 2012-2019 Red Hat.
|
|
+ * Copyright (c) 2012-2020 Red Hat.
|
|
* Copyright (c) 2008-2009 Aconex. All Rights Reserved.
|
|
* Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved.
|
|
*
|
|
@@ -846,6 +846,13 @@ PCP_CALL extern int __pmLogPutText(__pmA
|
|
PCP_CALL extern int __pmLogWriteLabel(__pmFILE *, const __pmLogLabel *);
|
|
PCP_CALL extern int __pmLogLoadLabel(__pmArchCtl *, const char *);
|
|
PCP_CALL extern int __pmLogLoadMeta(__pmArchCtl *);
|
|
+PCP_CALL extern int __pmLogAddDesc(__pmArchCtl *, const pmDesc *);
|
|
+PCP_CALL extern int __pmLogAddInDom(__pmArchCtl *, const pmTimespec *, const pmInResult *, int *, int);
|
|
+PCP_CALL extern int __pmLogAddPMNSNode(__pmArchCtl *, pmID, const char *);
|
|
+PCP_CALL extern int __pmLogAddLabelSets(__pmArchCtl *, const pmTimespec *, unsigned int, unsigned int, int, pmLabelSet *);
|
|
+PCP_CALL extern int __pmLogAddText(__pmArchCtl *, unsigned int, unsigned int, const char *);
|
|
+PCP_CALL extern int __pmLogAddVolume(__pmArchCtl *, unsigned int);
|
|
+
|
|
#define PMLOGREAD_NEXT 0
|
|
#define PMLOGREAD_TO_EOF 1
|
|
PCP_CALL extern int __pmLogRead(__pmArchCtl *, int, __pmFILE *, pmResult **, int);
|
|
@@ -862,7 +869,9 @@ PCP_CALL extern int __pmLogLookupText(__
|
|
PCP_CALL extern int __pmLogNameInDom(__pmArchCtl *, pmInDom, pmTimeval *, int, char **);
|
|
PCP_CALL extern const char *__pmLogLocalSocketDefault(int, char *buf, size_t bufSize);
|
|
PCP_CALL extern const char *__pmLogLocalSocketUser(int, char *buf, size_t bufSize);
|
|
+PCP_CALL extern int __pmLogCompressedSuffix(const char *);
|
|
PCP_CALL extern char *__pmLogBaseName(char *);
|
|
+PCP_CALL extern char *__pmLogBaseNameVol(char *, int *);
|
|
PCP_DATA extern int __pmLogReads;
|
|
|
|
/* Convert opaque context handle to __pmContext pointer */
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp/src/exports.master pcp-5.0.2/src/libpcp/src/exports.master
|
|
--- pcp-5.0.2.orig/src/libpcp/src/exports.master 2019-10-02 14:40:30.000000000 +1000
|
|
+++ pcp-5.0.2/src/libpcp/src/exports.master 2020-02-03 13:23:15.262762921 +1100
|
|
@@ -683,3 +683,15 @@ PCP_3.26 {
|
|
global:
|
|
__pmDupLabelSets;
|
|
} PCP_3.25;
|
|
+
|
|
+PCP_3.26_1 {
|
|
+ global:
|
|
+ __pmLogAddDesc;
|
|
+ __pmLogAddInDom;
|
|
+ __pmLogAddPMNSNode;
|
|
+ __pmLogAddLabelSets;
|
|
+ __pmLogAddText;
|
|
+ __pmLogAddVolume;
|
|
+ __pmLogCompressedSuffix;
|
|
+ __pmLogBaseNameVol;
|
|
+} PCP_3.26;
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp/src/io.c pcp-5.0.2/src/libpcp/src/io.c
|
|
--- pcp-5.0.2.orig/src/libpcp/src/io.c 2018-06-09 11:43:34.000000000 +1000
|
|
+++ pcp-5.0.2/src/libpcp/src/io.c 2020-02-03 13:23:15.262762921 +1100
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2017-2018 Red Hat.
|
|
+ * Copyright (c) 2017-2018,2020 Red Hat.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published
|
|
@@ -47,7 +47,7 @@ extern __pm_fops __pm_xz;
|
|
#endif
|
|
|
|
static const struct {
|
|
- const char *suff;
|
|
+ const char *suffix;
|
|
const int appl;
|
|
__pm_fops *handler;
|
|
} compress_ctl[] = {
|
|
@@ -61,40 +61,43 @@ static const struct {
|
|
};
|
|
static const int ncompress = sizeof(compress_ctl) / sizeof(compress_ctl[0]);
|
|
|
|
+int
|
|
+__pmLogCompressedSuffix(const char *suffix)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < ncompress; i++)
|
|
+ if (strcmp(suffix, compress_ctl[i].suffix) == 0)
|
|
+ return 1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
- * If name contains '.' and the suffix is "index", "meta" or a string of
|
|
- * digits, all optionally followed by one of the compression suffixes,
|
|
- * strip the suffix.
|
|
- *
|
|
- * Modifications are performed on the argument string in-place. If modifications
|
|
- * are made, a pointer to the start of the modified string is returned.
|
|
- * Otherwise, NULL is returned.
|
|
+ * Variant of __pmLogBaseName() - see below that also returns log
|
|
+ * the volume number if the file name is an archive log volume.
|
|
+ * If the vol argument is NULL it will be ignored.
|
|
*/
|
|
char *
|
|
-__pmLogBaseName(char *name)
|
|
+__pmLogBaseNameVol(char *name, int *vol)
|
|
{
|
|
- char *q;
|
|
- int strip;
|
|
- int i;
|
|
+ char *q, *q2;
|
|
+ int strip = 0;
|
|
|
|
- strip = 0;
|
|
+ if (vol)
|
|
+ *vol = -1;
|
|
if ((q = strrchr(name, '.')) != NULL) {
|
|
- for (i = 0; i < ncompress; i++) {
|
|
- if (strcmp(q, compress_ctl[i].suff) == 0) {
|
|
- char *q2;
|
|
- /*
|
|
- * The name ends with one of the supported compressed file
|
|
- * suffixes. Strip it before checking for other known suffixes.
|
|
- */
|
|
- *q = '\0';
|
|
- if ((q2 = strrchr(name, '.')) == NULL) {
|
|
- /* no . to the left of the suffix */
|
|
- *q = '.';
|
|
- goto done;
|
|
- }
|
|
- q = q2;
|
|
- break;
|
|
+ if (__pmLogCompressedSuffix(q)) {
|
|
+ /*
|
|
+ * The name ends with one of the supported compressed file
|
|
+ * suffixes. Strip it before checking for other known suffixes.
|
|
+ */
|
|
+ *q = '\0';
|
|
+ if ((q2 = strrchr(name, '.')) == NULL) {
|
|
+ /* no . to the left of the suffix */
|
|
+ *q = '.';
|
|
+ goto done;
|
|
}
|
|
+ q = q2;
|
|
}
|
|
if (strcmp(q, ".index") == 0) {
|
|
strip = 1;
|
|
@@ -109,16 +112,10 @@ __pmLogBaseName(char *name)
|
|
*/
|
|
if (q[1] != '\0') {
|
|
char *end;
|
|
- /*
|
|
- * Below we don't care about the value from strtol(),
|
|
- * we're interested in updating the pointer "end".
|
|
- * The messiness is thanks to gcc and glibc ... strtol()
|
|
- * is marked __attribute__((warn_unused_result)) ...
|
|
- * to avoid warnings on all platforms, assign to a
|
|
- * dummy variable that is explicitly marked unused.
|
|
- */
|
|
- long tmpl __attribute__((unused));
|
|
+ long tmpl;
|
|
tmpl = strtol(q+1, &end, 10);
|
|
+ if (vol)
|
|
+ *vol = tmpl;
|
|
if (*end == '\0') strip = 1;
|
|
}
|
|
}
|
|
@@ -131,6 +128,21 @@ done:
|
|
return NULL; /* not the name of an archive file. */
|
|
}
|
|
|
|
+/*
|
|
+ * If name contains '.' and the suffix is "index", "meta" or a string of
|
|
+ * digits, all optionally followed by one of the compression suffixes,
|
|
+ * strip the suffix.
|
|
+ *
|
|
+ * Modifications are performed on the argument string in-place. If modifications
|
|
+ * are made, a pointer to the start of the modified string is returned.
|
|
+ * Otherwise, NULL is returned.
|
|
+ */
|
|
+char *
|
|
+__pmLogBaseName(char *name)
|
|
+{
|
|
+ return __pmLogBaseNameVol(name, NULL);
|
|
+}
|
|
+
|
|
static int
|
|
popen_uncompress(const char *cmd, const char *arg, const char *fname, int fd)
|
|
{
|
|
@@ -319,7 +331,7 @@ __pmCompressedFileIndex(char *fname, siz
|
|
char tmpname[MAXPATHLEN];
|
|
|
|
for (i = 0; i < ncompress; i++) {
|
|
- suffix = compress_ctl[i].suff;
|
|
+ suffix = compress_ctl[i].suffix;
|
|
pmsprintf(tmpname, sizeof(tmpname), "%s%s", fname, suffix);
|
|
sts = access(tmpname, R_OK);
|
|
if (sts == 0 || (errno != ENOENT && errno != ENOTDIR)) {
|
|
@@ -358,7 +370,7 @@ index_compress(char *fname, size_t flen)
|
|
suffix = strrchr(fname, '.');
|
|
if (suffix != NULL) {
|
|
for (i = 0; i < ncompress; i++) {
|
|
- if (strcmp(suffix, compress_ctl[i].suff) == 0)
|
|
+ if (strcmp(suffix, compress_ctl[i].suffix) == 0)
|
|
return i;
|
|
}
|
|
}
|
|
@@ -731,7 +743,7 @@ compress_suffix_list(void)
|
|
const char *q;
|
|
|
|
for (i = 0; i < ncompress; i++) {
|
|
- q = compress_ctl[i].suff;
|
|
+ q = compress_ctl[i].suffix;
|
|
if (i > 0)
|
|
*p++ = ' ';
|
|
while (*q) {
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp/src/logmeta.c pcp-5.0.2/src/libpcp/src/logmeta.c
|
|
--- pcp-5.0.2.orig/src/libpcp/src/logmeta.c 2018-09-14 10:22:56.000000000 +1000
|
|
+++ pcp-5.0.2/src/libpcp/src/logmeta.c 2020-02-03 13:23:15.262762921 +1100
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2013-2018 Red Hat.
|
|
+ * Copyright (c) 2013-2018, 2020 Red Hat.
|
|
* Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it
|
|
@@ -490,7 +490,7 @@ check_dup_labels(const __pmArchCtl *acp)
|
|
}
|
|
|
|
static int
|
|
-addtext(__pmArchCtl *acp, unsigned int ident, unsigned int type, char *buffer)
|
|
+addtext(__pmArchCtl *acp, unsigned int ident, unsigned int type, const char *buffer)
|
|
{
|
|
__pmLogCtl *lcp = acp->ac_log;
|
|
__pmHashNode *hp;
|
|
@@ -553,6 +553,92 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":15",
|
|
return sts;
|
|
}
|
|
|
|
+int
|
|
+__pmLogAddDesc(__pmArchCtl *acp, const pmDesc *newdp)
|
|
+{
|
|
+ __pmHashNode *hp;
|
|
+ __pmLogCtl *lcp = acp->ac_log;
|
|
+ pmDesc *dp, *olddp;
|
|
+
|
|
+ if ((hp = __pmHashSearch((int)newdp->pmid, &lcp->l_hashpmid)) != NULL) {
|
|
+ /* PMID is already in the hash table - check for conflicts. */
|
|
+ olddp = (pmDesc *)hp->data;
|
|
+ if (newdp->type != olddp->type)
|
|
+ return PM_ERR_LOGCHANGETYPE;
|
|
+ if (newdp->sem != olddp->sem)
|
|
+ return PM_ERR_LOGCHANGESEM;
|
|
+ if (newdp->indom != olddp->indom)
|
|
+ return PM_ERR_LOGCHANGEINDOM;
|
|
+ if (newdp->units.dimSpace != olddp->units.dimSpace ||
|
|
+ newdp->units.dimTime != olddp->units.dimTime ||
|
|
+ newdp->units.dimCount != olddp->units.dimCount ||
|
|
+ newdp->units.scaleSpace != olddp->units.scaleSpace ||
|
|
+ newdp->units.scaleTime != olddp->units.scaleTime ||
|
|
+ newdp->units.scaleCount != olddp->units.scaleCount)
|
|
+ return PM_ERR_LOGCHANGEUNITS;
|
|
+
|
|
+ /* PMID is already known and checks out - we're done here. */
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Add a copy of the descriptor into the PMID:desc hash table. */
|
|
+PM_FAULT_POINT("libpcp/" __FILE__ ":2", PM_FAULT_ALLOC);
|
|
+ if ((dp = (pmDesc *)malloc(sizeof(pmDesc))) == NULL)
|
|
+ return -oserror();
|
|
+ *dp = *newdp;
|
|
+
|
|
+ return __pmHashAdd((int)dp->pmid, (void *)dp, &lcp->l_hashpmid);
|
|
+}
|
|
+
|
|
+int
|
|
+__pmLogAddPMNSNode(__pmArchCtl *acp, pmID pmid, const char *name)
|
|
+{
|
|
+ __pmLogCtl *lcp = acp->ac_log;
|
|
+ int sts;
|
|
+
|
|
+ /*
|
|
+ * If we see a duplicate name with a different PMID, its a
|
|
+ * recoverable error.
|
|
+ * We wont be able to see all of the data in the log, but
|
|
+ * its better to provide access to some rather than none,
|
|
+ * esp. when only one or two metric IDs may be corrupted
|
|
+ * in this way (which we may not be interested in anyway).
|
|
+ */
|
|
+ sts = __pmAddPMNSNode(lcp->l_pmns, pmid, name);
|
|
+ if (sts == PM_ERR_PMID)
|
|
+ sts = 0;
|
|
+ return sts;
|
|
+}
|
|
+
|
|
+int
|
|
+__pmLogAddInDom(__pmArchCtl *acp, const pmTimespec *when, const pmInResult *in,
|
|
+ int *tbuf, int allinbuf)
|
|
+{
|
|
+ pmTimeval tv;
|
|
+
|
|
+ tv.tv_sec = when->tv_sec;
|
|
+ tv.tv_usec = when->tv_nsec / 1000;
|
|
+ return addindom(acp->ac_log, in->indom, &tv,
|
|
+ in->numinst, in->instlist, in->namelist, tbuf, allinbuf);
|
|
+}
|
|
+
|
|
+int
|
|
+__pmLogAddLabelSets(__pmArchCtl *acp, const pmTimespec *when, unsigned int type,
|
|
+ unsigned int ident, int nsets, pmLabelSet *labelsets)
|
|
+{
|
|
+ pmTimeval tv;
|
|
+
|
|
+ tv.tv_sec = when->tv_sec;
|
|
+ tv.tv_usec = when->tv_nsec / 1000;
|
|
+ return addlabel(acp, type, ident, nsets, labelsets, &tv);
|
|
+}
|
|
+
|
|
+int
|
|
+__pmLogAddText(__pmArchCtl *acp, unsigned int ident, unsigned int type, const char *buffer)
|
|
+{
|
|
+ return addtext(acp, ident, type, buffer);
|
|
+}
|
|
+
|
|
/*
|
|
* Load _all_ of the hashed pmDesc and __pmLogInDom structures from the metadata
|
|
* log file -- used at the initialization (NewContext) of an archive.
|
|
@@ -563,11 +649,8 @@ int
|
|
__pmLogLoadMeta(__pmArchCtl *acp)
|
|
{
|
|
__pmLogCtl *lcp = acp->ac_log;
|
|
- __pmHashNode *hp;
|
|
int rlen;
|
|
int check;
|
|
- pmDesc *dp;
|
|
- pmDesc *olddp;
|
|
int sts = 0;
|
|
__pmLogHdr h;
|
|
__pmFILE *f = lcp->l_mdfp;
|
|
@@ -615,13 +698,10 @@ __pmLogLoadMeta(__pmArchCtl *acp)
|
|
}
|
|
rlen = h.len - (int)sizeof(__pmLogHdr) - (int)sizeof(int);
|
|
if (h.type == TYPE_DESC) {
|
|
+ pmDesc desc;
|
|
+
|
|
numpmid++;
|
|
-PM_FAULT_POINT("libpcp/" __FILE__ ":2", PM_FAULT_ALLOC);
|
|
- if ((dp = (pmDesc *)malloc(sizeof(pmDesc))) == NULL) {
|
|
- sts = -oserror();
|
|
- goto end;
|
|
- }
|
|
- if ((n = (int)__pmFread(dp, 1, sizeof(pmDesc), f)) != sizeof(pmDesc)) {
|
|
+ if ((n = (int)__pmFread(&desc, 1, sizeof(pmDesc), f)) != sizeof(pmDesc)) {
|
|
if (pmDebugOptions.logmeta) {
|
|
fprintf(stderr, "__pmLogLoadMeta: pmDesc read -> %d: expected: %d\n",
|
|
n, (int)sizeof(pmDesc));
|
|
@@ -632,67 +712,25 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":2",
|
|
}
|
|
else
|
|
sts = PM_ERR_LOGREC;
|
|
- free(dp);
|
|
goto end;
|
|
}
|
|
- else {
|
|
- /* swab desc */
|
|
- dp->type = ntohl(dp->type);
|
|
- dp->sem = ntohl(dp->sem);
|
|
- dp->indom = __ntohpmInDom(dp->indom);
|
|
- dp->units = __ntohpmUnits(dp->units);
|
|
- dp->pmid = __ntohpmID(dp->pmid);
|
|
- }
|
|
|
|
- /* Add it to the hash pmid hash table. */
|
|
- if ((hp = __pmHashSearch((int)dp->pmid, &lcp->l_hashpmid)) != NULL) {
|
|
- /*
|
|
- * This pmid is already in the hash table. Check for conflicts.
|
|
- */
|
|
- olddp = (pmDesc *)hp->data;
|
|
- if (dp->type != olddp->type) {
|
|
- sts = PM_ERR_LOGCHANGETYPE;
|
|
- free(dp);
|
|
- goto end;
|
|
- }
|
|
- if (dp->sem != olddp->sem) {
|
|
- sts = PM_ERR_LOGCHANGESEM;
|
|
- free(dp);
|
|
- goto end;
|
|
- }
|
|
- if (dp->indom != olddp->indom) {
|
|
- sts = PM_ERR_LOGCHANGEINDOM;
|
|
- free(dp);
|
|
- goto end;
|
|
- }
|
|
- if (dp->units.dimSpace != olddp->units.dimSpace ||
|
|
- dp->units.dimTime != olddp->units.dimTime ||
|
|
- dp->units.dimCount != olddp->units.dimCount ||
|
|
- dp->units.scaleSpace != olddp->units.scaleSpace ||
|
|
- dp->units.scaleTime != olddp->units.scaleTime ||
|
|
- dp->units.scaleCount != olddp->units.scaleCount) {
|
|
- sts = PM_ERR_LOGCHANGEUNITS;
|
|
- free(dp);
|
|
- goto end;
|
|
- }
|
|
- /*
|
|
- * This pmid is already known, and matches. We can free the newly
|
|
- * read copy and use the one in the hash table.
|
|
- */
|
|
- free(dp);
|
|
- dp = olddp;
|
|
- }
|
|
- else if ((sts = __pmHashAdd((int)dp->pmid, (void *)dp, &lcp->l_hashpmid)) < 0) {
|
|
- free(dp);
|
|
+ /* swab desc */
|
|
+ desc.type = ntohl(desc.type);
|
|
+ desc.sem = ntohl(desc.sem);
|
|
+ desc.indom = __ntohpmInDom(desc.indom);
|
|
+ desc.units = __ntohpmUnits(desc.units);
|
|
+ desc.pmid = __ntohpmID(desc.pmid);
|
|
+
|
|
+ if ((sts = __pmLogAddDesc(acp, &desc)) < 0)
|
|
goto end;
|
|
- }
|
|
|
|
/* read in the names & store in PMNS tree ... */
|
|
if ((n = (int)__pmFread(&numnames, 1, sizeof(numnames), f)) !=
|
|
sizeof(numnames)) {
|
|
if (pmDebugOptions.logmeta) {
|
|
- fprintf(stderr, "__pmLogLoadMeta: numnames read -> %d: expected: %d\n",
|
|
- n, (int)sizeof(numnames));
|
|
+ fprintf(stderr, "%s: numnames read -> %d: expected: %d\n",
|
|
+ "__pmLogLoadMeta", n, (int)sizeof(numnames));
|
|
}
|
|
if (__pmFerror(f)) {
|
|
__pmClearerr(f);
|
|
@@ -711,8 +749,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":2",
|
|
if ((n = (int)__pmFread(&len, 1, sizeof(len), f)) !=
|
|
sizeof(len)) {
|
|
if (pmDebugOptions.logmeta) {
|
|
- fprintf(stderr, "__pmLogLoadMeta: len name[%d] read -> %d: expected: %d\n",
|
|
- i, n, (int)sizeof(len));
|
|
+ fprintf(stderr, "%s: len name[%d] read -> %d: expected: %d\n",
|
|
+ "__pmLogLoadMeta", i, n, (int)sizeof(len));
|
|
}
|
|
if (__pmFerror(f)) {
|
|
__pmClearerr(f);
|
|
@@ -729,8 +767,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":2",
|
|
|
|
if ((n = (int)__pmFread(name, 1, len, f)) != len) {
|
|
if (pmDebugOptions.logmeta) {
|
|
- fprintf(stderr, "__pmLogLoadMeta: name[%d] read -> %d: expected: %d\n",
|
|
- i, n, len);
|
|
+ fprintf(stderr, "%s: name[%d] read -> %d: expected: %d\n",
|
|
+ "__pmLogLoadMeta", i, n, len);
|
|
}
|
|
if (__pmFerror(f)) {
|
|
__pmClearerr(f);
|
|
@@ -743,36 +781,23 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":2",
|
|
name[len] = '\0';
|
|
if (pmDebugOptions.logmeta) {
|
|
char strbuf[20];
|
|
- fprintf(stderr, "__pmLogLoadMeta: PMID: %s name: %s\n",
|
|
- pmIDStr_r(dp->pmid, strbuf, sizeof(strbuf)), name);
|
|
+ fprintf(stderr, "%s: PMID: %s name: %s\n",
|
|
+ "__pmLogLoadMeta",
|
|
+ pmIDStr_r(desc.pmid, strbuf, sizeof(strbuf)), name);
|
|
}
|
|
- /* Add the new PMNS node */
|
|
- if ((sts = __pmAddPMNSNode(lcp->l_pmns, dp->pmid, name)) < 0) {
|
|
- /*
|
|
- * If we see a duplicate name with a different PMID, its a
|
|
- * recoverable error.
|
|
- * We wont be able to see all of the data in the log, but
|
|
- * its better to provide access to some rather than none,
|
|
- * esp. when only one or two metric IDs may be corrupted
|
|
- * in this way (which we may not be interested in anyway).
|
|
- */
|
|
- if (sts != PM_ERR_PMID)
|
|
- goto end;
|
|
- }
|
|
+
|
|
+ /* Add the new PMNS node into this context */
|
|
+ if ((sts = __pmLogAddPMNSNode(acp, desc.pmid, name)) < 0)
|
|
+ goto end;
|
|
}/*for*/
|
|
}
|
|
else if (h.type == TYPE_INDOM) {
|
|
- int *tbuf;
|
|
- pmInDom indom;
|
|
- pmTimeval *when;
|
|
- int numinst;
|
|
- int *instlist;
|
|
- char **namelist;
|
|
+ pmTimeval *tv;
|
|
+ pmTimespec when;
|
|
+ pmInResult in;
|
|
char *namebase;
|
|
- int *stridx;
|
|
- int i;
|
|
- int k;
|
|
- int allinbuf = 0;
|
|
+ int *tbuf, *stridx;
|
|
+ int i, k, allinbuf = 0;
|
|
|
|
PM_FAULT_POINT("libpcp/" __FILE__ ":3", PM_FAULT_ALLOC);
|
|
if ((tbuf = (int *)malloc(rlen)) == NULL) {
|
|
@@ -781,8 +806,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":3",
|
|
}
|
|
if ((n = (int)__pmFread(tbuf, 1, rlen, f)) != rlen) {
|
|
if (pmDebugOptions.logmeta) {
|
|
- fprintf(stderr, "__pmLogLoadMeta: indom read -> %d: expected: %d\n",
|
|
- n, rlen);
|
|
+ fprintf(stderr, "%s: indom read -> %d: expected: %d\n",
|
|
+ "__pmLogLoadMeta", n, rlen);
|
|
}
|
|
if (__pmFerror(f)) {
|
|
__pmClearerr(f);
|
|
@@ -795,44 +820,44 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":3",
|
|
}
|
|
|
|
k = 0;
|
|
- when = (pmTimeval *)&tbuf[k];
|
|
- when->tv_sec = ntohl(when->tv_sec);
|
|
- when->tv_usec = ntohl(when->tv_usec);
|
|
- k += sizeof(*when)/sizeof(int);
|
|
- indom = __ntohpmInDom((unsigned int)tbuf[k++]);
|
|
- numinst = ntohl(tbuf[k++]);
|
|
- if (numinst > 0) {
|
|
- instlist = &tbuf[k];
|
|
- k += numinst;
|
|
+ tv = (pmTimeval *)&tbuf[k];
|
|
+ when.tv_sec = ntohl(tv->tv_sec);
|
|
+ when.tv_nsec = ntohl(tv->tv_usec) * 1000;
|
|
+ k += sizeof(*tv)/sizeof(int);
|
|
+ in.indom = __ntohpmInDom((unsigned int)tbuf[k++]);
|
|
+ in.numinst = ntohl(tbuf[k++]);
|
|
+ if (in.numinst > 0) {
|
|
+ in.instlist = &tbuf[k];
|
|
+ k += in.numinst;
|
|
stridx = &tbuf[k];
|
|
#if defined(HAVE_32BIT_PTR)
|
|
- namelist = (char **)stridx;
|
|
+ in.namelist = (char **)stridx;
|
|
allinbuf = 1; /* allocation is all in tbuf */
|
|
#else
|
|
allinbuf = 0; /* allocation for namelist + tbuf */
|
|
/* need to allocate to hold the pointers */
|
|
PM_FAULT_POINT("libpcp/" __FILE__ ":4", PM_FAULT_ALLOC);
|
|
- namelist = (char **)malloc(numinst*sizeof(char*));
|
|
- if (namelist == NULL) {
|
|
+ in.namelist = (char **)malloc(in.numinst * sizeof(char*));
|
|
+ if (in.namelist == NULL) {
|
|
sts = -oserror();
|
|
free(tbuf);
|
|
goto end;
|
|
}
|
|
#endif
|
|
- k += numinst;
|
|
+ k += in.numinst;
|
|
namebase = (char *)&tbuf[k];
|
|
- for (i = 0; i < numinst; i++) {
|
|
- instlist[i] = ntohl(instlist[i]);
|
|
- namelist[i] = &namebase[ntohl(stridx[i])];
|
|
+ for (i = 0; i < in.numinst; i++) {
|
|
+ in.instlist[i] = ntohl(in.instlist[i]);
|
|
+ in.namelist[i] = &namebase[ntohl(stridx[i])];
|
|
}
|
|
- if ((sts = addindom(lcp, indom, when, numinst, instlist, namelist, tbuf, allinbuf)) < 0)
|
|
+ if ((sts = __pmLogAddInDom(acp, &when, &in, tbuf, allinbuf)) < 0)
|
|
goto end;
|
|
/* If this indom was a duplicate, then we need to free tbuf and
|
|
namelist, as appropriate. */
|
|
if (sts == PMLOGPUTINDOM_DUP) {
|
|
free(tbuf);
|
|
- if (namelist != NULL && !allinbuf)
|
|
- free(namelist);
|
|
+ if (in.namelist != NULL && !allinbuf)
|
|
+ free(in.namelist);
|
|
}
|
|
}
|
|
else {
|
|
@@ -860,8 +885,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":11",
|
|
}
|
|
if ((n = (int)__pmFread(tbuf, 1, rlen, f)) != rlen) {
|
|
if (pmDebugOptions.logmeta) {
|
|
- fprintf(stderr, "__pmLogLoadMeta: label read -> %d: expected: %d\n",
|
|
- n, rlen);
|
|
+ fprintf(stderr, "%s: label read -> %d: expected: %d\n",
|
|
+ "__pmLogLoadMeta", n, rlen);
|
|
}
|
|
if (__pmFerror(f)) {
|
|
__pmClearerr(f);
|
|
@@ -908,7 +933,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":11",
|
|
|
|
if (jsonlen < 0 || jsonlen > PM_MAXLABELJSONLEN) {
|
|
if (pmDebugOptions.logmeta)
|
|
- fprintf(stderr, "__pmLogLoadMeta: corrupted json in labelset. jsonlen=%d\n", jsonlen);
|
|
+ fprintf(stderr, "%s: corrupted json in labelset. jsonlen=%d\n",
|
|
+ "__pmLogLoadMeta", jsonlen);
|
|
sts = PM_ERR_LOGREC;
|
|
free(labelsets);
|
|
free(tbuf);
|
|
@@ -935,7 +961,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":11",
|
|
if (nlabels > PM_MAXLABELS || k + nlabels * sizeof(pmLabel) > rlen) {
|
|
/* corrupt archive metadata detected. GH #475 */
|
|
if (pmDebugOptions.logmeta)
|
|
- fprintf(stderr, "__pmLogLoadMeta: corrupted labelset. nlabels=%d\n", nlabels);
|
|
+ fprintf(stderr, "%s: corrupted labelset. nlabels=%d\n",
|
|
+ "__pmLogLoadMeta", nlabels);
|
|
sts = PM_ERR_LOGREC;
|
|
free(labelsets);
|
|
free(tbuf);
|
|
@@ -975,8 +1002,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":16",
|
|
}
|
|
if ((n = (int)__pmFread(tbuf, 1, rlen, f)) != rlen) {
|
|
if (pmDebugOptions.logmeta) {
|
|
- fprintf(stderr, "__pmLogLoadMeta: text read -> %d: expected: %d\n",
|
|
- n, rlen);
|
|
+ fprintf(stderr, "%s: text read -> %d: expected: %d\n",
|
|
+ "__pmLogLoadMeta", n, rlen);
|
|
}
|
|
if (__pmFerror(f)) {
|
|
__pmClearerr(f);
|
|
@@ -1005,8 +1032,8 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":16",
|
|
ident = __ntohpmID(*((unsigned int *)&tbuf[k]));
|
|
else {
|
|
if (pmDebugOptions.logmeta) {
|
|
- fprintf(stderr, "__pmLogLoadMeta: bad text ident -> %x\n",
|
|
- type);
|
|
+ fprintf(stderr, "%s: bad text ident -> %x\n",
|
|
+ "__pmLogLoadMeta", type);
|
|
}
|
|
free(tbuf);
|
|
continue;
|
|
@@ -1024,8 +1051,9 @@ PM_FAULT_POINT("libpcp/" __FILE__ ":16",
|
|
check = ntohl(check);
|
|
if (n != sizeof(check) || h.len != check) {
|
|
if (pmDebugOptions.logmeta) {
|
|
- fprintf(stderr, "__pmLogLoadMeta: trailer read -> %d or len=%d: expected %d @ offset=%d\n",
|
|
- n, check, h.len, (int)(__pmFtell(f) - sizeof(check)));
|
|
+ fprintf(stderr, "%s: trailer read -> %d or len=%d: "
|
|
+ "expected %d @ offset=%d\n", "__pmLogLoadMeta",
|
|
+ n, check, h.len, (int)(__pmFtell(f) - sizeof(check)));
|
|
}
|
|
if (__pmFerror(f)) {
|
|
__pmClearerr(f);
|
|
@@ -1046,7 +1074,7 @@ end:
|
|
if (sts == 0) {
|
|
if (numpmid == 0) {
|
|
if (pmDebugOptions.logmeta) {
|
|
- fprintf(stderr, "__pmLogLoadMeta: no metrics found?\n");
|
|
+ fprintf(stderr, "%s: no metrics found?\n", "__pmLogLoadMeta");
|
|
}
|
|
sts = PM_ERR_LOGREC;
|
|
}
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp/src/logutil.c pcp-5.0.2/src/libpcp/src/logutil.c
|
|
--- pcp-5.0.2.orig/src/libpcp/src/logutil.c 2018-07-08 10:58:08.000000000 +1000
|
|
+++ pcp-5.0.2/src/libpcp/src/logutil.c 2020-02-03 13:23:15.263762911 +1100
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2012-2017 Red Hat.
|
|
+ * Copyright (c) 2012-2017,2020 Red Hat.
|
|
* Copyright (c) 1995-2002,2004 Silicon Graphics, Inc. All Rights Reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it
|
|
@@ -764,6 +764,22 @@ __pmLogClose(__pmArchCtl *acp)
|
|
}
|
|
|
|
int
|
|
+__pmLogAddVolume(__pmArchCtl *acp, unsigned int vol)
|
|
+{
|
|
+ __pmLogCtl *lcp = acp->ac_log;
|
|
+
|
|
+ if (lcp->l_minvol == -1) {
|
|
+ lcp->l_minvol = vol;
|
|
+ lcp->l_maxvol = vol;
|
|
+ } else if (vol < lcp->l_minvol) {
|
|
+ lcp->l_minvol = vol;
|
|
+ } else if (vol > lcp->l_maxvol) {
|
|
+ lcp->l_maxvol = vol;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int
|
|
__pmLogLoadLabel(__pmArchCtl *acp, const char *name)
|
|
{
|
|
__pmLogCtl *lcp = acp->ac_log;
|
|
@@ -876,21 +892,14 @@ __pmLogLoadLabel(__pmArchCtl *acp, const
|
|
}
|
|
}
|
|
else {
|
|
- char *q;
|
|
- int vol;
|
|
- vol = (int)strtol(tp, &q, 10);
|
|
+ char *q;
|
|
+ unsigned int vol;
|
|
+
|
|
+ vol = (unsigned int)strtoul(tp, &q, 10);
|
|
if (*q == '\0') {
|
|
exists = 1;
|
|
- if (lcp->l_minvol == -1) {
|
|
- lcp->l_minvol = vol;
|
|
- lcp->l_maxvol = vol;
|
|
- }
|
|
- else {
|
|
- if (vol < lcp->l_minvol)
|
|
- lcp->l_minvol = vol;
|
|
- if (vol > lcp->l_maxvol)
|
|
- lcp->l_maxvol = vol;
|
|
- }
|
|
+ if ((sts = __pmLogAddVolume(acp, vol)) < 0)
|
|
+ goto cleanup;
|
|
}
|
|
}
|
|
}
|
|
@@ -2282,7 +2291,7 @@ __pmLogSetTime(__pmContext *ctxp)
|
|
int match = 0;
|
|
int vol;
|
|
int numti = lcp->l_numti;
|
|
- __pmFILE *f;
|
|
+ __pmFILE *f;
|
|
__pmLogTI *tip = lcp->l_ti;
|
|
double t_lo;
|
|
struct stat sbuf;
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/discover.c pcp-5.0.2/src/libpcp_web/src/discover.c
|
|
--- pcp-5.0.2.orig/src/libpcp_web/src/discover.c 2019-12-10 17:04:20.000000000 +1100
|
|
+++ pcp-5.0.2/src/libpcp_web/src/discover.c 2020-02-03 13:36:11.958637560 +1100
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2018-2019 Red Hat.
|
|
+ * Copyright (c) 2018-2020 Red Hat.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published
|
|
@@ -14,6 +14,8 @@
|
|
#include "discover.h"
|
|
#include "slots.h"
|
|
#include "util.h"
|
|
+#include <dirent.h>
|
|
+#include <sys/stat.h>
|
|
|
|
/* Decode various archive metafile records (desc, indom, labels, helptext) */
|
|
static int pmDiscoverDecodeMetaDesc(uint32_t *, int, pmDesc *, int *, char ***);
|
|
@@ -24,11 +26,15 @@ static int pmDiscoverDecodeMetaLabelSet(
|
|
/* array of registered callbacks, see pmDiscoverSetup() */
|
|
static int discoverCallBackTableSize;
|
|
static pmDiscoverCallBacks **discoverCallBackTable;
|
|
+static char *pmDiscoverFlagsStr(pmDiscover *);
|
|
|
|
/* internal hash table of discovered paths */
|
|
-#define PM_DISCOVER_HASHTAB_SIZE 64
|
|
+#define PM_DISCOVER_HASHTAB_SIZE 16
|
|
static pmDiscover *discover_hashtable[PM_DISCOVER_HASHTAB_SIZE];
|
|
|
|
+/* pmlogger_daily log-roll lock count */
|
|
+static int lockcnt = 0;
|
|
+
|
|
/* FNV string hash algorithm. Return unsigned in range 0 .. limit-1 */
|
|
static unsigned int
|
|
strhash(const char *s, unsigned int limit)
|
|
@@ -43,18 +49,38 @@ strhash(const char *s, unsigned int limi
|
|
return h % limit;
|
|
}
|
|
|
|
+/* ctime string - note static buf is returned */
|
|
+static char *
|
|
+stamp(void)
|
|
+{
|
|
+ time_t now = time(NULL);
|
|
+ char *p, *c = ctime(&now);
|
|
+
|
|
+ if ((p = strrchr(c, '\n')) != NULL)
|
|
+ *p = '\0';
|
|
+ return c;
|
|
+}
|
|
+
|
|
/*
|
|
- * Lookup or Add a discovered file path (directory or PCP archive file)
|
|
+ * Lookup or Add a discovered file path (directory or PCP archive file).
|
|
+ * Note: the fullpath suffix (.meta, .[0-9]+) should already be stripped.
|
|
* Return path table entry (new or existing).
|
|
*/
|
|
static pmDiscover *
|
|
-pmDiscoverLookupAdd(const char *path, pmDiscoverModule *module, void *arg)
|
|
+pmDiscoverLookupAdd(const char *fullpath, pmDiscoverModule *module, void *arg)
|
|
{
|
|
pmDiscover *p, *h;
|
|
- unsigned int k = strhash(path, PM_DISCOVER_HASHTAB_SIZE);
|
|
+ unsigned int k;
|
|
+ sds name;
|
|
+
|
|
+ name = sdsnew(fullpath);
|
|
+ k = strhash(name, PM_DISCOVER_HASHTAB_SIZE);
|
|
+
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "pmDiscoverLookupAdd: name=%s\n", name);
|
|
|
|
for (p = NULL, h = discover_hashtable[k]; h != NULL; p = h, h = h->next) {
|
|
- if (strcmp(h->context.name, path) == 0)
|
|
+ if (sdscmp(h->context.name, name) == 0)
|
|
break;
|
|
}
|
|
|
|
@@ -65,14 +91,24 @@ pmDiscoverLookupAdd(const char *path, pm
|
|
h->ctx = -1; /* no PMAPI context initially */
|
|
h->flags = PM_DISCOVER_FLAGS_NEW;
|
|
h->context.type = PM_CONTEXT_ARCHIVE;
|
|
- h->context.name = sdsnew(path);
|
|
+ h->context.name = name;
|
|
h->module = module;
|
|
h->data = arg;
|
|
if (p == NULL)
|
|
discover_hashtable[k] = h;
|
|
else
|
|
p->next = h;
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "pmDiscoverLookupAdd: --> new entry %s\n", name);
|
|
+
|
|
+ }
|
|
+ else {
|
|
+ /* already in hash table, so free the buffer */
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "pmDiscoverLookupAdd: --> existing entry %s\n", name);
|
|
+ sdsfree(name);
|
|
}
|
|
+
|
|
return h;
|
|
}
|
|
|
|
@@ -82,12 +118,6 @@ pmDiscoverLookup(const char *path)
|
|
return pmDiscoverLookupAdd(path, NULL, NULL);
|
|
}
|
|
|
|
-static pmDiscover *
|
|
-pmDiscoverAdd(const char *path, pmDiscoverModule *module, void *arg)
|
|
-{
|
|
- return pmDiscoverLookupAdd(path, module, arg);
|
|
-}
|
|
-
|
|
static void
|
|
pmDiscoverFree(pmDiscover *p)
|
|
{
|
|
@@ -101,39 +131,42 @@ pmDiscoverFree(pmDiscover *p)
|
|
sdsfree(p->context.source);
|
|
if (p->context.labelset)
|
|
pmFreeLabelSets(p->context.labelset, 1);
|
|
+ if (p->event_handle) {
|
|
+ uv_fs_event_stop(p->event_handle);
|
|
+ free(p->event_handle);
|
|
+ p->event_handle = NULL;
|
|
+ }
|
|
+
|
|
memset(p, 0, sizeof(*p));
|
|
free(p);
|
|
}
|
|
|
|
/*
|
|
- * Delete tracking of a previously discovered path. Frees resources and
|
|
- * destroy PCP context (if any).
|
|
+ * Traverse and invoke callback for all paths matching any bit
|
|
+ * in the flags bitmap. Callback can be NULL to just get a count.
|
|
+ * Return count of matching paths, may be 0.
|
|
*/
|
|
-static void
|
|
-pmDiscoverDelete(sds path)
|
|
+static int
|
|
+pmDiscoverTraverse(unsigned int flags, void (*callback)(pmDiscover *))
|
|
{
|
|
- pmDiscover *p, *h;
|
|
- unsigned int k = strhash(path, PM_DISCOVER_HASHTAB_SIZE);
|
|
+ int count = 0, i;
|
|
+ pmDiscover *p;
|
|
|
|
- for (p = NULL, h = discover_hashtable[k]; h != NULL; p = h, h = h->next) {
|
|
- if (sdscmp(h->context.name, path) == 0) {
|
|
- if (p == NULL)
|
|
- discover_hashtable[k] = NULL;
|
|
- else
|
|
- p->next = h->next;
|
|
- pmDiscoverFree(h);
|
|
- break;
|
|
+ for (i = 0; i < PM_DISCOVER_HASHTAB_SIZE; i++) {
|
|
+ for (p = discover_hashtable[i]; p; p = p->next) {
|
|
+ if (p->flags & flags) {
|
|
+ if (callback)
|
|
+ callback(p);
|
|
+ count++;
|
|
+ }
|
|
}
|
|
}
|
|
+ return count;
|
|
}
|
|
|
|
-/*
|
|
- * Traverse and invoke callback for all paths matching any bit
|
|
- * in the flags bitmap. Callback can be NULL to just get a count.
|
|
- * Return count of matching paths, may be 0.
|
|
- */
|
|
+/* as above, but with an extra (void *)arg passed to the cb */
|
|
static int
|
|
-pmDiscoverTraverse(unsigned int flags, void (*callback)(pmDiscover *))
|
|
+pmDiscoverTraverseArg(unsigned int flags, void (*callback)(pmDiscover *, void *), void *arg)
|
|
{
|
|
int count = 0, i;
|
|
pmDiscover *p;
|
|
@@ -142,7 +175,7 @@ pmDiscoverTraverse(unsigned int flags, v
|
|
for (p = discover_hashtable[i]; p; p = p->next) {
|
|
if (p->flags & flags) {
|
|
if (callback)
|
|
- callback(p);
|
|
+ callback(p, arg);
|
|
count++;
|
|
}
|
|
}
|
|
@@ -150,6 +183,7 @@ pmDiscoverTraverse(unsigned int flags, v
|
|
return count;
|
|
}
|
|
|
|
+
|
|
/*
|
|
* Traverse and purge deleted entries
|
|
* Return count of purged entries.
|
|
@@ -173,6 +207,9 @@ pmDiscoverPurgeDeleted(void)
|
|
prev->next = next;
|
|
else
|
|
discover_hashtable[i] = next;
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "pmDiscoverPurgeDeleted: deleted %s %s\n",
|
|
+ p->context.name, pmDiscoverFlagsStr(p));
|
|
pmDiscoverFree(p);
|
|
count++;
|
|
}
|
|
@@ -180,14 +217,32 @@ pmDiscoverPurgeDeleted(void)
|
|
}
|
|
}
|
|
|
|
- if (pmDebugOptions.discovery)
|
|
- fprintf(stderr, "%s: purged %d entries\n",
|
|
- "pmDiscoverPurgeDeleted", count);
|
|
-
|
|
return count;
|
|
}
|
|
|
|
/*
|
|
+ * if string ends with given suffix then return pointer
|
|
+ * to start of suffix in string, else NULL
|
|
+ */
|
|
+static char *
|
|
+strsuffix(char *s, const char *suffix)
|
|
+{
|
|
+ int slen, suflen;
|
|
+ char *ret = NULL;
|
|
+
|
|
+ if (s && suffix) {
|
|
+ slen = strlen(s);
|
|
+ suflen = strlen(suffix);
|
|
+ if (slen >= suflen) {
|
|
+ ret = s + (slen - suflen);
|
|
+ if (strncmp(ret, suffix, suflen) != 0)
|
|
+ ret = NULL;
|
|
+ }
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/*
|
|
* Discover dirs and archives - add new entries or refresh existing.
|
|
* Call this for each top-level directory. Discovered paths are not
|
|
* automatically monitored. After discovery, need to traverse and
|
|
@@ -196,44 +251,88 @@ pmDiscoverPurgeDeleted(void)
|
|
static int
|
|
pmDiscoverArchives(const char *dir, pmDiscoverModule *module, void *arg)
|
|
{
|
|
- uv_fs_t sreq, req;
|
|
- uv_dirent_t dent;
|
|
- uv_stat_t *s;
|
|
+ DIR *dirp;
|
|
+ struct dirent *dent;
|
|
+ struct stat *s;
|
|
+ struct stat statbuf;
|
|
pmDiscover *a;
|
|
+ char *suffix;
|
|
char path[MAXNAMELEN];
|
|
- char basepath[MAXNAMELEN];
|
|
int sep = pmPathSeparator();
|
|
+ int vol;
|
|
+
|
|
+ /*
|
|
+ * note: pmDiscoverLookupAdd sets PM_DISCOVER_FLAGS_NEW
|
|
+ * if this is a newly discovered archive or directory
|
|
+ */
|
|
+ a = pmDiscoverLookupAdd(dir, module, arg);
|
|
+ a->flags |= PM_DISCOVER_FLAGS_DIRECTORY;
|
|
|
|
- if (uv_fs_scandir(NULL, &req, dir, 0, NULL) < 0)
|
|
+ if ((dirp = opendir(dir)) == NULL) {
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "pmDiscoverArchives: opendir %s failed %s: err %d\n", dir, path, errno);
|
|
return -ESRCH;
|
|
+ }
|
|
|
|
- a = pmDiscoverAdd(dir, module, arg);
|
|
- a->flags |= PM_DISCOVER_FLAGS_DIRECTORY;
|
|
+ while ((dent = readdir(dirp)) != NULL) {
|
|
+ if (dent->d_name[0] == '.')
|
|
+ continue;
|
|
+ pmsprintf(path, sizeof(path), "%s%c%s", dir, sep, dent->d_name);
|
|
+
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "pmDiscoverArchives: readdir found %s\n", path);
|
|
|
|
- while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
|
|
- pmsprintf(path, sizeof(path), "%s%c%s", dir, sep, dent.name);
|
|
- if (uv_fs_stat(NULL, &sreq, path, NULL) < 0)
|
|
+ if (stat(path, &statbuf) < 0) {
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "pmDiscoverArchives: stat failed %s, err %d\n", path, errno);
|
|
continue;
|
|
- s = &sreq.statbuf;
|
|
- strncpy(basepath, path, sizeof(basepath)); /* __pmLogBaseName modifies it's argument */
|
|
- if (S_ISREG(s->st_mode) && __pmLogBaseName(basepath) != NULL) {
|
|
- /*
|
|
- * An archive file (index, meta or data vol). If compressed, then
|
|
- * it is read-only and we don't have to monitor it for growth.
|
|
- */
|
|
- a = pmDiscoverAdd(path, module, arg);
|
|
- a->flags &= ~PM_DISCOVER_FLAGS_DELETED;
|
|
+ }
|
|
|
|
- if (strstr(path, ".meta"))
|
|
- a->flags |= PM_DISCOVER_FLAGS_META;
|
|
- else if (strstr(path, ".index"))
|
|
- a->flags |= PM_DISCOVER_FLAGS_INDEX;
|
|
- else
|
|
- a->flags |= PM_DISCOVER_FLAGS_DATAVOL;
|
|
-
|
|
- /* compare to libpcp io.c for suffix list */
|
|
- if (strstr(path, ".xz") || strstr(path, ".gz"))
|
|
- a->flags |= PM_DISCOVER_FLAGS_COMPRESSED;
|
|
+ s = &statbuf;
|
|
+ if (S_ISREG(s->st_mode)) {
|
|
+ if ((suffix = strsuffix(path, ".meta")) != NULL) {
|
|
+ /*
|
|
+ * An uncompressed PCP archive meta file. Track the meta
|
|
+ * file - the matching logvol filename varies because logvols
|
|
+ * are periodically rolled by pmlogger. Importantly, process all
|
|
+ * available metadata to EOF before processing any logvol data.
|
|
+ */
|
|
+ *suffix = '\0'; /* strip suffix from path giving archive name */
|
|
+ a = pmDiscoverLookupAdd(path, module, arg);
|
|
+
|
|
+ /*
|
|
+ * note: pmDiscoverLookupAdd sets PM_DISCOVER_FLAGS_NEW
|
|
+ * if this is a newly discovered archive, otherwise we're
|
|
+ * already tracking this archive.
|
|
+ */
|
|
+ a->flags |= PM_DISCOVER_FLAGS_META;
|
|
+ }
|
|
+ else if ((suffix = __pmLogBaseNameVol(path, &vol)) != NULL && vol >= 0) {
|
|
+ /*
|
|
+ * An archive logvol. This logvol may have been created since
|
|
+ * the context was first opened. Update the context maxvol
|
|
+ * to be sure pmFetchArchive can switch to it in due course.
|
|
+ */
|
|
+ if ((a = pmDiscoverLookup(path)) != NULL) {
|
|
+ a->flags |= PM_DISCOVER_FLAGS_DATAVOL;
|
|
+ /* ensure archive context knows about this volume */
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "pmDiscoverArchives: found logvol %s %s vol=%d\n",
|
|
+ a->context.name, pmDiscoverFlagsStr(a), vol);
|
|
+ if (a->ctx >= 0 && vol >= 0) {
|
|
+ __pmContext *ctxp = __pmHandleToPtr(a->ctx);
|
|
+ __pmArchCtl *acp = ctxp->c_archctl;
|
|
+
|
|
+ __pmLogAddVolume(acp, vol);
|
|
+ PM_UNLOCK(ctxp->c_lock);
|
|
+ }
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "pmDiscoverArchives: added logvol %s %s vol=%d\n",
|
|
+ a->context.name, pmDiscoverFlagsStr(a), vol);
|
|
+ }
|
|
+ } else if (pmDebugOptions.discovery) {
|
|
+ fprintf(stderr, "pmDiscoverArchives: ignored regular file %s\n", path);
|
|
+ }
|
|
}
|
|
else if (S_ISDIR(s->st_mode)) {
|
|
/*
|
|
@@ -241,29 +340,117 @@ pmDiscoverArchives(const char *dir, pmDi
|
|
*/
|
|
pmDiscoverArchives(path, module, arg);
|
|
}
|
|
- uv_fs_req_cleanup(&sreq);
|
|
}
|
|
- uv_fs_req_cleanup(&req);
|
|
+ if (dirp)
|
|
+ closedir(dirp);
|
|
|
|
/* success */
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+ * Return 1 if monitored path has been deleted.
|
|
+ * For archives, we only check the meta file because
|
|
+ * a logvol can be deleted (e.g. via compression when
|
|
+ * the logvol is rolled to a new volume) without
|
|
+ * actually deleting the archive.
|
|
+ */
|
|
+static int
|
|
+is_deleted(pmDiscover *p, struct stat *sbuf)
|
|
+{
|
|
+ int ret = 0;
|
|
+
|
|
+ if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
|
|
+ if (stat(p->context.name, sbuf) < 0)
|
|
+ ret = 1; /* directory has been deleted */
|
|
+ }
|
|
+
|
|
+ if (p->flags & (PM_DISCOVER_FLAGS_META|PM_DISCOVER_FLAGS_DATAVOL)) {
|
|
+ sds meta = sdsnew(p->context.name);
|
|
+ meta = sdscat(meta, ".meta");
|
|
+ if (stat(meta, sbuf) < 0) {
|
|
+ /*
|
|
+ * Archive metadata file has been deleted (or compressed)
|
|
+ * hence consider the archive to be deleted because there
|
|
+ * is no more data to logtail.
|
|
+ */
|
|
+ ret = 1;
|
|
+ }
|
|
+ sdsfree(meta);
|
|
+ }
|
|
+
|
|
+ if (pmDebugOptions.discovery) {
|
|
+ fprintf(stderr, "is_deleted: checking %s (%s) -> %s\n",
|
|
+ p->context.name, pmDiscoverFlagsStr(p), ret ? "DELETED" : "no");
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void
|
|
+logdir_is_locked_callBack(pmDiscover *p, void *arg)
|
|
+{
|
|
+ int *cntp = (int *)arg;
|
|
+ char sep = pmPathSeparator();
|
|
+ char path[MAXNAMELEN];
|
|
+
|
|
+ pmsprintf(path, sizeof(path), "%s%c%s", p->context.name, sep, "lock");
|
|
+ if (access(path, F_OK) == 0)
|
|
+ (*cntp)++;
|
|
+}
|
|
+
|
|
+static void
|
|
+check_deleted(pmDiscover *p)
|
|
+{
|
|
+ struct stat sbuf;
|
|
+ if (!(p->flags & PM_DISCOVER_FLAGS_DELETED) && is_deleted(p, &sbuf))
|
|
+ p->flags |= PM_DISCOVER_FLAGS_DELETED;
|
|
+}
|
|
+
|
|
static void
|
|
fs_change_callBack(uv_fs_event_t *handle, const char *filename, int events, int status)
|
|
{
|
|
char buffer[MAXNAMELEN];
|
|
size_t bytes = sizeof(buffer) - 1;
|
|
pmDiscover *p;
|
|
- uv_fs_t sreq;
|
|
+ char *s;
|
|
sds path;
|
|
- int path_changed = 0;
|
|
+ int count = 0;
|
|
+ struct stat statbuf;
|
|
+
|
|
+ /*
|
|
+ * check if logs are currently being rolled by pmlogger_daily et al
|
|
+ * in any of the directories we are tracking. For mutex, the log control
|
|
+ * scripts use a 'lock' file in each directory as it is processed.
|
|
+ */
|
|
+ pmDiscoverTraverseArg(PM_DISCOVER_FLAGS_DIRECTORY,
|
|
+ logdir_is_locked_callBack, (void *)&count);
|
|
+
|
|
+ if (lockcnt == 0 && count > 0) {
|
|
+ /* log-rolling has started */
|
|
+ fprintf(stderr, "%s discovery callback ignored: log-rolling is now in progress\n", stamp());
|
|
+ lockcnt = count;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (lockcnt > 0 && count > 0) {
|
|
+ /* log-rolling is still in progress */
|
|
+ lockcnt = count;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (lockcnt > 0 && count == 0) {
|
|
+ /* log-rolling is finished: check what got deleted, and then purge */
|
|
+ fprintf(stderr, "%s discovery callback: finished log-rolling\n", stamp());
|
|
+ pmDiscoverTraverse(PM_DISCOVER_FLAGS_META|PM_DISCOVER_FLAGS_DATAVOL, check_deleted);
|
|
+ }
|
|
+ lockcnt = count;
|
|
|
|
uv_fs_event_getpath(handle, buffer, &bytes);
|
|
path = sdsnewlen(buffer, bytes);
|
|
|
|
if (pmDebugOptions.discovery) {
|
|
- fprintf(stderr, "%s: event on %s -", "fs_change_callBack", path);
|
|
+ fprintf(stderr, "fs_change_callBack: event on %s -", path);
|
|
if (events & UV_RENAME)
|
|
fprintf(stderr, " renamed");
|
|
if (events & UV_CHANGE)
|
|
@@ -271,38 +458,40 @@ fs_change_callBack(uv_fs_event_t *handle
|
|
fputc('\n', stderr);
|
|
}
|
|
|
|
+
|
|
/*
|
|
- * Lookup the path, stat and update it's flags accordingly. If the
|
|
- * path has been deleted, stop it's event monitor and free the req buffer.
|
|
- * Then call the pmDiscovery callback.
|
|
+ * Strip ".meta" suffix (if any) and lookup the path. stat and update it's
|
|
+ * flags accordingly. If the path has been deleted, stop it's event monitor
|
|
+ * and free the req buffer, else call the pmDiscovery callback.
|
|
*/
|
|
- if ((p = pmDiscoverLookup(path)) == NULL) {
|
|
+ if ((s = strsuffix(path, ".meta")) != NULL)
|
|
+ *s = '\0';
|
|
+
|
|
+ p = pmDiscoverLookup(path);
|
|
+ if (p && pmDebugOptions.discovery) {
|
|
+ fprintf(stderr, "fs_change_callBack: ---> found entry %s (%s)\n",
|
|
+ p->context.name, pmDiscoverFlagsStr(p));
|
|
+ }
|
|
+
|
|
+ if (p == NULL) {
|
|
if (pmDebugOptions.discovery)
|
|
- fprintf(stderr, "%s: filename %s lookup failed\n",
|
|
- "fs_change_callBack", filename);
|
|
+ fprintf(stderr, "fs_change_callBack: %s lookup failed\n", filename);
|
|
}
|
|
- else if (uv_fs_stat(NULL, &sreq, p->context.name, NULL) < 0) {
|
|
- p->flags |= PM_DISCOVER_FLAGS_DELETED;
|
|
- if (p->event_handle) {
|
|
- uv_fs_event_stop(p->event_handle);
|
|
- free(p->event_handle);
|
|
- p->event_handle = NULL;
|
|
- }
|
|
+ else if (is_deleted(p, &statbuf)) {
|
|
/* path has been deleted. statbuf is invalid */
|
|
+ p->flags |= PM_DISCOVER_FLAGS_DELETED;
|
|
memset(&p->statbuf, 0, sizeof(p->statbuf));
|
|
- path_changed = 1;
|
|
- }
|
|
- else {
|
|
- /* avoid spurious events. only call the callBack if it really changed */
|
|
- if (p->statbuf.st_mtim.tv_sec != sreq.statbuf.st_mtim.tv_sec ||
|
|
- p->statbuf.st_mtim.tv_nsec != sreq.statbuf.st_mtim.tv_nsec)
|
|
- path_changed = 1;
|
|
- p->statbuf = sreq.statbuf; /* struct copy */
|
|
- uv_fs_req_cleanup(&sreq);
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "fs_change_callBack: %s (%s) has been deleted",
|
|
+ p->context.name, pmDiscoverFlagsStr(p));
|
|
}
|
|
|
|
- if (p && p->changed && path_changed && !(p->flags & PM_DISCOVER_FLAGS_DELETED))
|
|
- p->changed(p);
|
|
+ /*
|
|
+ * Something in the directory changed - new or deleted archive, or
|
|
+ * a tracked archive meta data file or logvolume grew
|
|
+ */
|
|
+ if (p)
|
|
+ p->changed(p); /* returns immediately if PM_DISCOVER_FLAGS_DELETED */
|
|
|
|
sdsfree(path);
|
|
}
|
|
@@ -316,9 +505,14 @@ pmDiscoverMonitor(sds path, void (*callb
|
|
{
|
|
discoverModuleData *data;
|
|
pmDiscover *p;
|
|
+ sds eventfilename;
|
|
|
|
- if ((p = pmDiscoverLookup(path)) == NULL)
|
|
+ if ((p = pmDiscoverLookup(path)) == NULL) {
|
|
+ if (pmDebugOptions.discovery) {
|
|
+ fprintf(stderr, "pmDiscoverMonitor: lookup failed for %s\n", path);
|
|
+ }
|
|
return -ESRCH;
|
|
+ }
|
|
data = getDiscoverModuleData(p->module);
|
|
|
|
/* save the discovery callback to be invoked */
|
|
@@ -330,9 +524,29 @@ pmDiscoverMonitor(sds path, void (*callb
|
|
* Start monitoring, using given uv loop. Up to the caller to create
|
|
* a PCP PMAPI context and to fetch/logtail in the changed callback.
|
|
*/
|
|
+ eventfilename = sdsnew(p->context.name);
|
|
uv_fs_event_init(data->events, p->event_handle);
|
|
- uv_fs_event_start(p->event_handle, fs_change_callBack, p->context.name,
|
|
+
|
|
+ if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
|
|
+ uv_fs_event_start(p->event_handle, fs_change_callBack, eventfilename,
|
|
+ UV_FS_EVENT_WATCH_ENTRY);
|
|
+ }
|
|
+ else {
|
|
+ /*
|
|
+ * Monitor an archive file. This tracks the archive meta file
|
|
+ * but the change callback processes both meta and logvol on
|
|
+ * every callback (meta before logvol).
|
|
+ */
|
|
+ eventfilename = sdscat(eventfilename, ".meta");
|
|
+ uv_fs_event_start(p->event_handle, fs_change_callBack, eventfilename,
|
|
UV_FS_EVENT_WATCH_ENTRY);
|
|
+ }
|
|
+
|
|
+ if (pmDebugOptions.discovery) {
|
|
+ fprintf(stderr, "pmDiscoverMonitor: added event for %s (%s)\n",
|
|
+ eventfilename, pmDiscoverFlagsStr(p));
|
|
+ }
|
|
+ sdsfree(eventfilename);
|
|
}
|
|
|
|
return 0;
|
|
@@ -411,41 +625,23 @@ static void changed_callback(pmDiscover
|
|
static void
|
|
created_callback(pmDiscover *p)
|
|
{
|
|
+ if (p->flags & (PM_DISCOVER_FLAGS_COMPRESSED|PM_DISCOVER_FLAGS_INDEX))
|
|
+ return; /* compressed archives don't grow and we ignore archive index files */
|
|
+
|
|
if (pmDebugOptions.discovery)
|
|
fprintf(stderr, "CREATED %s, %s\n", p->context.name, pmDiscoverFlagsStr(p));
|
|
|
|
- p->flags &= ~PM_DISCOVER_FLAGS_NEW;
|
|
-
|
|
- if (p->flags & PM_DISCOVER_FLAGS_COMPRESSED)
|
|
- return; /* compressed archives don't grow */
|
|
-
|
|
if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
|
|
if (pmDebugOptions.discovery)
|
|
fprintf(stderr, "MONITOR directory %s\n", p->context.name);
|
|
pmDiscoverMonitor(p->context.name, changed_callback);
|
|
}
|
|
-
|
|
- if (p->flags & PM_DISCOVER_FLAGS_DATAVOL) {
|
|
+ else if (p->flags & (PM_DISCOVER_FLAGS_META|PM_DISCOVER_FLAGS_DATAVOL)) {
|
|
if (pmDebugOptions.discovery)
|
|
- fprintf(stderr, "MONITOR logvol %s\n", p->context.name);
|
|
+ fprintf(stderr, "MONITOR archive %s\n", p->context.name);
|
|
pmDiscoverMonitor(p->context.name, changed_callback);
|
|
}
|
|
-
|
|
- if (p->flags & PM_DISCOVER_FLAGS_META) {
|
|
- if (pmDebugOptions.discovery)
|
|
- fprintf(stderr, "MONITOR metadata %s\n", p->context.name);
|
|
- pmDiscoverMonitor(p->context.name, changed_callback);
|
|
- }
|
|
-}
|
|
-
|
|
-static void
|
|
-deleted_callback(pmDiscover *p)
|
|
-{
|
|
- if (pmDebugOptions.discovery)
|
|
- fprintf(stderr, "DELETED %s (%s)\n", p->context.name,
|
|
- pmDiscoverFlagsStr(p));
|
|
- pmDiscoverDelete(p->context.name);
|
|
- /* p is now no longer valid */
|
|
+ p->flags &= ~PM_DISCOVER_FLAGS_NEW;
|
|
}
|
|
|
|
static void
|
|
@@ -509,37 +705,84 @@ static void
|
|
pmDiscoverInvokeMetricCallBacks(pmDiscover *p, pmTimespec *ts, pmDesc *desc,
|
|
int numnames, char **names)
|
|
{
|
|
+ discoverModuleData *data = getDiscoverModuleData(p->module);
|
|
pmDiscoverCallBacks *callbacks;
|
|
pmDiscoverEvent event;
|
|
char buf[32];
|
|
- int i;
|
|
+ int i, sts;
|
|
|
|
if (pmDebugOptions.discovery) {
|
|
fprintf(stderr, "%s[%s]: %s name%s", "pmDiscoverInvokeMetricCallBacks",
|
|
timespec_str(ts, buf, sizeof(buf)),
|
|
p->context.source, numnames > 0 ? " " : "(none)\n");
|
|
for (i = 0; i < numnames; i++)
|
|
- printf("\"%s\"%s", names[i], i < numnames - 1 ? ", " : "\n");
|
|
+ fprintf(stderr, "[%u/%u] \"%s\"%s", i+1, numnames, names[i],
|
|
+ i < numnames - 1 ? ", " : "\n");
|
|
pmPrintDesc(stderr, desc);
|
|
if (pmDebugOptions.labels)
|
|
fprintf(stderr, "context labels %s\n", p->context.labelset->json);
|
|
}
|
|
|
|
+ if (data->pmids) {
|
|
+ if (dictFind(data->pmids, &desc->pmid) != NULL)
|
|
+ goto out; /* metric contains an already excluded PMID */
|
|
+ for (i = 0; i < numnames; i++) {
|
|
+ if (regexec(&data->exclude_names, names[i], 0, NULL, 0) == 0)
|
|
+ break;
|
|
+ }
|
|
+ if (i != numnames) {
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "%s: excluding metric %s\n",
|
|
+ "pmDiscoverInvokeMetricCallBacks", names[i]);
|
|
+ /* add this pmid to the exclusion list and return early */
|
|
+ dictAdd(data->pmids, &desc->pmid, NULL);
|
|
+ goto out;
|
|
+ }
|
|
+ }
|
|
+ if (data->indoms) {
|
|
+ if (dictFind(data->indoms, &desc->indom) != NULL)
|
|
+ goto out; /* metric contains an already excluded InDom */
|
|
+ }
|
|
+
|
|
+ if (p->ctx >= 0 && p->context.type == PM_CONTEXT_ARCHIVE) {
|
|
+ __pmContext *ctxp = __pmHandleToPtr(p->ctx);
|
|
+ __pmArchCtl *acp = ctxp->c_archctl;
|
|
+ char idstr[32];
|
|
+
|
|
+ if ((sts = __pmLogAddDesc(acp, desc)) < 0)
|
|
+ fprintf(stderr, "%s: failed to add metric descriptor for %s\n",
|
|
+ "pmDiscoverInvokeMetricCallBacks",
|
|
+ pmIDStr_r(desc->pmid, idstr, sizeof(idstr)));
|
|
+ for (i = 0; i < numnames; i++) {
|
|
+ if ((sts = __pmLogAddPMNSNode(acp, desc->pmid, names[i])) < 0)
|
|
+ fprintf(stderr, "%s: failed to add metric name %s for %s\n",
|
|
+ "pmDiscoverInvokeMetricCallBacks", names[i],
|
|
+ pmIDStr_r(desc->pmid, idstr, sizeof(idstr)));
|
|
+ }
|
|
+ PM_UNLOCK(ctxp->c_lock);
|
|
+ }
|
|
+
|
|
discover_event_init(p, ts, &event);
|
|
for (i = 0; i < discoverCallBackTableSize; i++) {
|
|
if ((callbacks = discoverCallBackTable[i]) &&
|
|
callbacks->on_metric != NULL)
|
|
callbacks->on_metric(&event, desc, numnames, names, p->data);
|
|
}
|
|
+
|
|
+out:
|
|
+ for (i = 0; i < numnames; i++)
|
|
+ free(names[i]);
|
|
+ free(names);
|
|
}
|
|
|
|
static void
|
|
pmDiscoverInvokeInDomCallBacks(pmDiscover *p, pmTimespec *ts, pmInResult *in)
|
|
{
|
|
+ discoverModuleData *data = getDiscoverModuleData(p->module);
|
|
pmDiscoverCallBacks *callbacks;
|
|
pmDiscoverEvent event;
|
|
char buf[32], inbuf[32];
|
|
- int i;
|
|
+ int i, sts = PMLOGPUTINDOM_DUP; /* free after callbacks */
|
|
|
|
if (pmDebugOptions.discovery) {
|
|
fprintf(stderr, "%s[%s]: %s numinst %d indom %s\n",
|
|
@@ -551,22 +794,48 @@ pmDiscoverInvokeInDomCallBacks(pmDiscove
|
|
fprintf(stderr, "context labels %s\n", p->context.labelset->json);
|
|
}
|
|
|
|
+ if (data->indoms) {
|
|
+ if (dictFind(data->indoms, &in->indom) != NULL)
|
|
+ goto out; /* excluded InDom */
|
|
+ }
|
|
+
|
|
+ if (p->ctx >= 0 && p->context.type == PM_CONTEXT_ARCHIVE) {
|
|
+ __pmContext *ctxp = __pmHandleToPtr(p->ctx);
|
|
+ __pmArchCtl *acp = ctxp->c_archctl;
|
|
+ char errmsg[PM_MAXERRMSGLEN];
|
|
+
|
|
+ if ((sts = __pmLogAddInDom(acp, ts, in, NULL, 0)) < 0)
|
|
+ fprintf(stderr, "%s: failed to add indom for %s: %s\n",
|
|
+ "pmDiscoverInvokeInDomCallBacks", pmIDStr(in->indom),
|
|
+ pmErrStr_r(sts, errmsg, sizeof(errmsg)));
|
|
+ PM_UNLOCK(ctxp->c_lock);
|
|
+ }
|
|
+
|
|
discover_event_init(p, ts, &event);
|
|
for (i = 0; i < discoverCallBackTableSize; i++) {
|
|
if ((callbacks = discoverCallBackTable[i]) &&
|
|
callbacks->on_indom != NULL)
|
|
callbacks->on_indom(&event, in, p->data);
|
|
}
|
|
+
|
|
+out:
|
|
+ if (sts == PMLOGPUTINDOM_DUP) {
|
|
+ for (i = 0; i < in->numinst; i++)
|
|
+ free(in->namelist[i]);
|
|
+ free(in->namelist);
|
|
+ free(in->instlist);
|
|
+ }
|
|
}
|
|
|
|
static void
|
|
pmDiscoverInvokeLabelsCallBacks(pmDiscover *p, pmTimespec *ts,
|
|
int ident, int type, pmLabelSet *sets, int nsets)
|
|
{
|
|
+ discoverModuleData *data = getDiscoverModuleData(p->module);
|
|
pmDiscoverCallBacks *callbacks;
|
|
pmDiscoverEvent event;
|
|
char buf[32], idbuf[64];
|
|
- int i;
|
|
+ int i, sts = -EAGAIN; /* free labelsets after callbacks */
|
|
|
|
if (pmDebugOptions.discovery) {
|
|
__pmLabelIdentString(ident, type, idbuf, sizeof(idbuf));
|
|
@@ -579,22 +848,48 @@ pmDiscoverInvokeLabelsCallBacks(pmDiscov
|
|
fprintf(stderr, "context labels %s\n", p->context.labelset->json);
|
|
}
|
|
|
|
+ if ((type & PM_LABEL_ITEM) && data->pmids) {
|
|
+ if (dictFind(data->pmids, &ident) != NULL)
|
|
+ goto out; /* text from an already excluded InDom */
|
|
+ }
|
|
+ if ((type & (PM_LABEL_INDOM|PM_LABEL_INSTANCES)) && data->indoms) {
|
|
+ if (dictFind(data->indoms, &ident) != NULL)
|
|
+ goto out; /* text from an already excluded InDom */
|
|
+ }
|
|
+
|
|
+ if (p->ctx >= 0 && p->context.type == PM_CONTEXT_ARCHIVE) {
|
|
+ __pmContext *ctxp = __pmHandleToPtr(p->ctx);
|
|
+ __pmArchCtl *acp = ctxp->c_archctl;
|
|
+ char errmsg[PM_MAXERRMSGLEN];
|
|
+
|
|
+ if ((sts = __pmLogAddLabelSets(acp, ts, type, ident, nsets, sets)) < 0)
|
|
+ fprintf(stderr, "%s: failed to add log labelset: %s\n",
|
|
+ "pmDiscoverInvokeLabelsCallBacks",
|
|
+ pmErrStr_r(sts, errmsg, sizeof(errmsg)));
|
|
+ PM_UNLOCK(ctxp->c_lock);
|
|
+ }
|
|
+
|
|
discover_event_init(p, ts, &event);
|
|
for (i = 0; i < discoverCallBackTableSize; i++) {
|
|
if ((callbacks = discoverCallBackTable[i]) &&
|
|
callbacks->on_labels != NULL)
|
|
callbacks->on_labels(&event, ident, type, sets, nsets, p->data);
|
|
}
|
|
+
|
|
+out:
|
|
+ if (sts < 0)
|
|
+ pmFreeLabelSets(sets, nsets);
|
|
}
|
|
|
|
static void
|
|
pmDiscoverInvokeTextCallBacks(pmDiscover *p, pmTimespec *ts,
|
|
int ident, int type, char *text)
|
|
{
|
|
+ discoverModuleData *data = getDiscoverModuleData(p->module);
|
|
pmDiscoverCallBacks *callbacks;
|
|
pmDiscoverEvent event;
|
|
char buf[32];
|
|
- int i;
|
|
+ int i, sts;
|
|
|
|
if (pmDebugOptions.discovery) {
|
|
fprintf(stderr, "%s[%s]: %s ", "pmDiscoverInvokeTextCallBacks",
|
|
@@ -612,12 +907,36 @@ pmDiscoverInvokeTextCallBacks(pmDiscover
|
|
fprintf(stderr, "context labels %s\n", p->context.labelset->json);
|
|
}
|
|
|
|
+ if ((type & PM_TEXT_PMID) && data->pmids) {
|
|
+ if (dictFind(data->pmids, &ident) != NULL)
|
|
+ goto out; /* text from an already excluded InDom */
|
|
+ }
|
|
+ if ((type & PM_TEXT_INDOM) && data->indoms) {
|
|
+ if (dictFind(data->indoms, &ident) != NULL)
|
|
+ goto out; /* text from an already excluded InDom */
|
|
+ }
|
|
+
|
|
+ if (p->ctx >= 0 && p->context.type == PM_CONTEXT_ARCHIVE) {
|
|
+ __pmContext *ctxp = __pmHandleToPtr(p->ctx);
|
|
+ __pmArchCtl *acp = ctxp->c_archctl;
|
|
+ char errmsg[PM_MAXERRMSGLEN];
|
|
+
|
|
+ if ((sts = __pmLogAddText(acp, ident, type, text)) < 0)
|
|
+ fprintf(stderr, "%s: failed to add %u text for %u: %s\n",
|
|
+ "pmDiscoverInvokeTextCallBacks", type, ident,
|
|
+ pmErrStr_r(sts, errmsg, sizeof(errmsg)));
|
|
+ PM_UNLOCK(ctxp->c_lock);
|
|
+ }
|
|
+
|
|
discover_event_init(p, ts, &event);
|
|
for (i = 0; i < discoverCallBackTableSize; i++) {
|
|
if ((callbacks = discoverCallBackTable[i]) &&
|
|
callbacks->on_text != NULL)
|
|
callbacks->on_text(&event, ident, type, text, p->data);
|
|
}
|
|
+
|
|
+out:
|
|
+ free(text);
|
|
}
|
|
|
|
static void
|
|
@@ -645,8 +964,8 @@ pmDiscoverNewSource(pmDiscover *p, int c
|
|
p->context.labelset = labelset;
|
|
|
|
/* use timestamp from file creation as starting time */
|
|
- timestamp.tv_sec = p->statbuf.st_birthtim.tv_sec;
|
|
- timestamp.tv_nsec = p->statbuf.st_birthtim.tv_nsec;
|
|
+ timestamp.tv_sec = p->statbuf.st_ctim.tv_sec;
|
|
+ timestamp.tv_nsec = p->statbuf.st_ctim.tv_nsec;
|
|
|
|
/* inform utilities that a source has been discovered */
|
|
pmDiscoverInvokeSourceCallBacks(p, ×tamp);
|
|
@@ -664,7 +983,7 @@ process_metadata(pmDiscover *p)
|
|
pmDesc desc;
|
|
off_t off;
|
|
char *buffer;
|
|
- int e, i, nb, len, nsets;
|
|
+ int e, nb, len, nsets;
|
|
int type, id; /* pmID or pmInDom */
|
|
int nnames;
|
|
char **names;
|
|
@@ -674,6 +993,8 @@ process_metadata(pmDiscover *p)
|
|
__pmLogHdr hdr;
|
|
sds msg, source;
|
|
static uint32_t *buf = NULL;
|
|
+ int deleted;
|
|
+ struct stat sbuf;
|
|
static int buflen = 0;
|
|
|
|
/*
|
|
@@ -683,14 +1004,17 @@ process_metadata(pmDiscover *p)
|
|
*/
|
|
p->flags |= PM_DISCOVER_FLAGS_META_IN_PROGRESS;
|
|
if (pmDebugOptions.discovery)
|
|
- fprintf(stderr, "%s: in progress, flags=%s\n",
|
|
- "process_metadata", pmDiscoverFlagsStr(p));
|
|
+ fprintf(stderr, "process_metadata: %s in progress %s\n",
|
|
+ p->context.name, pmDiscoverFlagsStr(p));
|
|
for (;;) {
|
|
off = lseek(p->fd, 0, SEEK_CUR);
|
|
nb = read(p->fd, &hdr, sizeof(__pmLogHdr));
|
|
|
|
- if (nb <= 0) {
|
|
- /* we're at EOF or an error. But may still be part way through a record */
|
|
+ deleted = is_deleted(p, &sbuf);
|
|
+ if (nb <= 0 || deleted) {
|
|
+ /* we're at EOF or an error, or deleted. But may still be part way through a record */
|
|
+ if (deleted)
|
|
+ p->flags |= PM_DISCOVER_FLAGS_DELETED;
|
|
break;
|
|
}
|
|
|
|
@@ -750,10 +1074,6 @@ process_metadata(pmDiscover *p)
|
|
ts.tv_sec = p->statbuf.st_mtim.tv_sec;
|
|
ts.tv_nsec = p->statbuf.st_mtim.tv_nsec;
|
|
pmDiscoverInvokeMetricCallBacks(p, &ts, &desc, nnames, names);
|
|
- for (i = 0; i < nnames; i++)
|
|
- free(names[i]);
|
|
- if (names)
|
|
- free(names);
|
|
break;
|
|
|
|
case TYPE_INDOM:
|
|
@@ -765,12 +1085,6 @@ process_metadata(pmDiscover *p)
|
|
break;
|
|
}
|
|
pmDiscoverInvokeInDomCallBacks(p, &ts, &inresult);
|
|
- if (inresult.numinst > 0) {
|
|
- for (i = 0; i < inresult.numinst; i++)
|
|
- free(inresult.namelist[i]);
|
|
- free(inresult.namelist);
|
|
- free(inresult.instlist);
|
|
- }
|
|
break;
|
|
|
|
case TYPE_LABEL:
|
|
@@ -795,13 +1109,13 @@ process_metadata(pmDiscover *p)
|
|
} else {
|
|
sdsfree(p->context.source);
|
|
p->context.source = source;
|
|
- p->context.labelset = labelset;
|
|
+ if (p->context.labelset)
|
|
+ pmFreeLabelSets(p->context.labelset, 1);
|
|
+ p->context.labelset = __pmDupLabelSets(labelset, 1);
|
|
pmDiscoverInvokeSourceCallBacks(p, &ts);
|
|
}
|
|
}
|
|
pmDiscoverInvokeLabelsCallBacks(p, &ts, id, type, labelset, nsets);
|
|
- if (labelset != p->context.labelset)
|
|
- pmFreeLabelSets(labelset, nsets);
|
|
break;
|
|
|
|
case TYPE_TEXT:
|
|
@@ -819,8 +1133,6 @@ process_metadata(pmDiscover *p)
|
|
ts.tv_sec = p->statbuf.st_mtim.tv_sec;
|
|
ts.tv_nsec = p->statbuf.st_mtim.tv_nsec;
|
|
pmDiscoverInvokeTextCallBacks(p, &ts, id, type, buffer);
|
|
- if (buffer)
|
|
- free(buffer);
|
|
break;
|
|
|
|
default:
|
|
@@ -833,38 +1145,89 @@ process_metadata(pmDiscover *p)
|
|
}
|
|
|
|
if (partial == 0)
|
|
- /* flag that all available metadata has been now been read */
|
|
+ /* flag that all available metadata has now been read */
|
|
p->flags &= ~PM_DISCOVER_FLAGS_META_IN_PROGRESS;
|
|
|
|
if (pmDebugOptions.discovery)
|
|
- fprintf(stderr, "%s : completed, partial=%d flags=%s\n",
|
|
- "process_metadata", partial, pmDiscoverFlagsStr(p));
|
|
+ fprintf(stderr, "%s: completed, partial=%d %s %s\n",
|
|
+ "process_metadata", partial, p->context.name, pmDiscoverFlagsStr(p));
|
|
}
|
|
|
|
/*
|
|
- * fetch metric values to EOF and call all registered callbacks
|
|
+ * Fetch metric values to EOF and call all registered callbacks.
|
|
+ * Always process metadata thru to EOF before any logvol data.
|
|
*/
|
|
static void
|
|
-process_logvol_callback(pmDiscover *p)
|
|
+process_logvol(pmDiscover *p)
|
|
{
|
|
+ int sts;
|
|
pmResult *r;
|
|
pmTimespec ts;
|
|
+ int oldcurvol;
|
|
+ __pmContext *ctxp;
|
|
+ __pmArchCtl *acp;
|
|
+
|
|
+ for (;;) {
|
|
+ pmUseContext(p->ctx);
|
|
+ ctxp = __pmHandleToPtr(p->ctx);
|
|
+ acp = ctxp->c_archctl;
|
|
+ oldcurvol = acp->ac_curvol;
|
|
+ PM_UNLOCK(ctxp->c_lock);
|
|
+
|
|
+ if ((sts = pmFetchArchive(&r)) < 0) {
|
|
+ /* err handling to skip to the next vol */
|
|
+ ctxp = __pmHandleToPtr(p->ctx);
|
|
+ acp = ctxp->c_archctl;
|
|
+ if (oldcurvol < acp->ac_curvol) {
|
|
+ __pmLogChangeVol(acp, acp->ac_curvol);
|
|
+ acp->ac_offset = 0; /* __pmLogFetch will fix it up */
|
|
+ }
|
|
+ PM_UNLOCK(ctxp->c_lock);
|
|
+
|
|
+ if (sts == PM_ERR_EOL) {
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "process_logvol: %s end of archive reached\n",
|
|
+ p->context.name);
|
|
+
|
|
+ /* succesfully processed to current end of log */
|
|
+ break;
|
|
+ } else {
|
|
+ /*
|
|
+ * This log vol was probably deleted (likely compressed)
|
|
+ * under our feet. Try and skip to the next volume.
|
|
+ * We hold the context lock during error recovery here.
|
|
+ */
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "process_logvol: %s fetch failed:%s\n",
|
|
+ p->context.name, pmErrStr(sts));
|
|
+ }
|
|
|
|
- pmUseContext(p->ctx);
|
|
- while (pmFetchArchive(&r) == 0) {
|
|
+ /* we are done - return and wait for another callback */
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Fetch succeeded - call the values callback and continue
|
|
+ */
|
|
if (pmDebugOptions.discovery) {
|
|
char tbuf[64], bufs[64];
|
|
|
|
- fprintf(stderr, "FETCHED @%s [%s] %d metrics\n",
|
|
- timeval_str(&r->timestamp, tbuf, sizeof(tbuf)),
|
|
+ fprintf(stderr, "process_logvol: %s FETCHED @%s [%s] %d metrics\n",
|
|
+ p->context.name, timeval_str(&r->timestamp, tbuf, sizeof(tbuf)),
|
|
timeval_stream_str(&r->timestamp, bufs, sizeof(bufs)),
|
|
r->numpmid);
|
|
}
|
|
+
|
|
+ /*
|
|
+ * TODO: persistently save current timestamp, so after being restarted,
|
|
+ * pmproxy can resume where it left off for each archive.
|
|
+ */
|
|
ts.tv_sec = r->timestamp.tv_sec;
|
|
ts.tv_nsec = r->timestamp.tv_usec * 1000;
|
|
pmDiscoverInvokeValuesCallBack(p, &ts, r);
|
|
pmFreeResult(r);
|
|
}
|
|
+
|
|
/* datavol is now up-to-date and at EOF */
|
|
p->flags &= ~PM_DISCOVER_FLAGS_DATAVOL_READY;
|
|
}
|
|
@@ -874,12 +1237,13 @@ pmDiscoverInvokeCallBacks(pmDiscover *p)
|
|
{
|
|
int sts;
|
|
sds msg;
|
|
+ sds metaname;
|
|
|
|
if (p->ctx < 0) {
|
|
/*
|
|
* once off initialization on the first event
|
|
*/
|
|
- if (p->flags & PM_DISCOVER_FLAGS_DATAVOL) {
|
|
+ if (p->flags & (PM_DISCOVER_FLAGS_DATAVOL | PM_DISCOVER_FLAGS_META)) {
|
|
struct timeval tvp;
|
|
|
|
/* create the PMAPI context (once off) */
|
|
@@ -898,28 +1262,25 @@ pmDiscoverInvokeCallBacks(pmDiscover *p)
|
|
p->ctx = -1;
|
|
return;
|
|
}
|
|
+ /* seek to end of archive for logvol data - see TODO in process_logvol() */
|
|
pmSetMode(PM_MODE_FORW, &tvp, 1);
|
|
- /* note: we do not scan pre-existing logvol data. */
|
|
- }
|
|
- else if (p->flags & PM_DISCOVER_FLAGS_META) {
|
|
- if ((sts = pmNewContext(p->context.type, p->context.name)) < 0) {
|
|
- infofmt(msg, "pmNewContext failed for %s: %s\n",
|
|
- p->context.name, pmErrStr(sts));
|
|
- moduleinfo(p->module, PMLOG_ERROR, msg, p->data);
|
|
- return;
|
|
- }
|
|
- pmDiscoverNewSource(p, sts);
|
|
|
|
- /* for archive meta files, p->fd is the direct file descriptor */
|
|
- if ((p->fd = open(p->context.name, O_RDONLY)) < 0) {
|
|
- infofmt(msg, "open failed for %s: %s\n", p->context.name,
|
|
- osstrerror());
|
|
+ /*
|
|
+ * For archive meta files, p->fd is the direct file descriptor
|
|
+ * and we pre-scan existing metadata. Note: we do NOT scan
|
|
+ * pre-existing logvol data (see pmSetMode above)
|
|
+ */
|
|
+ metaname = sdsnew(p->context.name);
|
|
+ metaname = sdscat(metaname, ".meta");
|
|
+ if ((p->fd = open(metaname, O_RDONLY)) < 0) {
|
|
+ infofmt(msg, "open failed for %s: %s\n", metaname, osstrerror());
|
|
moduleinfo(p->module, PMLOG_ERROR, msg, p->data);
|
|
+ sdsfree(metaname);
|
|
return;
|
|
}
|
|
-
|
|
- /* process all existing metadata */
|
|
+ /* pre-process all existing metadata */
|
|
process_metadata(p);
|
|
+ sdsfree(metaname);
|
|
}
|
|
}
|
|
|
|
@@ -943,15 +1304,61 @@ pmDiscoverInvokeCallBacks(pmDiscover *p)
|
|
}
|
|
|
|
if (p->flags & PM_DISCOVER_FLAGS_META) {
|
|
- /* process metadata */
|
|
+ /* process new metadata, if any */
|
|
process_metadata(p);
|
|
}
|
|
|
|
- /* process any unprocessed datavol callbacks */
|
|
- pmDiscoverTraverse(PM_DISCOVER_FLAGS_DATAVOL_READY, process_logvol_callback);
|
|
+ if ((p->flags & PM_DISCOVER_FLAGS_META_IN_PROGRESS) == 0) {
|
|
+ /* no metdata read in progress, so process new datavol data, if any */
|
|
+ process_logvol(p);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+print_callback(pmDiscover *p)
|
|
+{
|
|
+ if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
|
|
+ fprintf(stderr, " DIRECTORY %s %s\n",
|
|
+ p->context.name, pmDiscoverFlagsStr(p));
|
|
+ }
|
|
+ else {
|
|
+ __pmContext *ctxp;
|
|
+ __pmArchCtl *acp;
|
|
|
|
- /* finally, purge deleted entries, if any */
|
|
- pmDiscoverPurgeDeleted();
|
|
+ if (p->ctx >= 0 && (ctxp = __pmHandleToPtr(p->ctx)) != NULL) {
|
|
+ acp = ctxp->c_archctl;
|
|
+ fprintf(stderr, " ARCHIVE %s fd=%d ctx=%d maxvol=%d ac_curvol=%d ac_offset=%ld %s\n",
|
|
+ p->context.name, p->fd, p->ctx, acp->ac_log->l_maxvol, acp->ac_curvol,
|
|
+ acp->ac_offset, pmDiscoverFlagsStr(p));
|
|
+ PM_UNLOCK(ctxp->c_lock);
|
|
+ } else {
|
|
+ /* no context yet - probably PM_DISCOVER_FLAGS_NEW */
|
|
+ fprintf(stderr, " ARCHIVE %s fd=%d ctx=%d %s\n",
|
|
+ p->context.name, p->fd, p->ctx, pmDiscoverFlagsStr(p));
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*
|
|
+ * p is a tracked archive and arg is a directory path.
|
|
+ * If p is in the directory, call it's callbacks to
|
|
+ * process metadata and logvol data. This allows better
|
|
+ * scalability because we only process archives in the
|
|
+ * directories that have changed.
|
|
+ */
|
|
+static void
|
|
+directory_changed_cb(pmDiscover *p, void *arg)
|
|
+{
|
|
+ char *dirpath = (char *)arg;
|
|
+ int dlen = strlen(dirpath);
|
|
+
|
|
+ if (strncmp(p->context.name, dirpath, dlen) == 0) {
|
|
+ /* this archive is in this directory - process it's metadata and logvols */
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "directory_changed_cb: archive %s is in dir %s\n",
|
|
+ p->context.name, dirpath);
|
|
+ pmDiscoverInvokeCallBacks(p);
|
|
+ }
|
|
}
|
|
|
|
static void
|
|
@@ -962,27 +1369,46 @@ changed_callback(pmDiscover *p)
|
|
pmDiscoverFlagsStr(p));
|
|
|
|
if (p->flags & PM_DISCOVER_FLAGS_DELETED) {
|
|
- /* path or directory has been deleted - remove from hash table */
|
|
- deleted_callback(p);
|
|
- }
|
|
- else if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
|
|
/*
|
|
- * A changed directory path means a new archive or subdirectory
|
|
- * has been created - traverse and update the hash table.
|
|
+ * Path has been deleted. Do nothing for now. Will be purged
|
|
+ * in due course by pmDiscoverPurgeDeleted.
|
|
*/
|
|
- pmDiscoverArchives(p->context.name, p->module, p->data);
|
|
- pmDiscoverTraverse(PM_DISCOVER_FLAGS_NEW, created_callback);
|
|
+ return;
|
|
+
|
|
}
|
|
- else if (p->flags & PM_DISCOVER_FLAGS_COMPRESSED) {
|
|
+
|
|
+ if (p->flags & PM_DISCOVER_FLAGS_COMPRESSED) {
|
|
/* we do not monitor compressed files - do nothing */
|
|
- ; /**/
|
|
+ return;
|
|
}
|
|
- else if (p->flags & (PM_DISCOVER_FLAGS_DATAVOL|PM_DISCOVER_FLAGS_META)) {
|
|
- /*
|
|
- * We only monitor uncompressed logvol and metadata paths. Fetch new data
|
|
- * (metadata or logvol) and call the registered callbacks.
|
|
+
|
|
+ if (p->flags & PM_DISCOVER_FLAGS_DIRECTORY) {
|
|
+ /*
|
|
+ * A changed directory path means a new archive or subdirectory may have
|
|
+ * been created or deleted - traverse and update the hash table.
|
|
*/
|
|
- pmDiscoverInvokeCallBacks(p);
|
|
+ if (pmDebugOptions.discovery) {
|
|
+ fprintf(stderr, "%s DIRECTORY CHANGED %s (%s)\n",
|
|
+ stamp(), p->context.name, pmDiscoverFlagsStr(p));
|
|
+ }
|
|
+ pmDiscoverArchives(p->context.name, p->module, p->data);
|
|
+ pmDiscoverTraverse(PM_DISCOVER_FLAGS_NEW, created_callback);
|
|
+
|
|
+ /*
|
|
+ * Walk directory and invoke callbacks for tracked archives in this
|
|
+ * directory that have changed
|
|
+ */
|
|
+ pmDiscoverTraverseArg(PM_DISCOVER_FLAGS_DATAVOL|PM_DISCOVER_FLAGS_META,
|
|
+ directory_changed_cb, (void *)p->context.name);
|
|
+
|
|
+ /* finally, purge deleted entries (globally), if any */
|
|
+ pmDiscoverPurgeDeleted();
|
|
+ }
|
|
+
|
|
+ if (pmDebugOptions.discovery) {
|
|
+ fprintf(stderr, "%s -- tracking status\n", stamp());
|
|
+ pmDiscoverTraverse(PM_DISCOVER_FLAGS_ALL, print_callback);
|
|
+ fprintf(stderr, "--\n");
|
|
}
|
|
}
|
|
|
|
@@ -995,18 +1421,9 @@ dir_callback(pmDiscover *p)
|
|
static void
|
|
archive_callback(pmDiscover *p)
|
|
{
|
|
- if (p->flags & PM_DISCOVER_FLAGS_COMPRESSED)
|
|
- return; /* compressed archives don't grow */
|
|
-
|
|
- if (p->flags & PM_DISCOVER_FLAGS_DATAVOL) {
|
|
- if (pmDebugOptions.discovery)
|
|
- fprintf(stderr, "DISCOVERED ARCHIVE LOGVOL %s\n", p->context.name);
|
|
- pmDiscoverMonitor(p->context.name, changed_callback);
|
|
- }
|
|
-
|
|
if (p->flags & PM_DISCOVER_FLAGS_META) {
|
|
if (pmDebugOptions.discovery)
|
|
- fprintf(stderr, "DISCOVERED ARCHIVE METADATA %s\n", p->context.name);
|
|
+ fprintf(stderr, "DISCOVERED ARCHIVE %s\n", p->context.name);
|
|
pmDiscoverMonitor(p->context.name, changed_callback);
|
|
}
|
|
}
|
|
@@ -1048,9 +1465,9 @@ pmDiscoverRegister(const char *dir, pmDi
|
|
}
|
|
|
|
if (pmDebugOptions.discovery) {
|
|
- fprintf(stderr, "Now managing %d directories and %d archive files\n",
|
|
+ fprintf(stderr, "Now tracking %d directories and %d archives\n",
|
|
pmDiscoverTraverse(PM_DISCOVER_FLAGS_DIRECTORY, NULL),
|
|
- pmDiscoverTraverse(PM_DISCOVER_FLAGS_DATAVOL, NULL));
|
|
+ pmDiscoverTraverse(PM_DISCOVER_FLAGS_DATAVOL|PM_DISCOVER_FLAGS_META, NULL));
|
|
}
|
|
|
|
/* monitor the directories */
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/discover.h pcp-5.0.2/src/libpcp_web/src/discover.h
|
|
--- pcp-5.0.2.orig/src/libpcp_web/src/discover.h 2019-12-10 17:04:20.000000000 +1100
|
|
+++ pcp-5.0.2/src/libpcp_web/src/discover.h 2020-02-03 13:36:09.904659047 +1100
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2018-2019 Red Hat.
|
|
+ * Copyright (c) 2018-2020 Red Hat.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published
|
|
@@ -18,7 +18,9 @@
|
|
#include "libpcp.h"
|
|
#include "mmv_stats.h"
|
|
#include "slots.h"
|
|
-
|
|
+#ifdef HAVE_REGEX_H
|
|
+#include <regex.h>
|
|
+#endif
|
|
#ifdef HAVE_LIBUV
|
|
#include <uv.h>
|
|
#else
|
|
@@ -84,8 +86,8 @@ typedef struct pmDiscover {
|
|
int fd; /* meta file descriptor */
|
|
#ifdef HAVE_LIBUV
|
|
uv_fs_event_t *event_handle; /* uv fs_notify event handle */
|
|
- uv_stat_t statbuf; /* stat buffer from event CB */
|
|
#endif
|
|
+ struct stat statbuf; /* stat buffer */
|
|
void *baton; /* private internal lib data */
|
|
void *data; /* opaque user data pointer */
|
|
} pmDiscover;
|
|
@@ -115,6 +117,10 @@ typedef struct discoverModuleData {
|
|
struct dict *config; /* configuration dict */
|
|
uv_loop_t *events; /* event library loop */
|
|
redisSlots *slots; /* server slots data */
|
|
+ regex_t exclude_names; /* metric names to exclude */
|
|
+ struct dict *pmids; /* dict of excluded PMIDs */
|
|
+ unsigned int exclude_indoms; /* exclude instance domains */
|
|
+ struct dict *indoms; /* dict of excluded InDoms */
|
|
void *data; /* user-supplied pointer */
|
|
} discoverModuleData;
|
|
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/exports pcp-5.0.2/src/libpcp_web/src/exports
|
|
--- pcp-5.0.2.orig/src/libpcp_web/src/exports 2019-11-26 16:29:58.000000000 +1100
|
|
+++ pcp-5.0.2/src/libpcp_web/src/exports 2020-02-03 13:23:15.264762900 +1100
|
|
@@ -178,3 +178,8 @@ PCP_WEB_1.11 {
|
|
global:
|
|
pmSeriesLabelValues;
|
|
} PCP_WEB_1.10;
|
|
+
|
|
+PCP_WEB_1.12 {
|
|
+ global:
|
|
+ SDS_NOINIT;
|
|
+} PCP_WEB_1.11;
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/load.c pcp-5.0.2/src/libpcp_web/src/load.c
|
|
--- pcp-5.0.2.orig/src/libpcp_web/src/load.c 2019-12-11 14:01:53.000000000 +1100
|
|
+++ pcp-5.0.2/src/libpcp_web/src/load.c 2020-02-03 13:36:03.947721365 +1100
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2017-2019 Red Hat.
|
|
+ * Copyright (c) 2017-2020 Red Hat.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published
|
|
@@ -112,22 +112,41 @@ load_prepare_metric(const char *name, vo
|
|
* Iterate over an instance domain and extract names and labels
|
|
* for each instance.
|
|
*/
|
|
-static unsigned int
|
|
-get_instance_metadata(seriesLoadBaton *baton, pmInDom indom)
|
|
+static void
|
|
+get_instance_metadata(seriesLoadBaton *baton, pmInDom indom, int force_refresh)
|
|
{
|
|
context_t *cp = &baton->pmapi.context;
|
|
- unsigned int count = 0;
|
|
domain_t *dp;
|
|
indom_t *ip;
|
|
|
|
if (indom != PM_INDOM_NULL) {
|
|
if ((dp = pmwebapi_add_domain(cp, pmInDom_domain(indom))))
|
|
pmwebapi_add_domain_labels(cp, dp);
|
|
- if ((ip = pmwebapi_add_indom(cp, dp, indom)) &&
|
|
- (count = pmwebapi_add_indom_instances(cp, ip)) > 0)
|
|
- pmwebapi_add_instances_labels(cp, ip);
|
|
+ if ((ip = pmwebapi_add_indom(cp, dp, indom)) != NULL) {
|
|
+ if (force_refresh)
|
|
+ ip->updated = 1;
|
|
+ if (ip->updated) {
|
|
+ pmwebapi_add_indom_instances(cp, ip);
|
|
+ pmwebapi_add_instances_labels(cp, ip);
|
|
+ }
|
|
+ }
|
|
}
|
|
- return count;
|
|
+}
|
|
+
|
|
+static void
|
|
+get_metric_metadata(seriesLoadBaton *baton, metric_t *metric)
|
|
+{
|
|
+ context_t *context = &baton->pmapi.context;
|
|
+
|
|
+ if (metric->cluster) {
|
|
+ if (metric->cluster->domain)
|
|
+ pmwebapi_add_domain_labels(context, metric->cluster->domain);
|
|
+ pmwebapi_add_cluster_labels(context, metric->cluster);
|
|
+ }
|
|
+ if (metric->indom)
|
|
+ pmwebapi_add_instances_labels(context, metric->indom);
|
|
+ pmwebapi_add_item_labels(context, metric);
|
|
+ pmwebapi_metric_hash(metric);
|
|
}
|
|
|
|
static metric_t *
|
|
@@ -140,18 +159,25 @@ new_metric(seriesLoadBaton *baton, pmVal
|
|
char **nameall = NULL;
|
|
int count, sts, i;
|
|
|
|
- if ((sts = pmLookupDesc(vsp->pmid, &desc)) < 0) {
|
|
+ if ((sts = pmUseContext(context->context)) < 0) {
|
|
+ fprintf(stderr, "%s: failed to use context for PMID %s: %s\n",
|
|
+ "new_metric",
|
|
+ pmIDStr_r(vsp->pmid, idbuf, sizeof(idbuf)),
|
|
+ pmErrStr_r(sts, errmsg, sizeof(errmsg)));
|
|
+ } else if ((sts = pmLookupDesc(vsp->pmid, &desc)) < 0) {
|
|
if (sts == PM_ERR_IPC)
|
|
context->setup = 0;
|
|
if (pmDebugOptions.series)
|
|
- fprintf(stderr, "failed to lookup metric %s descriptor: %s",
|
|
+ fprintf(stderr, "%s: failed to lookup metric %s descriptor: %s\n",
|
|
+ "new_metric",
|
|
pmIDStr_r(vsp->pmid, idbuf, sizeof(idbuf)),
|
|
pmErrStr_r(sts, errmsg, sizeof(errmsg)));
|
|
} else if ((sts = count = pmNameAll(vsp->pmid, &nameall)) < 0) {
|
|
if (sts == PM_ERR_IPC)
|
|
context->setup = 0;
|
|
if (pmDebugOptions.series)
|
|
- fprintf(stderr, "failed to lookup metric %s names: %s",
|
|
+ fprintf(stderr, "%s: failed to lookup metric %s names: %s\n",
|
|
+ "new_metric",
|
|
pmIDStr_r(vsp->pmid, idbuf, sizeof(idbuf)),
|
|
pmErrStr_r(sts, errmsg, sizeof(errmsg)));
|
|
}
|
|
@@ -160,18 +186,10 @@ new_metric(seriesLoadBaton *baton, pmVal
|
|
|
|
if ((metric = pmwebapi_new_metric(context, NULL, &desc, count, nameall)) == NULL)
|
|
return NULL;
|
|
- if (metric->cluster) {
|
|
- if (metric->cluster->domain)
|
|
- pmwebapi_add_domain_labels(context, metric->cluster->domain);
|
|
- pmwebapi_add_cluster_labels(context, metric->cluster);
|
|
- }
|
|
- if (metric->indom)
|
|
- pmwebapi_add_instances_labels(context, metric->indom);
|
|
- pmwebapi_add_item_labels(context, metric);
|
|
- pmwebapi_metric_hash(metric);
|
|
+ get_metric_metadata(baton, metric);
|
|
|
|
if (pmDebugOptions.series) {
|
|
- fprintf(stderr, "new_metric [%s] names:",
|
|
+ fprintf(stderr, "%s [%s] names:\n", "new_metric",
|
|
pmIDStr_r(vsp->pmid, idbuf, sizeof(idbuf)));
|
|
for (i = 0; i < count; i++) {
|
|
pmwebapi_hash_str(metric->names[i].hash, idbuf, sizeof(idbuf));
|
|
@@ -409,7 +427,7 @@ pmwebapi_add_valueset(metric_t *metric,
|
|
}
|
|
|
|
static void
|
|
-series_cache_update(seriesLoadBaton *baton)
|
|
+series_cache_update(seriesLoadBaton *baton, struct dict *exclude)
|
|
{
|
|
seriesGetContext *context = &baton->pmapi;
|
|
context_t *cp = &context->context;
|
|
@@ -418,7 +436,7 @@ series_cache_update(seriesLoadBaton *bat
|
|
metric_t *metric = NULL;
|
|
char ts[64];
|
|
sds timestamp;
|
|
- int i, write_meta, write_data;
|
|
+ int i, write_meta, write_inst, write_data;
|
|
|
|
timestamp = sdsnew(timeval_stream_str(&result->timestamp, ts, sizeof(ts)));
|
|
write_data = (!(baton->flags & PM_SERIES_FLAG_METADATA));
|
|
@@ -441,6 +459,12 @@ series_cache_update(seriesLoadBaton *bat
|
|
dictFetchValue(baton->wanted, &vsp->pmid) == NULL)
|
|
continue;
|
|
|
|
+ /* check if metric to be skipped (optional metric exclusion) */
|
|
+ if (exclude && (dictFind(exclude, &vsp->pmid)) != NULL)
|
|
+ continue;
|
|
+
|
|
+ write_meta = write_inst = 0;
|
|
+
|
|
/* check if pmid already in hash list */
|
|
if ((metric = dictFetchValue(cp->pmids, &vsp->pmid)) == NULL) {
|
|
/* create a new metric, and add it to load context */
|
|
@@ -448,21 +472,22 @@ series_cache_update(seriesLoadBaton *bat
|
|
continue;
|
|
write_meta = 1;
|
|
} else { /* pmid already observed */
|
|
- write_meta = 0;
|
|
+ if ((write_meta = metric->cached) == 0)
|
|
+ get_metric_metadata(baton, metric);
|
|
}
|
|
|
|
/* iterate through result instances and ensure metric_t is complete */
|
|
if (metric->error == 0 && vsp->numval < 0)
|
|
write_meta = 1;
|
|
if (pmwebapi_add_valueset(metric, vsp) != 0)
|
|
- write_meta = 1;
|
|
+ write_meta = write_inst = 1;
|
|
|
|
/* record the error code in the cache */
|
|
metric->error = (vsp->numval < 0) ? vsp->numval : 0;
|
|
|
|
/* make PMAPI calls to cache metadata */
|
|
- if (write_meta && get_instance_metadata(baton, metric->desc.indom) != 0)
|
|
- continue;
|
|
+ if (write_meta)
|
|
+ get_instance_metadata(baton, metric->desc.indom, write_inst);
|
|
|
|
/* initiate writes to backend caching servers (Redis) */
|
|
server_cache_metric(baton, metric, timestamp, write_meta, write_data);
|
|
@@ -549,7 +574,7 @@ server_cache_window(void *arg)
|
|
(finish->tv_sec == result->timestamp.tv_sec &&
|
|
finish->tv_usec >= result->timestamp.tv_usec)) {
|
|
context->done = server_cache_update_done;
|
|
- series_cache_update(baton);
|
|
+ series_cache_update(baton, NULL);
|
|
}
|
|
else {
|
|
if (pmDebugOptions.series)
|
|
@@ -1023,7 +1048,7 @@ pmSeriesDiscoverSource(pmDiscoverEvent *
|
|
sds msg;
|
|
int i;
|
|
|
|
- if (data == NULL || data->slots == NULL)
|
|
+ if (data == NULL || data->slots == NULL || data->slots->setup == 0)
|
|
return;
|
|
|
|
baton = (seriesLoadBaton *)calloc(1, sizeof(seriesLoadBaton));
|
|
@@ -1032,22 +1057,31 @@ pmSeriesDiscoverSource(pmDiscoverEvent *
|
|
moduleinfo(module, PMLOG_ERROR, msg, arg);
|
|
return;
|
|
}
|
|
+ if ((set = pmwebapi_labelsetdup(p->context.labelset)) == NULL) {
|
|
+ infofmt(msg, "%s: out of memory for labels", "pmSeriesDiscoverSource");
|
|
+ moduleinfo(module, PMLOG_ERROR, msg, arg);
|
|
+ free(baton);
|
|
+ return;
|
|
+ }
|
|
+
|
|
initSeriesLoadBaton(baton, module, 0 /*flags*/,
|
|
module->on_info, series_discover_done,
|
|
data->slots, arg);
|
|
initSeriesGetContext(&baton->pmapi, baton);
|
|
p->baton = baton;
|
|
|
|
+ cp = &baton->pmapi.context;
|
|
+
|
|
if (pmDebugOptions.discovery)
|
|
- fprintf(stderr, "%s: new source %s context=%d\n",
|
|
- "pmSeriesDiscoverSource", p->context.name, p->ctx);
|
|
+ fprintf(stderr, "%s: new source %s context=%p ctxid=%d\n",
|
|
+ "pmSeriesDiscoverSource", p->context.name, cp, p->ctx);
|
|
|
|
- cp = &baton->pmapi.context;
|
|
cp->context = p->ctx;
|
|
cp->type = p->context.type;
|
|
cp->name.sds = sdsdup(p->context.name);
|
|
- cp->host = p->context.hostname;
|
|
- cp->labelset = set = p->context.labelset;
|
|
+ cp->host = sdsdup(p->context.hostname);
|
|
+ cp->labelset = set;
|
|
+
|
|
pmwebapi_source_hash(cp->name.hash, set->json, set->jsonlen);
|
|
pmwebapi_setup_context(cp);
|
|
set_source_origin(cp);
|
|
@@ -1095,21 +1129,22 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
|
|
sds msg;
|
|
int i, id;
|
|
|
|
+ if (baton == NULL || baton->slots == NULL || baton->slots->setup == 0)
|
|
+ return;
|
|
+
|
|
switch (type) {
|
|
case PM_LABEL_CONTEXT:
|
|
if (pmDebugOptions.discovery)
|
|
fprintf(stderr, "%s: context\n", "pmSeriesDiscoverLabels");
|
|
|
|
if ((labels = pmwebapi_labelsetdup(sets)) != NULL) {
|
|
-#if 0 /* PCP GH#800 do not free this labelset - it's owned by the discover code */
|
|
if (cp->labelset)
|
|
pmFreeLabelSets(cp->labelset, 1);
|
|
-#endif
|
|
cp->labelset = labels;
|
|
pmwebapi_locate_context(cp);
|
|
cp->updated = 1;
|
|
} else {
|
|
- infofmt(msg, "failed to duplicate label set");
|
|
+ infofmt(msg, "failed to duplicate %s label set", "context");
|
|
moduleinfo(event->module, PMLOG_ERROR, msg, arg);
|
|
}
|
|
break;
|
|
@@ -1125,8 +1160,8 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
|
|
pmFreeLabelSets(domain->labelset, 1);
|
|
domain->labelset = labels;
|
|
domain->updated = 1;
|
|
- } else {
|
|
- infofmt(msg, "failed to duplicate label set");
|
|
+ } else if (domain) {
|
|
+ infofmt(msg, "failed to duplicate %s label set", "domain");
|
|
moduleinfo(event->module, PMLOG_ERROR, msg, arg);
|
|
}
|
|
break;
|
|
@@ -1142,8 +1177,8 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
|
|
pmFreeLabelSets(cluster->labelset, 1);
|
|
cluster->labelset = labels;
|
|
cluster->updated = 1;
|
|
- } else {
|
|
- infofmt(msg, "failed to duplicate label set");
|
|
+ } else if (cluster) {
|
|
+ infofmt(msg, "failed to duplicate %s label set", "cluster");
|
|
moduleinfo(event->module, PMLOG_ERROR, msg, arg);
|
|
}
|
|
break;
|
|
@@ -1159,8 +1194,8 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
|
|
pmFreeLabelSets(metric->labelset, 1);
|
|
metric->labelset = labels;
|
|
metric->updated = 1;
|
|
- } else {
|
|
- infofmt(msg, "failed to duplicate label set");
|
|
+ } else if (metric) {
|
|
+ infofmt(msg, "failed to duplicate %s label set", "item");
|
|
moduleinfo(event->module, PMLOG_ERROR, msg, arg);
|
|
}
|
|
break;
|
|
@@ -1177,8 +1212,8 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
|
|
pmFreeLabelSets(indom->labelset, 1);
|
|
indom->labelset = labels;
|
|
indom->updated = 1;
|
|
- } else {
|
|
- infofmt(msg, "failed to duplicate label set");
|
|
+ } else if (indom) {
|
|
+ infofmt(msg, "failed to duplicate %s label set", "indom");
|
|
moduleinfo(event->module, PMLOG_ERROR, msg, arg);
|
|
}
|
|
break;
|
|
@@ -1196,7 +1231,7 @@ pmSeriesDiscoverLabels(pmDiscoverEvent *
|
|
if ((instance = dictFetchValue(indom->insts, &id)) == NULL)
|
|
continue;
|
|
if ((labels = pmwebapi_labelsetdup(&sets[i])) == NULL) {
|
|
- infofmt(msg, "failed to dup %s instance labels: %s",
|
|
+ infofmt(msg, "failed to dup indom %s instance label set: %s",
|
|
pmInDomStr_r(indom->indom, idbuf, sizeof(idbuf)),
|
|
pmErrStr_r(-ENOMEM, errmsg, sizeof(errmsg)));
|
|
moduleinfo(event->module, PMLOG_ERROR, msg, arg);
|
|
@@ -1229,10 +1264,13 @@ pmSeriesDiscoverMetric(pmDiscoverEvent *
|
|
|
|
if (pmDebugOptions.discovery) {
|
|
for (i = 0; i < numnames; i++)
|
|
- fprintf(stderr, "pmSeriesDiscoverMetric: [%d/%d] %s - %s\n",
|
|
+ fprintf(stderr, "%s: [%d/%d] %s - %s\n", "pmSeriesDiscoverMetric",
|
|
i + 1, numnames, pmIDStr(desc->pmid), names[i]);
|
|
}
|
|
|
|
+ if (baton == NULL || baton->slots == NULL || baton->slots->setup == 0)
|
|
+ return;
|
|
+
|
|
if ((metric = pmwebapi_add_metric(&baton->pmapi.context,
|
|
NULL, desc, numnames, names)) == NULL) {
|
|
infofmt(msg, "%s: failed metric discovery", "pmSeriesDiscoverMetric");
|
|
@@ -1244,18 +1282,23 @@ pmSeriesDiscoverMetric(pmDiscoverEvent *
|
|
void
|
|
pmSeriesDiscoverValues(pmDiscoverEvent *event, pmResult *result, void *arg)
|
|
{
|
|
+ pmDiscoverModule *module = event->module;
|
|
pmDiscover *p = (pmDiscover *)event->data;
|
|
seriesLoadBaton *baton = p->baton;
|
|
seriesGetContext *context = &baton->pmapi;
|
|
+ discoverModuleData *data = getDiscoverModuleData(module);
|
|
|
|
if (pmDebugOptions.discovery)
|
|
fprintf(stderr, "%s: result numpmids=%d\n", "pmSeriesDiscoverValues", result->numpmid);
|
|
|
|
+ if (baton == NULL || baton->slots == NULL || baton->slots->setup == 0)
|
|
+ return;
|
|
+
|
|
seriesBatonReference(context, "pmSeriesDiscoverValues");
|
|
baton->arg = arg;
|
|
context->result = result;
|
|
|
|
- series_cache_update(baton);
|
|
+ series_cache_update(baton, data->pmids);
|
|
}
|
|
|
|
void
|
|
@@ -1271,7 +1314,10 @@ pmSeriesDiscoverInDom(pmDiscoverEvent *e
|
|
int i;
|
|
|
|
if (pmDebugOptions.discovery)
|
|
- fprintf(stderr, "pmSeriesDiscoverInDom: %s\n", pmInDomStr(id));
|
|
+ fprintf(stderr, "%s: %s\n", "pmSeriesDiscoverInDom", pmInDomStr(id));
|
|
+
|
|
+ if (baton == NULL || baton->slots == NULL || baton->slots->setup == 0)
|
|
+ return;
|
|
|
|
if ((domain = pmwebapi_add_domain(context, pmInDom_domain(id))) == NULL) {
|
|
infofmt(msg, "%s: failed indom discovery (domain %u)",
|
|
@@ -1303,11 +1349,10 @@ pmSeriesDiscoverText(pmDiscoverEvent *ev
|
|
pmDiscover *p = (pmDiscover *)event->data;
|
|
seriesLoadBaton *baton = p->baton;
|
|
|
|
- (void)baton;
|
|
- (void)ident;
|
|
- (void)type;
|
|
- (void)text;
|
|
- (void)arg;
|
|
+ if (pmDebugOptions.discovery)
|
|
+ fprintf(stderr, "%s: ident=%u type=%u arg=%p\n",
|
|
+ "pmSeriesDiscoverText", ident, type, arg);
|
|
|
|
- /* for Redis, help text will need special handling (RediSearch) */
|
|
+ if (baton == NULL || baton->slots == NULL || baton->slots->setup == 0)
|
|
+ return;
|
|
}
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/query.c pcp-5.0.2/src/libpcp_web/src/query.c
|
|
--- pcp-5.0.2.orig/src/libpcp_web/src/query.c 2019-12-05 17:29:43.000000000 +1100
|
|
+++ pcp-5.0.2/src/libpcp_web/src/query.c 2020-02-03 13:23:15.265762890 +1100
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2017-2019 Red Hat.
|
|
+ * Copyright (c) 2017-2020 Red Hat.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published
|
|
@@ -1243,24 +1243,43 @@ series_prepare_time_reply(
|
|
series_query_end_phase(baton);
|
|
}
|
|
|
|
+unsigned int
|
|
+series_value_count_only(timing_t *tp)
|
|
+{
|
|
+ if (tp->window.range || tp->window.delta ||
|
|
+ tp->window.start || tp->window.end)
|
|
+ return 0;
|
|
+ return tp->count;
|
|
+}
|
|
+
|
|
static void
|
|
series_prepare_time(seriesQueryBaton *baton, series_set_t *result)
|
|
{
|
|
timing_t *tp = &baton->u.query.timing;
|
|
unsigned char *series = result->series;
|
|
seriesGetSID *sid;
|
|
- char buffer[64];
|
|
+ char buffer[64], revbuf[64];
|
|
sds start, end, key, cmd;
|
|
- unsigned int i;
|
|
+ unsigned int i, revlen = 0, reverse = 0;
|
|
+
|
|
+ /* if only 'count' is requested, work back from most recent value */
|
|
+ if ((reverse = series_value_count_only(tp)) != 0) {
|
|
+ revlen = pmsprintf(revbuf, sizeof(revbuf), "%u", reverse);
|
|
+ start = sdsnew("+");
|
|
+ } else {
|
|
+ start = sdsnew(timeval_stream_str(&tp->start, buffer, sizeof(buffer)));
|
|
+ }
|
|
|
|
- start = sdsnew(timeval_stream_str(&tp->start, buffer, sizeof(buffer)));
|
|
if (pmDebugOptions.series)
|
|
fprintf(stderr, "START: %s\n", start);
|
|
|
|
- if (tp->end.tv_sec)
|
|
+ if (reverse)
|
|
+ end = sdsnew("-");
|
|
+ else if (tp->end.tv_sec)
|
|
end = sdsnew(timeval_stream_str(&tp->end, buffer, sizeof(buffer)));
|
|
else
|
|
end = sdsnew("+"); /* "+" means "no end" - to the most recent */
|
|
+
|
|
if (pmDebugOptions.series)
|
|
fprintf(stderr, "END: %s\n", end);
|
|
|
|
@@ -1277,12 +1296,21 @@ series_prepare_time(seriesQueryBaton *ba
|
|
|
|
key = sdscatfmt(sdsempty(), "pcp:values:series:%S", sid->name);
|
|
|
|
- /* XRANGE key t1 t2 */
|
|
- cmd = redis_command(4);
|
|
- cmd = redis_param_str(cmd, XRANGE, XRANGE_LEN);
|
|
+ /* X[REV]RANGE key t1 t2 [count N] */
|
|
+ if (reverse) {
|
|
+ cmd = redis_command(6);
|
|
+ cmd = redis_param_str(cmd, XREVRANGE, XREVRANGE_LEN);
|
|
+ } else {
|
|
+ cmd = redis_command(4);
|
|
+ cmd = redis_param_str(cmd, XRANGE, XRANGE_LEN);
|
|
+ }
|
|
cmd = redis_param_sds(cmd, key);
|
|
cmd = redis_param_sds(cmd, start);
|
|
cmd = redis_param_sds(cmd, end);
|
|
+ if (reverse) {
|
|
+ cmd = redis_param_str(cmd, "COUNT", sizeof("COUNT")-1);
|
|
+ cmd = redis_param_str(cmd, revbuf, revlen);
|
|
+ }
|
|
redisSlotsRequest(baton->slots, XRANGE, key, cmd,
|
|
series_prepare_time_reply, sid);
|
|
}
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/schema.c pcp-5.0.2/src/libpcp_web/src/schema.c
|
|
--- pcp-5.0.2.orig/src/libpcp_web/src/schema.c 2019-11-18 19:35:11.000000000 +1100
|
|
+++ pcp-5.0.2/src/libpcp_web/src/schema.c 2020-02-03 13:36:03.948721355 +1100
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2017-2019 Red Hat.
|
|
+ * Copyright (c) 2017-2020 Red Hat.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published
|
|
@@ -819,7 +819,7 @@ redis_series_metric(redisSlots *slots, m
|
|
*/
|
|
|
|
/* ensure all metric name strings are mapped */
|
|
- for (i = 0; i < metric->numnames; i++) {
|
|
+ for (i = 0; metric->cached == 0 && i < metric->numnames; i++) {
|
|
assert(metric->names[i].sds != NULL);
|
|
seriesBatonReference(baton, "redis_series_metric");
|
|
redisGetMap(slots,
|
|
@@ -830,7 +830,8 @@ redis_series_metric(redisSlots *slots, m
|
|
|
|
/* ensure all metric or instance label strings are mapped */
|
|
if (metric->desc.indom == PM_INDOM_NULL || metric->u.vlist == NULL) {
|
|
- series_metric_label_mapping(metric, baton);
|
|
+ if (metric->cached == 0)
|
|
+ series_metric_label_mapping(metric, baton);
|
|
} else {
|
|
for (i = 0; i < metric->u.vlist->listcount; i++) {
|
|
value = &metric->u.vlist->value[i];
|
|
@@ -847,7 +848,8 @@ redis_series_metric(redisSlots *slots, m
|
|
series_name_mapping_callback,
|
|
baton->info, baton->userdata, baton);
|
|
|
|
- series_instance_label_mapping(metric, instance, baton);
|
|
+ if (instance->cached == 0)
|
|
+ series_instance_label_mapping(metric, instance, baton);
|
|
}
|
|
}
|
|
|
|
@@ -941,6 +943,9 @@ redis_series_metadata(context_t *context
|
|
sds cmd, key;
|
|
int i;
|
|
|
|
+ if (metric->cached)
|
|
+ goto check_instances;
|
|
+
|
|
indom = pmwebapi_indom_str(metric, ibuf, sizeof(ibuf));
|
|
pmid = pmwebapi_pmid_str(metric, pbuf, sizeof(pbuf));
|
|
sem = pmwebapi_semantics_str(metric, sbuf, sizeof(sbuf));
|
|
@@ -1000,16 +1005,24 @@ redis_series_metadata(context_t *context
|
|
cmd = redis_param_sha(cmd, metric->names[i].hash);
|
|
redisSlotsRequest(slots, SADD, key, cmd, redis_series_source_callback, arg);
|
|
|
|
+check_instances:
|
|
if (metric->desc.indom == PM_INDOM_NULL || metric->u.vlist == NULL) {
|
|
- redis_series_labelset(slots, metric, NULL, baton);
|
|
+ if (metric->cached == 0) {
|
|
+ redis_series_labelset(slots, metric, NULL, baton);
|
|
+ metric->cached = 1;
|
|
+ }
|
|
} else {
|
|
for (i = 0; i < metric->u.vlist->listcount; i++) {
|
|
value = &metric->u.vlist->value[i];
|
|
if ((instance = dictFetchValue(metric->indom->insts, &value->inst)) == NULL)
|
|
continue;
|
|
- redis_series_instance(slots, metric, instance, baton);
|
|
- redis_series_labelset(slots, metric, instance, baton);
|
|
+ if (instance->cached == 0 || metric->cached == 0) {
|
|
+ redis_series_instance(slots, metric, instance, baton);
|
|
+ redis_series_labelset(slots, metric, instance, baton);
|
|
+ }
|
|
+ instance->cached = 1;
|
|
}
|
|
+ metric->cached = 1;
|
|
}
|
|
}
|
|
|
|
@@ -1210,7 +1223,6 @@ redis_series_stream(redisSlots *slots, s
|
|
|
|
redisSlotsRequest(slots, XADD, key, cmd, redis_series_stream_callback, baton);
|
|
|
|
-
|
|
key = sdscatfmt(sdsempty(), "pcp:values:series:%s", hash);
|
|
cmd = redis_command(3); /* EXPIRE key timer */
|
|
cmd = redis_param_str(cmd, EXPIRE, EXPIRE_LEN);
|
|
@@ -1228,9 +1240,6 @@ redis_series_streamed(sds stamp, metric_
|
|
char hashbuf[42];
|
|
int i;
|
|
|
|
- if (metric->updated == 0)
|
|
- return;
|
|
-
|
|
for (i = 0; i < metric->numnames; i++) {
|
|
pmwebapi_hash_str(metric->names[i].hash, hashbuf, sizeof(hashbuf));
|
|
redis_series_stream(slots, stamp, metric, hashbuf, arg);
|
|
@@ -1545,7 +1554,10 @@ redis_load_slots_callback(
|
|
redisSlots *slots = baton->slots;
|
|
|
|
seriesBatonCheckMagic(baton, MAGIC_SLOTS, "redis_load_slots_callback");
|
|
+
|
|
+ slots->setup = 1; /* we've received initial response from Redis */
|
|
slots->refresh = 0; /* we're processing CLUSTER SLOTS command now */
|
|
+
|
|
/* no cluster redirection checking is needed for this callback */
|
|
sdsfree(cmd);
|
|
|
|
@@ -1832,12 +1844,47 @@ pmDiscoverSetup(pmDiscoverModule *module
|
|
const char fallback[] = "/var/log/pcp";
|
|
const char *paths[] = { "pmlogger", "pmmgr" };
|
|
const char *logdir = pmGetOptionalConfig("PCP_LOG_DIR");
|
|
+ struct dict *config;
|
|
+ unsigned int domain, serial;
|
|
+ pmInDom indom;
|
|
char path[MAXPATHLEN];
|
|
char sep = pmPathSeparator();
|
|
- int i, sts, count = 0;
|
|
+ sds option, *ids;
|
|
+ int i, sts, nids, count = 0;
|
|
|
|
if (data == NULL)
|
|
return -ENOMEM;
|
|
+ config = data->config;
|
|
+
|
|
+ /* double-check that we are supposed to be in here */
|
|
+ if ((option = pmIniFileLookup(config, "discover", "enabled"))) {
|
|
+ if (strcasecmp(option, "false") == 0)
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* prepare for optional metric and indom exclusion */
|
|
+ if ((option = pmIniFileLookup(config, "discover", "exclude.metrics"))) {
|
|
+ if ((data->pmids = dictCreate(&intKeyDictCallBacks, NULL)) == NULL)
|
|
+ return -ENOMEM;
|
|
+ /* parse regular expression string for matching on metric names */
|
|
+ regcomp(&data->exclude_names, option, REG_EXTENDED|REG_NOSUB);
|
|
+ }
|
|
+ if ((option = pmIniFileLookup(config, "discover", "exclude.indoms"))) {
|
|
+ if ((data->indoms = dictCreate(&intKeyDictCallBacks, NULL)) == NULL)
|
|
+ return -ENOMEM;
|
|
+ /* parse comma-separated indoms in 'option', convert to pmInDom */
|
|
+ if ((ids = sdssplitlen(option, sdslen(option), ",", 1, &nids))) {
|
|
+ data->exclude_indoms = nids;
|
|
+ for (i = 0; i < nids; i++) {
|
|
+ if (sscanf(ids[i], "%u.%u", &domain, &serial) == 2) {
|
|
+ indom = pmInDom_build(domain, serial);
|
|
+ dictAdd(data->indoms, &indom, NULL);
|
|
+ }
|
|
+ sdsfree(ids[i]);
|
|
+ }
|
|
+ free(ids);
|
|
+ }
|
|
+ }
|
|
|
|
/* create global EVAL hashes and string map caches */
|
|
redisGlobalsInit(data->config);
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/schema.h pcp-5.0.2/src/libpcp_web/src/schema.h
|
|
--- pcp-5.0.2.orig/src/libpcp_web/src/schema.h 2019-10-11 17:16:29.000000000 +1100
|
|
+++ pcp-5.0.2/src/libpcp_web/src/schema.h 2020-02-03 13:23:15.266762879 +1100
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2017-2018 Red Hat.
|
|
+ * Copyright (c) 2017-2020 Red Hat.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published
|
|
@@ -51,6 +51,10 @@
|
|
#define HSET_LEN (sizeof(HSET)-1)
|
|
#define HVALS "HVALS"
|
|
#define HVALS_LEN (sizeof(HVALS)-1)
|
|
+#define INFO "INFO"
|
|
+#define INFO_LEN (sizeof(INFO)-1)
|
|
+#define PING "PING"
|
|
+#define PING_LEN (sizeof(PING)-1)
|
|
#define PUBLISH "PUBLISH"
|
|
#define PUBLISH_LEN (sizeof(PUBLISH)-1)
|
|
#define SADD "SADD"
|
|
@@ -63,6 +67,8 @@
|
|
#define XADD_LEN (sizeof(XADD)-1)
|
|
#define XRANGE "XRANGE"
|
|
#define XRANGE_LEN (sizeof(XRANGE)-1)
|
|
+#define XREVRANGE "XREVRANGE"
|
|
+#define XREVRANGE_LEN (sizeof(XREVRANGE)-1)
|
|
|
|
/* create a Redis protocol command (e.g. XADD, SMEMBER) */
|
|
static inline sds
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/slots.c pcp-5.0.2/src/libpcp_web/src/slots.c
|
|
--- pcp-5.0.2.orig/src/libpcp_web/src/slots.c 2019-10-11 17:16:29.000000000 +1100
|
|
+++ pcp-5.0.2/src/libpcp_web/src/slots.c 2020-02-03 13:23:15.266762879 +1100
|
|
@@ -356,6 +356,21 @@ redisSlotsRequest(redisSlots *slots, con
|
|
|
|
if (UNLIKELY(pmDebugOptions.desperate))
|
|
fputs(cmd, stderr);
|
|
+ if (UNLIKELY(!key && !slots->setup)) {
|
|
+ /*
|
|
+ * First request must be CLUSTER, PING, or similar - must
|
|
+ * not allow regular requests until these have completed.
|
|
+ * This is because the low layers accumulate async requests
|
|
+ * until connection establishment, which might not happen.
|
|
+ * Over time this becomes a memory leak - if we do not ever
|
|
+ * establish an initial connection).
|
|
+ */
|
|
+ if (strcmp(topic, CLUSTER) != 0 &&
|
|
+ strcmp(topic, PING) != 0 && strcmp(topic, INFO) != 0) {
|
|
+ sdsfree(cmd);
|
|
+ return -ENOTCONN;
|
|
+ }
|
|
+ }
|
|
|
|
sts = redisAsyncFormattedCommand(context, callback, cmd, arg);
|
|
if (key)
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/slots.h pcp-5.0.2/src/libpcp_web/src/slots.h
|
|
--- pcp-5.0.2.orig/src/libpcp_web/src/slots.h 2019-04-08 09:11:00.000000000 +1000
|
|
+++ pcp-5.0.2/src/libpcp_web/src/slots.h 2020-02-03 13:23:15.266762879 +1100
|
|
@@ -44,10 +44,11 @@ typedef struct redisSlotRange {
|
|
typedef struct redisSlots {
|
|
unsigned int counter;
|
|
unsigned int nslots;
|
|
+ unsigned int setup; /* slots info all successfully setup */
|
|
+ unsigned int refresh; /* do slot refresh whenever possible */
|
|
redisSlotRange *slots; /* all instances; e.g. CLUSTER SLOTS */
|
|
redisMap *keymap; /* map command names to key position */
|
|
dict *contexts; /* async contexts access by hostspec */
|
|
- unsigned int refresh; /* do slot refresh whenever possible */
|
|
void *events;
|
|
} redisSlots;
|
|
|
|
diff -Naurp pcp-5.0.2.orig/src/libpcp_web/src/util.c pcp-5.0.2/src/libpcp_web/src/util.c
|
|
--- pcp-5.0.2.orig/src/libpcp_web/src/util.c 2019-12-10 17:39:49.000000000 +1100
|
|
+++ pcp-5.0.2/src/libpcp_web/src/util.c 2020-02-03 13:23:15.266762879 +1100
|
|
@@ -1,5 +1,5 @@
|
|
/*
|
|
- * Copyright (c) 2017-2019 Red Hat.
|
|
+ * Copyright (c) 2017-2020 Red Hat.
|
|
*
|
|
* This library is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published
|
|
@@ -535,6 +535,8 @@ pmwebapi_metric_hash(metric_t *metric)
|
|
sdsclear(identifier);
|
|
}
|
|
sdsfree(identifier);
|
|
+
|
|
+ metric->cached = 0;
|
|
}
|
|
|
|
void
|
|
@@ -574,6 +576,8 @@ pmwebapi_instance_hash(indom_t *ip, inst
|
|
SHA1Update(&shactx, (unsigned char *)identifier, sdslen(identifier));
|
|
SHA1Final(instance->name.hash, &shactx);
|
|
sdsfree(identifier);
|
|
+
|
|
+ instance->cached = 0;
|
|
}
|
|
|
|
sds
|
|
@@ -1046,7 +1050,6 @@ pmwebapi_add_instance(struct indom *indo
|
|
instance->name.sds = sdscatlen(instance->name.sds, name, length);
|
|
pmwebapi_string_hash(instance->name.id, name, length);
|
|
pmwebapi_instance_hash(indom, instance);
|
|
- instance->cached = 0;
|
|
}
|
|
return instance;
|
|
}
|
|
@@ -1202,12 +1205,14 @@ struct metric *
|
|
pmwebapi_add_metric(context_t *cp, const sds base, pmDesc *desc, int numnames, char **names)
|
|
{
|
|
struct metric *metric;
|
|
- sds name = sdsempty();
|
|
+ sds name;
|
|
int i;
|
|
|
|
/* search for a match on any of the given names */
|
|
if (base && (metric = dictFetchValue(cp->metrics, base)) != NULL)
|
|
return metric;
|
|
+
|
|
+ name = sdsempty();
|
|
for (i = 0; i < numnames; i++) {
|
|
sdsclear(name);
|
|
name = sdscat(name, names[i]);
|
|
@@ -1217,6 +1222,7 @@ pmwebapi_add_metric(context_t *cp, const
|
|
}
|
|
}
|
|
sdsfree(name);
|
|
+
|
|
return pmwebapi_new_metric(cp, base, desc, numnames, names);
|
|
}
|
|
|
|
@@ -1230,21 +1236,24 @@ pmwebapi_new_pmid(context_t *cp, const s
|
|
int sts, numnames;
|
|
|
|
if ((sts = pmUseContext(cp->context)) < 0) {
|
|
- fprintf(stderr, "failed to use context for PMID %s: %s",
|
|
+ fprintf(stderr, "%s: failed to use context for PMID %s: %s\n",
|
|
+ "pmwebapi_new_pmid",
|
|
pmIDStr_r(pmid, buffer, sizeof(buffer)),
|
|
pmErrStr_r(sts, errmsg, sizeof(errmsg)));
|
|
} else if ((sts = pmLookupDesc(pmid, &desc)) < 0) {
|
|
if (sts == PM_ERR_IPC)
|
|
cp->setup = 0;
|
|
if (pmDebugOptions.series)
|
|
- fprintf(stderr, "failed to lookup metric %s descriptor: %s",
|
|
+ fprintf(stderr, "%s: failed to lookup metric %s descriptor: %s\n",
|
|
+ "pmwebapi_new_pmid",
|
|
pmIDStr_r(pmid, buffer, sizeof(buffer)),
|
|
pmErrStr_r(sts, errmsg, sizeof(errmsg)));
|
|
} else if ((numnames = sts = pmNameAll(pmid, &names)) < 0) {
|
|
if (sts == PM_ERR_IPC)
|
|
cp->setup = 0;
|
|
if (pmDebugOptions.series)
|
|
- fprintf(stderr, "failed to lookup metric %s names: %s",
|
|
+ fprintf(stderr, "%s: failed to lookup metric %s names: %s\n",
|
|
+ "pmwebapi_new_pmid",
|
|
pmIDStr_r(pmid, buffer, sizeof(buffer)),
|
|
pmErrStr_r(sts, errmsg, sizeof(errmsg)));
|
|
} else {
|
|
diff -Naurp pcp-5.0.2.orig/src/pmproxy/pmproxy.conf pcp-5.0.2/src/pmproxy/pmproxy.conf
|
|
--- pcp-5.0.2.orig/src/pmproxy/pmproxy.conf 2019-08-09 15:50:17.000000000 +1000
|
|
+++ pcp-5.0.2/src/pmproxy/pmproxy.conf 2020-02-03 13:36:03.948721355 +1100
|
|
@@ -43,6 +43,11 @@ secure.enabled = true
|
|
# propogate archives from pmlogger(1) into Redis querying
|
|
enabled = true
|
|
|
|
+# metrics name regex to skip during discovery (eg due to high volume)
|
|
+exclude.metrics = proc.*
|
|
+
|
|
+# comma-separated list of instance domains to skip during discovery
|
|
+exclude.indoms = 3.9,79.7
|
|
|
|
#####################################################################
|
|
## settings for fast, scalable time series quering via Redis
|
|
diff -Naurp pcp-5.0.2.orig/src/pmproxy/src/redis.c pcp-5.0.2/src/pmproxy/src/redis.c
|
|
--- pcp-5.0.2.orig/src/pmproxy/src/redis.c 2019-12-02 16:39:33.000000000 +1100
|
|
+++ pcp-5.0.2/src/pmproxy/src/redis.c 2020-02-03 13:36:13.585620539 +1100
|
|
@@ -145,11 +145,11 @@ setup_redis_module(struct proxy *proxy)
|
|
proxy->slots = redisSlotsConnect(proxy->config,
|
|
flags, proxylog, on_redis_connected,
|
|
proxy, proxy->events, proxy);
|
|
- if (archive_discovery)
|
|
+ if (archive_discovery && series_queries)
|
|
pmDiscoverSetSlots(&redis_discover.module, proxy->slots);
|
|
}
|
|
|
|
- if (archive_discovery) {
|
|
+ if (archive_discovery && series_queries) {
|
|
pmDiscoverSetEventLoop(&redis_discover.module, proxy->events);
|
|
pmDiscoverSetConfiguration(&redis_discover.module, proxy->config);
|
|
pmDiscoverSetMetricRegistry(&redis_discover.module, metric_registry);
|