blob: f700f888c6a4a25867c2bba9bcbc852bb01b2e4a [file] [log] [blame]
package backup
import (
"fmt"
"github.com/greenplum-db/gp-common-go-libs/dbconn"
"github.com/greenplum-db/gp-common-go-libs/gplog"
"github.com/greenplum-db/gpbackup/toc"
)
func GetAOIncrementalMetadata(connectionPool *dbconn.DBConn) map[string]toc.AOEntry {
gplog.Verbose("Querying table row mod counts")
var modCounts = getAllModCounts(connectionPool)
gplog.Verbose("Querying last DDL modification timestamp for tables")
var lastDDLTimestamps = getLastDDLTimestamps(connectionPool)
aoTableEntries := make(map[string]toc.AOEntry)
for aoTableFQN := range modCounts {
aoTableEntries[aoTableFQN] = toc.AOEntry{
Modcount: modCounts[aoTableFQN],
LastDDLTimestamp: lastDDLTimestamps[aoTableFQN],
}
}
return aoTableEntries
}
func getAllModCounts(connectionPool *dbconn.DBConn) map[string]int64 {
var segTableFQNs = getAOSegTableFQNs(connectionPool)
modCounts := make(map[string]int64)
for aoTableFQN, segTableFQN := range segTableFQNs {
modCounts[aoTableFQN] = getModCount(connectionPool, segTableFQN)
}
return modCounts
}
func getAOSegTableFQNs(connectionPool *dbconn.DBConn) map[string]string {
atLeast7Query := fmt.Sprintf(`
SELECT seg.aotablefqn,
'pg_aoseg.' || quote_ident(aoseg_c.relname) AS aosegtablefqn
FROM pg_class aoseg_c
JOIN (SELECT pg_ao.relid AS aooid,
pg_ao.segrelid,
aotables.aotablefqn
FROM pg_appendonly pg_ao
JOIN (SELECT c.oid,
quote_ident(n.nspname) || '.' || quote_ident(c.relname) AS aotablefqn
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_am a ON c.relam = a.oid
WHERE a.amname in ('ao_row', 'ao_column')
AND %s
) aotables ON pg_ao.relid = aotables.oid
) seg ON aoseg_c.oid = seg.segrelid`, relationAndSchemaFilterClause())
query := atLeast7Query
results := make([]struct {
AOTableFQN string
AOSegTableFQN string
}, 0)
err := connectionPool.Select(&results, query)
gplog.FatalOnError(err)
resultMap := make(map[string]string)
for _, result := range results {
resultMap[result.AOTableFQN] = result.AOSegTableFQN
}
return resultMap
}
func getModCount(connectionPool *dbconn.DBConn, aosegtablefqn string) int64 {
// In GPDB 7+, the coordinator no longer stores AO segment data so we must
// query the modcount from the segments. Unfortunately, this does give a
// false positive if a VACUUM FULL compaction happens on the AO table.
atLeast7Query := fmt.Sprintf(`SELECT COALESCE(pg_catalog.sum(modcount), 0) AS modcount FROM gp_dist_random('%s')`,
aosegtablefqn)
query := atLeast7Query
var results []struct {
Modcount int64
}
err := connectionPool.Select(&results, query)
gplog.FatalOnError(err)
return results[0].Modcount
}
func getLastDDLTimestamps(connectionPool *dbconn.DBConn) map[string]string {
atLeast7Query := fmt.Sprintf(`
SELECT quote_ident(aoschema) || '.' || quote_ident(aorelname) as aotablefqn,
lastddltimestamp
FROM ( SELECT c.oid AS aooid,
n.nspname AS aoschema,
c.relname AS aorelname
FROM pg_class c
JOIN pg_namespace n ON c.relnamespace = n.oid
JOIN pg_am a ON c.relam = a.oid
WHERE a.amname in ('ao_row', 'ao_column')
AND %s
) aotables
JOIN ( SELECT lo.objid,
MAX(lo.statime) AS lastddltimestamp
FROM pg_stat_last_operation lo
WHERE lo.staactionname IN ('CREATE', 'ALTER', 'TRUNCATE')
GROUP BY lo.objid
) lastop
ON aotables.aooid = lastop.objid`, relationAndSchemaFilterClause())
query := atLeast7Query
var results []struct {
AOTableFQN string
LastDDLTimestamp string
}
err := connectionPool.Select(&results, query)
gplog.FatalOnError(err)
resultMap := make(map[string]string)
for _, result := range results {
resultMap[result.AOTableFQN] = result.LastDDLTimestamp
}
return resultMap
}