diff --git a/docker/docker-compose.install-template.yaml b/docker/docker-compose.install-template.yaml index b3d5c29b1bb..a0080ebb233 100644 --- a/docker/docker-compose.install-template.yaml +++ b/docker/docker-compose.install-template.yaml @@ -13,6 +13,7 @@ services: - ../install_template/config.yaml:/app/config.yaml:ro - ../install_template/main.mjs:/app/main.mjs:ro - ../install_template/deploy.mjs:/app/deploy.mjs:ro + - ../install_template/lib:/app/lib:ro - ../install_template/package-lock.json:/app/package-lock.json - ../install_template/package.json:/app/package.json - ../install_template/templates:/app/templates:ro diff --git a/install_template/config.yaml b/install_template/config.yaml index 7e64b4e2bfe..5739d6c9d9b 100644 --- a/install_template/config.yaml +++ b/install_template/config.yaml @@ -3,46 +3,46 @@ products: platforms: - name: CentOS 7 arch: x86_64 - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: RHEL 8 arch: ppc64le - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: AlmaLinux 8 or Rocky Linux 8 arch: x86_64 - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: RHEL 7 or OL 7 arch: x86_64 - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: RHEL 8 or OL 8 arch: x86_64 - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: Debian 10 arch: x86_64 - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: Debian 11 arch: x86_64 - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: Ubuntu 18.04 arch: x86_64 - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: Ubuntu 20.04 arch: x86_64 - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: Ubuntu 22.04 arch: x86_64 - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: SLES 12 arch: x86_64 - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: SLES 12 arch: ppc64le - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: SLES 15 arch: x86_64 - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: SLES 15 arch: ppc64le - supported versions: [42.5.1.2] + supported versions: [42.5.4.1] - name: Migration Toolkit platforms: - name: RHEL 8 or OL 8 @@ -400,9 +400,6 @@ products: - name: RHEL 8 arch: ppc64le supported versions: [41] - - name: Ubuntu 18.04 - arch: x86_64 - supported versions: [41] - name: Debian 10 arch: x86_64 supported versions: [41] @@ -447,9 +444,6 @@ products: - name: RHEL 8 arch: ppc64le supported versions: [4] - - name: Ubuntu 18.04 - arch: x86_64 - supported versions: [4] - name: Debian 10 arch: x86_64 supported versions: [4] @@ -494,9 +488,6 @@ products: - name: RHEL 8 arch: ppc64le supported versions: [2] - - name: Ubuntu 18.04 - arch: x86_64 - supported versions: [2] - name: Debian 10 arch: x86_64 supported versions: [2] @@ -638,9 +629,6 @@ products: - name: Ubuntu 18.04 arch: x86_64 supported versions: [3.2] - - name: Ubuntu 20.04 - arch: x86_64 - supported versions: [3.2] - name: Debian 11 arch: x86_64 supported versions: [3.2] @@ -735,9 +723,6 @@ products: - name: Ubuntu 18.04 arch: x86_64 supported versions: [9] - - name: Ubuntu 20.04 - arch: x86_64 - supported versions: [9] - name: SLES 12 arch: x86_64 supported versions: [9] diff --git a/install_template/deploy.mjs b/install_template/deploy.mjs index b00517661eb..b74c3310bec 100644 --- a/install_template/deploy.mjs +++ b/install_template/deploy.mjs @@ -3,7 +3,7 @@ import path from "path"; import { fileURLToPath } from "url"; import nunjucks from "nunjucks"; import yaml from "yaml"; -import isMatch from "lodash.ismatch"; +import loadProductConfig from "./lib/config.mjs"; nunjucks.configure("templates", { throwOnUndefined: true, autoescape: false }); @@ -19,16 +19,20 @@ const destPath = path.resolve(__dirname, args[0] || "../product_docs/docs"); * @returns void */ const run = async () => { - const config = yaml.parse( - await fs.readFile(path.resolve(__dirname, "config.yaml"), "utf8"), - ); + const products = await loadProductConfig(path.resolve(__dirname, "config.yaml")); let results = []; - for (const product of config.products) { - for (const platform of product.platforms) { - for (const version of platform["supported versions"]) { - results.push(await moveDoc(product, platform, version)); + for (let product of products) { + for (let prodVersion in product.cpuArchitecturesForVersion) { + const prodVersionDetail = product.cpuArchitecturesForVersion[prodVersion]; + results.push(await moveIndex({product, prodVersion})); + for (let arch in prodVersionDetail) { + const osArchDetail = prodVersionDetail[arch]; + results.push(await moveIndex({product, prodVersion, arch})); + for (let os of osArchDetail) { + results.push(await moveDoc(product, {name: os.name, arch}, prodVersion)); + } } } } @@ -40,138 +44,71 @@ const run = async () => { console.log( `${ results.filter((r) => r.note && /^Skipping/.test(r.note)).length - } files skipped`, + } files skipped +${ results.filter((r) => !!r.success).length} files deployed`, ); return; }; /** - * Composes the code needed to copy a document for a product/platform/version combination. - * @param product The product name we are generating a template for - * @param platform The platform and architecture we are generating docs for (e.g. { name: Centos 7, arch: x86_64 }) - * @param version The version of the product to generate docs for + * Copies a generated index document for a product/(optional)architecture/version combination. + * @param product The product name we are deploying docs for + * @param prodVersion The version of the product to deploy docs for + * @param arch The CPU architecture for a sub-index * @returns object {success: 'message', note: 'observation', warn: 'warning or error', context: {additional}} */ -const moveDoc = async (product, platform, version) => { - /* - console.log( - `Copying install guide for ${product.name} ${version} on ${platform.name} ${platform.arch}`, - ); - */ - - const context = generateContext(product, platform, version); - - const product_stub = formatStringForFile(context.product.name); - +const moveIndex = async ({product, prodVersion, arch}) => { + const product_stub = formatStringForFile(product.name); const srcFilename = [ product_stub, - context.product.version, - formatStringForFile(context.platform.name), - context.platform.arch, - ].join("_") + ".mdx"; + prodVersion, + arch, + "index" + ].filter((p) => !!p).join("_") + ".mdx"; const srcFilepath = path.resolve(__dirname, "renders", srcFilename); - const prefix = { - rhel_8_x86_64: "01", - other_linux8_x86_64: "02", - rhel_7_x86_64: "03", - centos_7_x86_64: "04", - sles_15_x86_64: "05", - sles_12_x86_64: "06", - "ubuntu_22.04_x86_64": "06b", - "ubuntu_20.04_x86_64": "07", - "ubuntu_18.04_x86_64": "07a", - debian_11_x86_64: "07b", - debian_10_x86_64: "08", - rhel_8_ppc64le: "09", - rhel_7_ppc64le: "10", - sles_15_ppc64le: "11", - sles_12_ppc64le: "12", - }; - - switch (product_stub) { - case "hadoop-foreign-data-wrapper": - case "mongodb-foreign-data-wrapper": - case "mysql-foreign-data-wrapper": - prefix["sles_12_x86"] = "07"; - prefix["sles_12_x86_64"] = "07"; - prefix["rhel_8_ppc64le"] = "13"; - prefix["rhel_7_ppc64le"] = "15"; - prefix["sles_12_ppc64le"] = "19"; - prefix["sles_15_ppc64le"] = "17"; - break; - case "edb-ocl-connector": - prefix["sles_15_x86_64"] = "03"; - prefix["sles_12_x86_64"] = "04"; - prefix["sles_15_ppc64le"] = "09"; - prefix["sles_12_ppc64le"] = "10"; - prefix["ubuntu_22.04_x86_64"] = "05"; - prefix["ubuntu_20.04_x86_64"] = "05a"; - prefix["ubuntu_18.04_x86_64"] = "05b"; - prefix["debian_11_x86_64"] = "06"; - prefix["debian_10_x86_64"] = "06a"; - prefix["debian_9_x86_64"] = "06b"; - break; - } + return await moveRender(srcFilepath); +}; - const expand_arch = { - ppcle: "ibm_power_ppc64le", - x86: "x86_amd64", - x86_64: "x86_amd64", - ppc64le: "ibm_power_ppc64le", - }; +/** + * Copies a generated document for a product/platform/version combination. + * @param product The product name we are deploying docs for + * @param platform The platform and architecture we are deploying docs for (e.g. { name: Centos 7, arch: x86_64 }) + * @param prodVersion The version of the product to deploy docs for + * @returns object {success: 'message', note: 'observation', warn: 'warning or error', context: {additional}} + */ +const moveDoc = async (product, platform, prodVersion) => { + const product_stub = formatStringForFile(product.name); - const plat = [ - context.platform.name.toLowerCase().replace(/ /g, "_"), - context.platform.arch, - ].join("_"); + const srcFilename = + [ + product_stub, + prodVersion, + formatStringForFile(platform.name), + platform.arch, + ].join("_") + ".mdx"; - const product_prefix = { - "failover-manager": "03", - "migration-toolkit": "05", - "hadoop-foreign-data-wrapper": "05", - "mongodb-foreign-data-wrapper": "04", - "mysql-foreign-data-wrapper": "04", - "edb-pgpool-ii": "01", - "edb-pgpool-ii-extensions": "pgpoolext", - postgis: "01a", - "edb-jdbc-connector": "04", - "edb-ocl-connector": "04", - "edb-odbc-connector": "03", - "edb-pgbouncer": "01", - }; + const srcFilepath = path.resolve(__dirname, "renders", srcFilename); - const fmtArchPath = (ctx) => expand_arch[ctx.platform.arch]; - const fmtArchFilename = (ctx) => ctx.platform.arch.replace(/_?64/g, ""); + return await moveRender(srcFilepath); +}; +/** + * Copies a document at a given source path + * @param srcFilepath The path to the generated mdx file + * @returns object {success: 'message', note: 'observation', warn: 'warning or error', context: {additional}} + */ +const moveRender = async (srcFilepath) => { const [srcContent, integralDeploymentPath] = await readSource(srcFilepath); - // prettier-ignore - const destFilename = integralDeploymentPath || match(context, - when({product: {name: "xdb", version: 99}, platform: {name: "MS-DOS 4.0"}}, - (ctx) => `xdb/99/installing/${fmtArchPath(ctx)}/xdb_centos7_${fmtArchFilename(ctx)}.mdx`), - ); - - function match(context, ...conditions) { - for (let test of conditions) { - const result = test(context); - if (result !== false && result !== null) return result; - } - return null; - } - - function when(pattern, resultFn) { - return (ctx) => isMatch(ctx, pattern) && resultFn(ctx); - } - - if (!destFilename) { - return { note: `Skipping (no mapping): ${srcFilename}`, context }; + if (!integralDeploymentPath) { + return { note: `Skipping (missing deployPath?): ${path.basename(srcFilepath)}`, }; } - const destFilepath = path.resolve(__dirname, destPath, destFilename); + const destFilepath = path.resolve(__dirname, destPath, integralDeploymentPath); try { await fs.mkdir(path.dirname(destFilepath), { recursive: true }); await fs.writeFile(destFilepath, srcContent, "utf8"); @@ -197,37 +134,6 @@ const formatStringForFile = (string) => { return string.toLowerCase().replace(/ /g, "-"); }; -/** - * Creates a filename based on the filenameParts passed in, and appends to to a base path - * @param basePath A file path formatted string which will be used as a prefix to the generated filename. e.g "products/product-name/" - * @param filenameParts An array of strings to combine into a template name. e.g. ["first-part", "second", "last-part"] - * @returns A file path which refers to the expected location of a nunjucks template, with each filename part seperated by an underscore. - * e.g. "products/product-name/first-part_second_last-part.njk" - */ -const constructTemplatePath = (basePath, filenameParts) => { - return path.join(basePath, filenameParts.join("_") + ".njk"); -}; - -/** - * Creates the context object used by nunjucks templates - * @param product The product to render docs for, from the config. - * @param platform The platform to render docs for, from the config. - * @param version The version of the product to render docs for - * @returns a context object. - */ -const generateContext = (product, platform, version) => { - return { - product: { - name: product.name, - version: version, - }, - platform: { - name: platform.name, - arch: platform.arch, - }, - }; -}; - /** * Reads the source mdx file, parse out the deployment path and filename from the MDX frontmatter * @param srcPath the path + name of the mdx file to read @@ -263,9 +169,10 @@ const readSource = async (srcPath) => { } for (let i = 0; i < redirects?.items?.length; ++i) { - redirects.items[i].value = redirects.items[i].value - .replace(/^\/?/, "/") - .replace(/\.mdx$/, ""); + if (/\.mdx$/.test(redirects.items[i].value)) + redirects.items[i].value = redirects.items[i].value + .replace(/^\/?/, "/") + .replace(/\.mdx$/, ""); } src = src.replace( @@ -275,7 +182,11 @@ const readSource = async (srcPath) => { return [src, deployPath]; } catch (e) { - console.log(srcPath, e); + if (e?.code === "ENOENT") + console.log("not found: " + e.path); + else + console.log(srcPath, e); + return [null, null]; } }; diff --git a/install_template/lib/config.mjs b/install_template/lib/config.mjs new file mode 100644 index 00000000000..867ca941a98 --- /dev/null +++ b/install_template/lib/config.mjs @@ -0,0 +1,94 @@ +import fs from "fs/promises"; +import { version } from "os"; +import yaml from "yaml"; + +const osFamily = (osName) => { + const mappings = [ + [/RHEL \d+/, "RHEL"], + [/RHEL \d+ or OL \d+/, "RHEL"], + [/Oracle Linux (OL) \d+/, "RHEL"], + [/AlmaLinux \d+ or Rocky Linux \d+/, "RHEL"], + [/Rocky Linux \d+/, "RHEL"], + [/AlmaLinux \d+/, "RHEL"], + [/CentOS \d+/, "RHEL"], + [/SLES \d+/, "SLES"], + [/Ubuntu [\d\.]+/, "Debian"], + [/Debian [\d\.]+/, "Debian"], + ]; + + for (let mapping of mappings) { + if (mapping[0].test(osName)) + return mapping[1]; + } + return ""; +}; + +const osShortname = (osName) => { + const mappings = [ + [/RHEL \d+/, "RHEL"], + [/RHEL \d+ or OL \d+/, "RHEL"], + [/Oracle Linux (OL) \d+/, "OL"], + [/AlmaLinux \d+ or Rocky Linux \d+/, "Alma/Rocky"], + [/Rocky Linux \d+/, "Rocky"], + [/AlmaLinux \d+/, "Alma"], + [/CentOS \d+/, "CentOS"], + [/SLES \d+/, "SLES"], + [/Ubuntu [\d\.]+/, "Ubuntu"], + [/Debian [\d\.]+/, "Debian"], + ]; + + for (let mapping of mappings) { + if (mapping[0].test(osName)) + return mapping[1]; + } + return ""; +}; + +const osVersion = (osName) => { + return osName.match(/(?[\d\.]+)\s*$/)?.groups?.version || ''; +}; + +function hasOS(osShortname, osVersion) { + return this.some((os) => os.shortname === osShortname && (!osVersion || osVersion === os.version)); +} + +function hasFamily(osFamily) { + return this.some((os) => os.family === osFamily); +} + +function filterFamily(osFamily) { + return this.filter((os) => os.family === osFamily).sort((a,b) => b.version - a.version); +} + +function filterOS(osShortname, osVersion) { + return this.filter((os) => os.shortname === osShortname && (!osVersion || osVersion === os.version)).sort((a,b) => b.version - a.version); +} + +const loadProductConfig = async (configFile) => { + const config = yaml.parse(await fs.readFile(configFile, "utf8")); + + let products = []; + + for (let product of config.products) { + let cpuArchitecturesForVersion = product.platforms.reduce((p,c) => { + for (let prodVersion of c["supported versions"]) { + const prodVersionDetail = p[prodVersion] = p[prodVersion] || {}; + const osArchDetail = prodVersionDetail[c.arch] = prodVersionDetail[c.arch] || []; + const family = osFamily(c.name); + const shortname = osShortname(c.name); + const version = osVersion(c.name); + osArchDetail.push({name: c.name, family, shortname, version}); + osArchDetail.hasOS = hasOS; + osArchDetail.hasFamily = hasFamily; + osArchDetail.filterOS = filterOS; + osArchDetail.filterFamily = filterFamily; + } + return p; + }, {}); + + products.push({name: product.name, cpuArchitecturesForVersion}); + } + return products; +}; + +export default loadProductConfig; diff --git a/install_template/main.mjs b/install_template/main.mjs index c9a57560f83..1c0548f985a 100644 --- a/install_template/main.mjs +++ b/install_template/main.mjs @@ -1,30 +1,152 @@ import fs from "fs/promises"; import { existsSync as fileExists } from "fs"; import path from "path"; +import { fileURLToPath } from "url"; import nunjucks from "nunjucks"; import prettier from "prettier"; -import yaml from "yaml"; +import loadProductConfig from "./lib/config.mjs"; -nunjucks.configure("templates", { throwOnUndefined: true, autoescape: false }); +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +nunjucks.configure(path.join(__dirname, "templates"), { throwOnUndefined: true, autoescape: false }); /** * Loop through the config.yaml file and generate docs for every product/platform/supported version combination found. * @returns void */ const run = async () => { - const config = yaml.parse(await fs.readFile("config.yaml", "utf8")); - - config.products.forEach((product) => { - product.platforms.forEach((platform) => { - platform["supported versions"].forEach((version) => { - renderDoc(product, platform, version); - }); - }); - }); + const products = await loadProductConfig(path.resolve(__dirname, "config.yaml")); + + for (let product of products) { + for (let prodVersion in product.cpuArchitecturesForVersion) { + const prodVersionDetail = product.cpuArchitecturesForVersion[prodVersion]; + renderProdIndex(product, prodVersion, prodVersionDetail); + for (let arch in prodVersionDetail) { + const osArchDetail = prodVersionDetail[arch]; + renderArchIndex(product, prodVersion, arch, osArchDetail); + for (let os of osArchDetail) { + renderDoc(product, {name: os.name, arch}, prodVersion); + } + } + } + } return; }; + +const transientLog = (message) => { + if (process.stdout.clearLine) { + process.stdout.clearLine(); + process.stdout.write("\r" + message); + } else { + console.log(message); + } +}; + + +const normalizeOSName = (name, version, display_name) => { + if (version) return name + " " + version; + + const platformTransformations = [ + [/Rocky\/Alma Linux 8/, "AlmaLinux 8 or Rocky Linux 8"], + [/ LTS .+/, ""], + [/SUSE Linux Enterprise Server/, "SLES"], + ]; + + if (display_name) + return platformTransformations.reduce( + (result, trans) => result.replace(trans[0], trans[1]), + display_name, + ); + + return name; +}; + +/** + * Composes the code needed to render an index page for a product, given just a product, a product + version, or a product + version + OS list. + * @param product The product we are generating an index for + * @param version The version of the product to generate docs for + * @param osArchitectures Collection of supported CPU architectures for Linux installs + * @returns void + */ +const renderProdIndex = (product, version, osArchitectures) => { + console.log( + `Starting index render for ${product.name}` + ); + + const template = findTemplate( + product.name, + version, + null, + null, + "index", + ); + + if (template === false) { + return; + } + + console.log(` using template "${template}"`); + + const context = { + product: { name: product.name, version: version }, + osArchitectures, + outputType: "index", + }; + + try { + writeDoc(template, context); + } catch (error) { + console.error("[ERROR] An exception occurred. Details below:"); + console.error(error); + process.exit(1); + } +}; + +/** + * Composes the code needed to render an index page for a product, given just a product, a product + version, or a product + version + OS list. + * @param product The product we are generating an index for + * @param version The version of the product to generate docs for + * @param osArchitecture Specific CPU architecture for linux installs + * @param osVersions OS versions supported for this architecture + * @returns void + */ +const renderArchIndex = (product, version, osArchitecture, osVersions) => { + console.log( + `Starting index render for ${product.name} on Linux ${ osArchitecture }`, + ); + + const template = findTemplate( + product.name, + version, + osArchitecture, + null, + "index", + ); + + if (template === false) { + return; + } + + console.log(` using template "${template}"`); + + const context = { + product: { name: product.name, version: version }, + arch: osArchitecture, + osVersions, + outputType: "index", + }; + + try { + writeDoc(template, context); + } catch (error) { + console.error("[ERROR] An exception occurred. Details below:"); + console.error(error); + process.exit(1); + } +}; + /** * Composes the code needed to render a single installation docuement for a product/platform/version combination. * @param product The product name we are generating a template for @@ -74,51 +196,35 @@ const findTemplate = ( productVersion, platformName, platformArch, + suffix, ) => { const basePath = "products/" + formatStringForFile(productName); const formattedPlatform = formatStringForFile(platformName); - // Check if a file exists for the specific product version, platform, and architecture - const fullFilename = constructTemplatePath(basePath, [ - `v${productVersion}`, - formattedPlatform, - platformArch, - ]); - if (fileExists("templates/" + fullFilename)) { - return fullFilename; - } + const possibilities = [ + // Check if a file exists for the specific product version, platform, and architecture + platformArch && constructTemplatePath(basePath, [ + `v${productVersion}`, + formattedPlatform, + platformArch, + suffix, + ]), + // Check if a file exists for the specific product version and platform + constructTemplatePath(basePath, [`v${productVersion}`, formattedPlatform, suffix]), + // check if a file exists for a specific platform and architecture + platformArch && constructTemplatePath(basePath, [formattedPlatform, platformArch, suffix]), + // check if a file exists for a specific platform + constructTemplatePath(basePath, [formattedPlatform, suffix]), + ].filter((p) => !!p); - // Check if a file exists for the specific product version and platform - const versionPlatformFilename = constructTemplatePath(basePath, [ - `v${productVersion}`, - formattedPlatform, - ]); - if (fileExists("templates/" + versionPlatformFilename)) { - return versionPlatformFilename; + for (let templateFilename of possibilities) { + if (fileExists(path.join(__dirname, "templates", templateFilename))) return templateFilename; } - // check if a file exists for a specific platform and architecture - const platformArchFilename = constructTemplatePath(basePath, [ - formattedPlatform, - platformArch, - ]); - if (fileExists("templates/" + platformArchFilename)) { - return platformArchFilename; - } - - // check if a file exists for a specific platform - const platformFilename = constructTemplatePath(basePath, [formattedPlatform]); - if (fileExists("templates/" + platformFilename)) { - return platformFilename; - } - - console.error( + console.log( `[ERROR] no template could be found\n` + - " Please add one of the following files:\n" + - ` ${fullFilename}\n` + - ` ${versionPlatformFilename}\n` + - ` ${platformArchFilename}\n` + - ` ${platformFilename}\n`, + " Please add one of the following files:\n " + + possibilities.join("\n "), ); return false; @@ -131,7 +237,7 @@ const findTemplate = ( * @returns a string formatted for file names */ const formatStringForFile = (string) => { - return string.toLowerCase().replace(/ /g, "-"); + return string?.toLowerCase().replace(/[ /]/g, "-"); }; /** @@ -142,7 +248,7 @@ const formatStringForFile = (string) => { * e.g. "products/product-name/first-part_second_last-part.njk" */ const constructTemplatePath = (basePath, filenameParts) => { - return path.join(basePath, filenameParts.join("_") + ".njk"); + return path.join(basePath, filenameParts.filter(p => p != null && p.length).join("_") + ".njk"); }; /** @@ -171,6 +277,7 @@ const generateContext = (product, platform, version) => { * @param context An object passed into the nunjucks template which will be used to render some variable content. */ const writeDoc = (template, context) => { + context.leafTemplatePath = template; const render = prettier.format(nunjucks.render(template, context), { parser: "mdx", }); @@ -178,13 +285,14 @@ const writeDoc = (template, context) => { [ formatStringForFile(context.product.name), context.product.version, - formatStringForFile(context.platform.name), - context.platform.arch, - ].join("_") + ".mdx"; + formatStringForFile(context.platform?.name), + context.platform?.arch || context.arch, + context.outputType, + ].filter(p => p != null && p.length).join("_") + ".mdx"; console.log(` writing ${filename}`); - fs.writeFile(`renders/${filename}`, render); + fs.writeFile(path.join(__dirname, "renders", filename), render); }; run(); diff --git a/install_template/package-lock.json b/install_template/package-lock.json index ab3ade601cc..0cae709360b 100644 --- a/install_template/package-lock.json +++ b/install_template/package-lock.json @@ -11,8 +11,8 @@ "dependencies": { "lodash.ismatch": "^4.4.0", "nunjucks": "^3.2.3", - "prettier": "^2.4.0", - "yaml": "^2.1.3" + "prettier": "^2.8.7", + "yaml": "^2.2.1" } }, "node_modules/a-sync-waterfall": { @@ -63,20 +63,23 @@ } }, "node_modules/prettier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz", - "integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==", + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", "bin": { "prettier": "bin-prettier.js" }, "engines": { "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/yaml": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz", - "integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", "engines": { "node": ">= 14" } @@ -114,14 +117,14 @@ } }, "prettier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.0.tgz", - "integrity": "sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==" + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==" }, "yaml": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz", - "integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==" + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", + "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==" } } } diff --git a/install_template/package.json b/install_template/package.json index e4a68964649..ba9d6baa87f 100644 --- a/install_template/package.json +++ b/install_template/package.json @@ -12,7 +12,7 @@ "dependencies": { "lodash.ismatch": "^4.4.0", "nunjucks": "^3.2.3", - "prettier": "^2.4.0", - "yaml": "^2.1.3" + "prettier": "^2.8.7", + "yaml": "^2.2.1" } } diff --git a/install_template/templates/platformBase/index.njk b/install_template/templates/platformBase/index.njk new file mode 100644 index 00000000000..9d7220a5a20 --- /dev/null +++ b/install_template/templates/platformBase/index.njk @@ -0,0 +1,86 @@ +--- +{% block title %} +navTitle: Installing +title: Installing {{ product.name }} on Linux +{% endblock title %} +# This topic is generated from templates. If you have feedback on it, instead of +# editing the page and creating a pull request, please enter a GitHub issue and +# the documentation team will update the templates accordingly. +# Leaf template: {{ leafTemplatePath }} +{% block frontmatter %} +deployPath: {{productShortname}}/{{ product.version }}/installing/index.mdx +{% endblock frontmatter %} +navigation: +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +{% endblock navigation %} +--- + +Select a link to access the applicable installation instructions: + +{% macro archInstall(name, path, renderOSes) %} +{% if osArchitectures[path] %} +## Linux [{{name}}](linux_{{path}}) + +{% if osArchitectures[path].hasFamily("RHEL") %} +### Red Hat Enterprise Linux (RHEL) and derivatives + +{% if osArchitectures[path].hasOS("RHEL") and renderOSes.includes("RHEL")%} +{% set comma = joiner() %} +- {% for os in osArchitectures[path].filterOS("RHEL") %}{{comma()}} [RHEL {{os.version}}](linux_{{path}}/{{productShortname}}_rhel_{{os.version}}){% endfor %} +{% endif %} +{% if osArchitectures[path].hasOS("RHEL") and renderOSes.includes("OL") %} +{% set comma = joiner() %} +- {% for os in osArchitectures[path].filterOS("RHEL") %}{{comma()}} [Oracle Linux (OL) {{os.version}}](linux_{{path}}/{{productShortname}}_rhel_{{os.version}}){% endfor %} +{% endif %} +{% if osArchitectures[path].hasOS("Alma/Rocky") and renderOSes.includes("Rocky") %} +{% set comma = joiner() %} +- {% for os in osArchitectures[path].filterOS("Alma/Rocky") %}{{comma()}} [Rocky Linux {{os.version}}](linux_{{path}}/{{productShortname}}_other_linux_{{os.version}}){% endfor %} +{% endif %} +{% if osArchitectures[path].hasOS("Alma/Rocky") and renderOSes.includes("Alma") %} +{% set comma = joiner() %} +- {% for os in osArchitectures[path].filterOS("Alma/Rocky") %}{{comma()}} [AlmaLinux {{os.version}}](linux_{{path}}/{{productShortname}}_other_linux_{{os.version}}){% endfor %} +{% endif %} +{% if osArchitectures[path].hasOS("CentOS") and renderOSes.includes("CentOS") %} +{% set comma = joiner() %} +- {% for os in osArchitectures[path].filterOS("CentOS") %}{{comma()}} [CentOS {{os.version}}](linux_{{path}}/{{productShortname}}_centos_{{os.version}}){% endfor %} +{% endif %} +{% endif %} + + +{% if osArchitectures[path].hasFamily("SLES") and renderOSes.includes("SLES") %} +### SUSE Linux Enterprise (SLES) + +{% set comma = joiner() %} +- {% for os in osArchitectures[path].filterOS("SLES") %}{{comma()}} [SLES {{os.version}}](linux_{{path}}/{{productShortname}}_sles_{{os.version}}){% endfor %} + +{% endif %} + +{% if osArchitectures[path].hasFamily("Debian") %} +### Debian and derivatives + +{% if osArchitectures[path].hasOS("Ubuntu") and renderOSes.includes("Ubuntu") %} +{% set comma = joiner() %} +- {% for os in osArchitectures[path].filterOS("Ubuntu") %}{{comma()}} [Ubuntu {{os.version}}](linux_{{path}}/{{productShortname}}_ubuntu_{{os.version | replace(r/\.\d+$/, "")}}){% endfor %} +{% endif %} +{% if osArchitectures[path].hasOS("Debian") and renderOSes.includes("Debian") %} +{% set comma = joiner() %} +- {% for os in osArchitectures[path].filterOS("Debian") %}{{comma()}} [Debian {{os.version}}](linux_{{path}}/{{productShortname}}_debian_{{os.version | replace(r/\.\d+$/, "")}}){% endfor %} +{% endif %} + +{% endif %} +{% endif %} +{% endmacro %} + +{% block linuxinstall %} +{{archInstall("x86-64 (amd64)", "x86_64", ["RHEL", "OL", "Rocky", "Alma", "CentOS", "SLES", "Ubuntu", "Debian"])}} + +{{archInstall("IBM Power (ppc64le)", "ppc64le", ["RHEL", "SLES"])}} +{% endblock linuxinstall %} + +{% block otherosinstall %} +{% endblock otherosinstall %} + +{% block final %} +{% endblock final %} diff --git a/install_template/templates/platformBase/ppc64le_index.njk b/install_template/templates/platformBase/ppc64le_index.njk new file mode 100644 index 00000000000..71c5122b40c --- /dev/null +++ b/install_template/templates/platformBase/ppc64le_index.njk @@ -0,0 +1,43 @@ +--- +title: "Installing {{ product.name }} on Linux IBM Power (ppc64le)" +navTitle: "On Linux ppc64le" +# This topic is generated from templates. If you have feedback on it, instead of +# editing the page and creating a pull request, please enter a GitHub issue and +# the documentation team will update the templates accordingly. +# Leaf template: {{ leafTemplatePath }} +{% block frontmatter %} +deployPath: {{productShortname}}/{{ product.version }}/installing/linux_ppc64le/index.mdx +{% endblock frontmatter %} +navigation: +{% block navigation %} +- {{productShortname}}_rhel_8 +- {{productShortname}}_sles_15 +- {{productShortname}}_sles_12 +{% endblock navigation %} +--- + +For operating system-specific install instructions, including accessing the repo, see: + +{% block install %} +{% if osVersions.hasFamily("RHEL") %} +### Red Hat Enterprise Linux (RHEL) + +{% for os in osVersions.filterOS("RHEL") %} +- [RHEL {{os.version}}]({{productShortname}}_rhel_{{os.version}}) +{% endfor %} + +{% endif %} + +{% if osVersions.hasFamily("SLES") %} +### SUSE Linux Enterprise (SLES) + +{% for os in osVersions.filterOS("SLES") %} +- [SLES {{os.version}}]({{productShortname}}_sles_{{os.version}}) +{% endfor %} + +{% endif %} +{% endblock install %} + + +{% block final %} +{% endblock final %} diff --git a/install_template/templates/platformBase/x86_64_index.njk b/install_template/templates/platformBase/x86_64_index.njk new file mode 100644 index 00000000000..89933294262 --- /dev/null +++ b/install_template/templates/platformBase/x86_64_index.njk @@ -0,0 +1,73 @@ +--- +title: "Installing {{ product.name }} on Linux x86 (amd64)" +navTitle: "On Linux x86" +# This topic is generated from templates. If you have feedback on it, instead of +# editing the page and creating a pull request, please enter a GitHub issue and +# the documentation team will update the templates accordingly. +# Leaf template: {{ leafTemplatePath }} +{% block frontmatter %} +deployPath: {{productShortname}}/{{ product.version }}/installing/linux_x86_64/index.mdx +{% endblock frontmatter %} +navigation: +{% block navigation %} +- {{productShortname}}_rhel_8 +- {{productShortname}}_other_linux_8 +- {{productShortname}}_rhel_7 +- {{productShortname}}_centos_7 +- {{productShortname}}_sles_15 +- {{productShortname}}_sles_12 +- {{productShortname}}_ubuntu_22 +- {{productShortname}}_ubuntu_20 +- {{productShortname}}_ubuntu_18 +- {{productShortname}}_debian_11 +- {{productShortname}}_debian_10 +{% endblock navigation %} +--- + +For operating system-specific install instructions, including accessing the repo, see: + +{% if osVersions.hasFamily("RHEL") %} +### Red Hat Enterprise Linux (RHEL) and derivatives + +{% for os in osVersions.filterOS("RHEL") %} +- [RHEL {{os.version}}]({{productShortname}}_rhel_{{os.version}}) +{% endfor %} +{% for os in osVersions.filterOS("RHEL") %} +- [Oracle Linux (OL) {{os.version}}]({{productShortname}}_rhel_{{os.version}}) +{% endfor %} +{% for os in osVersions.filterOS("Alma/Rocky") %} +- [Rocky Linux {{os.version}}]({{productShortname}}_other_linux_{{os.version}}) +{% endfor %} +{% for os in osVersions.filterOS("Alma/Rocky") %} +- [AlmaLinux {{os.version}}]({{productShortname}}_other_linux_{{os.version}}) +{% endfor %} +{% for os in osVersions.filterOS("CentOS") %} +- [CentOS {{os.version}}]({{productShortname}}_centos_{{os.version}}) +{% endfor %} +{% endif %} + +{% if osVersions.hasFamily("SLES") %} +### SUSE Linux Enterprise (SLES) + +{% for os in osVersions.filterOS("SLES") %} +- [SLES {{os.version}}]({{productShortname}}_sles_{{os.version}}) +{% endfor %} + +{% endif %} + +{% if osVersions.hasFamily("Debian") %} +### Debian and derivatives + +{% for os in osVersions.filterOS("Ubuntu") %} +- [Ubuntu {{os.version}}]({{productShortname}}_ubuntu_{{os.version | replace(r/\.\d+$/, "")}}) +{% endfor %} + +{% for os in osVersions.filterOS("Debian") %} +- [Debian {{os.version}}]({{productShortname}}_debian_{{os.version | replace(r/\.\d+$/, "")}}) +{% endfor %} + +{% endif %} + + +{% block final %} +{% endblock final %} diff --git a/install_template/templates/products/edb*plus/base.njk b/install_template/templates/products/edb*plus/base.njk index f3496f7e3e0..ecf38e3baba 100644 --- a/install_template/templates/products/edb*plus/base.njk +++ b/install_template/templates/products/edb*plus/base.njk @@ -14,7 +14,6 @@ redirects: {% block prodprereq %} -{% include "platformBase/_javainstall.njk" %} {% endblock prodprereq %} {% block installCommand %} {{super()}} diff --git a/install_template/templates/products/edb*plus/index.njk b/install_template/templates/products/edb*plus/index.njk new file mode 100644 index 00000000000..77f279897e1 --- /dev/null +++ b/install_template/templates/products/edb*plus/index.njk @@ -0,0 +1,25 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="edbplus" %} + +{% block title %} +navTitle: Installing +title: Installing {{ product.name }} +{% endblock title %} + +{% block frontmatter %} +deployPath: edb_plus/{{ product.version }}/installing/index.mdx +redirects: + - /edb_plus/latest/03_installing_edb_plus/ + - /edb_plus/latest/03_installing_edb_plus/install_on_linux/ +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- windows +- configuring_linux_installation +{% endblock navigation %} + +{% block otherosinstall %} +## Windows +- [Windows Server 2019](windows) +{% endblock otherosinstall %} diff --git a/install_template/templates/products/edb*plus/ppc64le_index.njk b/install_template/templates/products/edb*plus/ppc64le_index.njk new file mode 100644 index 00000000000..40b2b365549 --- /dev/null +++ b/install_template/templates/products/edb*plus/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="edbplus" %} + +{% block frontmatter %} +deployPath: edb_plus/{{ product.version }}/installing/linux_ppc64le/index.mdx +redirects: + - /edb_plus/latest/03_installing_edb_plus/install_on_linux/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb*plus/x86_64_index.njk b/install_template/templates/products/edb*plus/x86_64_index.njk new file mode 100644 index 00000000000..73e74b184d8 --- /dev/null +++ b/install_template/templates/products/edb*plus/x86_64_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="edbplus" %} + +{% block frontmatter %} +deployPath: edb_plus/{{ product.version }}/installing/linux_x86_64/index.mdx +redirects: + - /edb_plus/latest/03_installing_edb_plus/install_on_linux/x86_amd64/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-jdbc-connector/index.njk b/install_template/templates/products/edb-jdbc-connector/index.njk new file mode 100644 index 00000000000..ce36ec7c0b4 --- /dev/null +++ b/install_template/templates/products/edb-jdbc-connector/index.njk @@ -0,0 +1,32 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="jdbc" %} + +{% block title %} +navTitle: Installing +title: Installing {{ product.name }} +{% endblock title %} + +{% block frontmatter %} +deployPath: jdbc_connector/{{ product.version }}/installing/index.mdx +redirects: + - /jdbc_connector/latest/04_installing_and_configuring_the_jdbc_connector/ + - /jdbc_connector/latest/04_installing_and_configuring_the_jdbc_connector/01_installing_the_connector_with_an_rpm_package/ +legacyRedirectsGenerated: + # This list is generated by a script. If you need add entries, use the `legacyRedirects` key. + - "/edb-docs/d/jdbc-connector/user-guides/jdbc-guide/42.2.12.3/installing_and_configuring_the_jdbc_connector.html" + - "/edb-docs/d/jdbc-connector/user-guides/jdbc-guide/42.2.9.1/installing_and_configuring_the_jdbc_connector.html" + - "/edb-docs/d/jdbc-connector/user-guides/jdbc-guide/42.2.8.1/installing_and_configuring_the_jdbc_connector.html" + - "/edb-docs/d/jdbc-connector/user-guides/jdbc-guide/42.2.12.1/installing_and_configuring_the_jdbc_connector.html" +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- windows +- configuring_for_java +- upgrading +{% endblock navigation %} + +{% block otherosinstall %} +## Windows +- [Windows Server 2019](windows) +{% endblock otherosinstall %} diff --git a/install_template/templates/products/edb-jdbc-connector/ppc64le_index.njk b/install_template/templates/products/edb-jdbc-connector/ppc64le_index.njk new file mode 100644 index 00000000000..f780dab7edb --- /dev/null +++ b/install_template/templates/products/edb-jdbc-connector/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="jdbc" %} + +{% block frontmatter %} +deployPath: jdbc_connector/{{ product.version }}/installing/linux_ppc64le/index.mdx +redirects: + - /jdbc_connector/latest/04_installing_and_configuring_the_jdbc_connector/01_installing_the_connector_with_an_rpm_package/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-jdbc-connector/x86_64_index.njk b/install_template/templates/products/edb-jdbc-connector/x86_64_index.njk new file mode 100644 index 00000000000..94e374a63a5 --- /dev/null +++ b/install_template/templates/products/edb-jdbc-connector/x86_64_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="jdbc" %} + +{% block frontmatter %} +deployPath: jdbc_connector/{{ product.version }}/installing/linux_x86_64/index.mdx +redirects: + - /jdbc_connector/latest/04_installing_and_configuring_the_jdbc_connector/01_installing_the_connector_with_an_rpm_package/x86_amd64/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-ocl-connector/index.njk b/install_template/templates/products/edb-ocl-connector/index.njk new file mode 100644 index 00000000000..0ba0d357492 --- /dev/null +++ b/install_template/templates/products/edb-ocl-connector/index.njk @@ -0,0 +1,25 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="ocl" %} + +{% block title %} +navTitle: Installing +title: Installing {{ product.name }} +{% endblock title %} + +{% block frontmatter %} +deployPath: ocl_connector/{{ product.version }}/installing/index.mdx +redirects: + - /ocl_connector/latest/04_open_client_library/01_installing_and_configuring_the_ocl_connector/ + - /ocl_connector/latest/04_open_client_library/01_installing_and_configuring_the_ocl_connector/install_on_linux_using_edb_repo/ +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- windows +- upgrading +{% endblock navigation %} + +{% block otherosinstall %} +## Windows +- [Windows Server 2019](windows) +{% endblock otherosinstall %} diff --git a/install_template/templates/products/edb-ocl-connector/ppc64le_index.njk b/install_template/templates/products/edb-ocl-connector/ppc64le_index.njk new file mode 100644 index 00000000000..082d0267b7a --- /dev/null +++ b/install_template/templates/products/edb-ocl-connector/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="ocl" %} + +{% block frontmatter %} +deployPath: ocl_connector/{{ product.version }}/installing/linux_ppc64le/index.mdx +redirects: + - /ocl_connector/latest/04_open_client_library/01_installing_and_configuring_the_ocl_connector/install_on_linux_using_edb_repo/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-ocl-connector/x86_64_index.njk b/install_template/templates/products/edb-ocl-connector/x86_64_index.njk new file mode 100644 index 00000000000..8633514848b --- /dev/null +++ b/install_template/templates/products/edb-ocl-connector/x86_64_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="ocl" %} + +{% block frontmatter %} +deployPath: ocl_connector/{{ product.version }}/installing/linux_x86_64/index.mdx +redirects: + - /ocl_connector/latest/04_open_client_library/01_installing_and_configuring_the_ocl_connector/install_on_linux_using_edb_repo/x86_amd64/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-odbc-connector/index.njk b/install_template/templates/products/edb-odbc-connector/index.njk new file mode 100644 index 00000000000..4fb3a841b23 --- /dev/null +++ b/install_template/templates/products/edb-odbc-connector/index.njk @@ -0,0 +1,26 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="odbc" %} + +{% block title %} +navTitle: Installing +title: Installing {{ product.name }} +{% endblock title %} + +{% block frontmatter %} +deployPath: odbc_connector/{{ product.version }}/installing/index.mdx +redirects: + - ../03_edb-odbc_overview/01_installing_edb-odbc + - /odbc_connector/latest/03_installing_edb_odbc/ + - /odbc_connector/latest/03_installing_edb_odbc/01_installing_linux/ +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- windows +- upgrading +{% endblock navigation %} + +{% block otherosinstall %} +## Windows +- [Windows Server 2019](windows) +{% endblock otherosinstall %} diff --git a/install_template/templates/products/edb-odbc-connector/ppc64le_index.njk b/install_template/templates/products/edb-odbc-connector/ppc64le_index.njk new file mode 100644 index 00000000000..ebdc596f87e --- /dev/null +++ b/install_template/templates/products/edb-odbc-connector/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="odbc" %} + +{% block frontmatter %} +deployPath: odbc_connector/{{ product.version }}/installing/linux_ppc64le/index.mdx +redirects: + - /odbc_connector/latest/03_installing_edb_odbc/01_installing_linux/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-odbc-connector/x86_64_index.njk b/install_template/templates/products/edb-odbc-connector/x86_64_index.njk new file mode 100644 index 00000000000..ceaa161603d --- /dev/null +++ b/install_template/templates/products/edb-odbc-connector/x86_64_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="odbc" %} + +{% block frontmatter %} +deployPath: odbc_connector/{{ product.version }}/installing/linux_x86_64/index.mdx +redirects: + - /odbc_connector/latest/03_installing_edb_odbc/01_installing_linux/x86_amd64/ + {% endblock frontmatter %} diff --git a/install_template/templates/products/edb-pgbouncer/index.njk b/install_template/templates/products/edb-pgbouncer/index.njk new file mode 100644 index 00000000000..77c2b3fd9e5 --- /dev/null +++ b/install_template/templates/products/edb-pgbouncer/index.njk @@ -0,0 +1,26 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="pgbouncer" %} + +{% block title %} +navTitle: Installing +title: Installing {{ product.name }} +{% endblock title %} + +{% block frontmatter %} +{{super()}} +redirects: + - ../03_installing_pgbouncer_on_an_sles_host + - ../01_installation + - ../01_installation/install_on_linux/ +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- windows +{% endblock navigation %} + +{% block otherosinstall %} +## Windows +- [Windows Server 2019](windows) +{% endblock otherosinstall %} + \ No newline at end of file diff --git a/install_template/templates/products/edb-pgbouncer/ppc64le_index.njk b/install_template/templates/products/edb-pgbouncer/ppc64le_index.njk new file mode 100644 index 00000000000..3ba6a588bb8 --- /dev/null +++ b/install_template/templates/products/edb-pgbouncer/ppc64le_index.njk @@ -0,0 +1,10 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="pgbouncer" %} + +{% block frontmatter %} +{{super()}} +redirects: + - ../../03a_installing_pgbouncer_on_a_rhel8_ppcle_host + - /pgbouncer/latest/01_installation/install_on_linux/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-pgbouncer/x86_64_index.njk b/install_template/templates/products/edb-pgbouncer/x86_64_index.njk new file mode 100644 index 00000000000..31ae99695bb --- /dev/null +++ b/install_template/templates/products/edb-pgbouncer/x86_64_index.njk @@ -0,0 +1,10 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="pgbouncer" %} + +{% block frontmatter %} +{{super()}} +redirects: + - ../../02_installing_pgbouncer_on_a_debian_or_ubuntu_host/ + - /pgbouncer/latest/01_installation/install_on_linux/x86_amd64/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-pgpool-ii-extensions/index.njk b/install_template/templates/products/edb-pgpool-ii-extensions/index.njk new file mode 100644 index 00000000000..cc29bc39691 --- /dev/null +++ b/install_template/templates/products/edb-pgpool-ii-extensions/index.njk @@ -0,0 +1,23 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="pgpoolext" %} + +{% block title %} +navTitle: Installing extensions +title: Installing {{ product.name }} on Linux +{% endblock title %} + +{% block frontmatter %} +deployPath: pgpool/{{ product.version }}/installing_extensions/index.mdx +redirects: + - /pgpool/latest/02_extensions/ +legacyRedirectsGenerated: + # This list is generated by a script. If you need add entries, use the `legacyRedirects` key. + - "/edb-docs/d/pgpool-ii/user-guides/pgpool-ii-guide/1.0/extensions.html" +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- creating_pgpool_extensions +- upgrading_extensions +- uninstalling_extensions +{% endblock navigation %} diff --git a/install_template/templates/products/edb-pgpool-ii-extensions/ppc64le_index.njk b/install_template/templates/products/edb-pgpool-ii-extensions/ppc64le_index.njk new file mode 100644 index 00000000000..3a062bbb825 --- /dev/null +++ b/install_template/templates/products/edb-pgpool-ii-extensions/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="pgpoolext" %} + +{% block frontmatter %} +deployPath: pgpool/{{ product.version }}/installing_extensions/linux_ppc64le/index.mdx +redirects: + - /pgpool/latest/02_extensions/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-pgpool-ii-extensions/x86_64_index.njk b/install_template/templates/products/edb-pgpool-ii-extensions/x86_64_index.njk new file mode 100644 index 00000000000..5c50a9103cd --- /dev/null +++ b/install_template/templates/products/edb-pgpool-ii-extensions/x86_64_index.njk @@ -0,0 +1,12 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="pgpoolext" %} + +{% block frontmatter %} +deployPath: pgpool/{{ product.version }}/installing_extensions/linux_x86_64/index.mdx +redirects: + - /pgpool/latest/02_extensions/x86_amd64/ +legacyRedirectsGenerated: + # This list is generated by a script. If you need add entries, use the `legacyRedirects` key. + - "/edb-docs/d/pgbouncer/user-guides/pgbouncer-guide/1.0/installing_pgbouncer_on_a_debian_or_ubuntu_host.html" +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-pgpool-ii/index.njk b/install_template/templates/products/edb-pgpool-ii/index.njk new file mode 100644 index 00000000000..cea6efa9540 --- /dev/null +++ b/install_template/templates/products/edb-pgpool-ii/index.njk @@ -0,0 +1,17 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="pgpool" %} + +{% block frontmatter %} +{{super()}} +redirects: + - /pgpool/latest/01_installing_and_configuring_the_pgpool-II/ +legacyRedirectsGenerated: + # This list is generated by a script. If you need add entries, use the `legacyRedirects` key. + - "/edb-docs/d/pgpool-ii/user-guides/pgpool-ii-guide/1.0/installing_and_configuring_the_pgpool-II.html" +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- upgrading +- uninstalling +{% endblock navigation %} diff --git a/install_template/templates/products/edb-pgpool-ii/ppc64le_index.njk b/install_template/templates/products/edb-pgpool-ii/ppc64le_index.njk new file mode 100644 index 00000000000..637b55cba1a --- /dev/null +++ b/install_template/templates/products/edb-pgpool-ii/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="pgpool" %} + +{% block frontmatter %} +{{super()}} +redirects: + - /pgpool/latest/01_installing_and_configuring_the_pgpool-II/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-pgpool-ii/x86_64_index.njk b/install_template/templates/products/edb-pgpool-ii/x86_64_index.njk new file mode 100644 index 00000000000..1fb444792ce --- /dev/null +++ b/install_template/templates/products/edb-pgpool-ii/x86_64_index.njk @@ -0,0 +1,12 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="pgpool" %} + +{% block frontmatter %} +{{super()}} +redirects: + - /pgpool/latest/01_installing_and_configuring_the_pgpool-II/x86_amd64/ +legacyRedirectsGenerated: + # This list is generated by a script. If you need add entries, use the `legacyRedirects` key. + - "/edb-docs/d/pgbouncer/user-guides/pgbouncer-guide/1.0/installing_pgbouncer_on_a_debian_or_ubuntu_host.html" +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-postgres-advanced-server/index.njk b/install_template/templates/products/edb-postgres-advanced-server/index.njk new file mode 100644 index 00000000000..2f5770c467d --- /dev/null +++ b/install_template/templates/products/edb-postgres-advanced-server/index.njk @@ -0,0 +1,26 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="epas" %} + +{% block title %} +navTitle: Installing +title: Installing {{ product.name }} +{% endblock title %} + +{% block frontmatter %} +{{super()}} +redirects: + - /epas/{{product.version}}/epas_inst_linux/ + - /epas/{{product.version}}/epas_inst_linux/installing_epas_using_edb_repository/ +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- windows +- linux_install_details +- windows_install_details +{% endblock navigation %} + +{% block otherosinstall %} +## Windows +- [Windows Server 2019](windows) +{% endblock otherosinstall %} diff --git a/install_template/templates/products/edb-postgres-advanced-server/ppc64le_index.njk b/install_template/templates/products/edb-postgres-advanced-server/ppc64le_index.njk new file mode 100644 index 00000000000..8f71fec6073 --- /dev/null +++ b/install_template/templates/products/edb-postgres-advanced-server/ppc64le_index.njk @@ -0,0 +1,10 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="epas" %} + +{% block frontmatter %} +{{super()}} +redirects: + - /epas/{{product.version}}/epas_inst_linux/installing_epas_using_edb_repository/ibm_power_ppc64le/ + - /epas/{{product.version}}/epas_inst_linux/03_using_a_package_manager_to_install_advanced_server/#installing-on-ibm-power-ppc64le +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-postgres-advanced-server/x86_64_index.njk b/install_template/templates/products/edb-postgres-advanced-server/x86_64_index.njk new file mode 100644 index 00000000000..742cb64f166 --- /dev/null +++ b/install_template/templates/products/edb-postgres-advanced-server/x86_64_index.njk @@ -0,0 +1,10 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="epas" %} + +{% block frontmatter %} +{{super()}} +redirects: + - ../03_using_a_package_manager_to_install_advanced_server + - /epas/{{product.version}}/epas_inst_linux/installing_epas_using_edb_repository/x86_amd64/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-postgres-extended-server/index.njk b/install_template/templates/products/edb-postgres-extended-server/index.njk new file mode 100644 index 00000000000..9a4450076cd --- /dev/null +++ b/install_template/templates/products/edb-postgres-extended-server/index.njk @@ -0,0 +1,11 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="pge" %} + +{% block frontmatter %} +{{super()}} +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +{% endblock navigation %} + diff --git a/install_template/templates/products/edb-postgres-extended-server/ppc64le_index.njk b/install_template/templates/products/edb-postgres-extended-server/ppc64le_index.njk new file mode 100644 index 00000000000..ae05f262a10 --- /dev/null +++ b/install_template/templates/products/edb-postgres-extended-server/ppc64le_index.njk @@ -0,0 +1,7 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="pge" %} + +{% block frontmatter %} +{{super()}} +{% endblock frontmatter %} diff --git a/install_template/templates/products/edb-postgres-extended-server/x86_64_index.njk b/install_template/templates/products/edb-postgres-extended-server/x86_64_index.njk new file mode 100644 index 00000000000..e288bb22890 --- /dev/null +++ b/install_template/templates/products/edb-postgres-extended-server/x86_64_index.njk @@ -0,0 +1,7 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="pge" %} + +{% block frontmatter %} +{{super()}} +{% endblock frontmatter %} diff --git a/install_template/templates/products/failover-manager/index.njk b/install_template/templates/products/failover-manager/index.njk new file mode 100644 index 00000000000..c2c84eb084a --- /dev/null +++ b/install_template/templates/products/failover-manager/index.njk @@ -0,0 +1,20 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="efm" %} + +{% block frontmatter %} +{{ super() }} +redirects: + - ../efm_user/03_installing_efm + - 13_initial_config + - /efm/latest/03_installing_efm/ +legacyRedirectsGenerated: + # This list is generated by a script. If you need add entries, use the `legacyRedirects` key. + - "/edb-docs/d/edb-postgres-failover-manager/user-guides/user-guide/4.0/installing_efm.html" + - "/edb-docs/d/edb-postgres-failover-manager/user-guides/user-guide/4.1/installing_efm.html" +{% endblock frontmatter %} +{% block navigation %} +- prerequisites +- linux_x86_64 +- linux_ppc64le +- install_details +{% endblock navigation %} diff --git a/install_template/templates/products/failover-manager/ppc64le_index.njk b/install_template/templates/products/failover-manager/ppc64le_index.njk new file mode 100644 index 00000000000..79c3f2b7a06 --- /dev/null +++ b/install_template/templates/products/failover-manager/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="efm" %} + +{% block frontmatter %} +{{ super() }} +redirects: + - /efm/latest/03_installing_efm/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/failover-manager/x86_64_index.njk b/install_template/templates/products/failover-manager/x86_64_index.njk new file mode 100644 index 00000000000..edd08eb5c26 --- /dev/null +++ b/install_template/templates/products/failover-manager/x86_64_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="efm" %} + +{% block frontmatter %} +{{ super() }} +redirects: + - /efm/latest/03_installing_efm/x86_amd64/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/hadoop-foreign-data-wrapper/index.njk b/install_template/templates/products/hadoop-foreign-data-wrapper/index.njk new file mode 100644 index 00000000000..e8fc3c9cfaa --- /dev/null +++ b/install_template/templates/products/hadoop-foreign-data-wrapper/index.njk @@ -0,0 +1,12 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="hadoop" %} + +{% block frontmatter %} +deployPath: hadoop_data_adapter/{{ product.version }}/installing/index.mdx +redirects: + - /hadoop_data_adapter/latest/05_installing_the_hadoop_data_adapter/ +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +{% endblock navigation %} diff --git a/install_template/templates/products/hadoop-foreign-data-wrapper/ppc64le_index.njk b/install_template/templates/products/hadoop-foreign-data-wrapper/ppc64le_index.njk new file mode 100644 index 00000000000..7fa9c009f8c --- /dev/null +++ b/install_template/templates/products/hadoop-foreign-data-wrapper/ppc64le_index.njk @@ -0,0 +1,13 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="hadoop" %} + +{% block frontmatter %} +deployPath: hadoop_data_adapter/{{ product.version }}/installing/linux_ppc64le/index.mdx +redirects: + - /hadoop_data_adapter/latest/05_installing_the_hadoop_data_adapter/ibm_power_ppc64le/ +{% endblock frontmatter %} + +{% block final %} +After you complete the installation, see [Initial configuration](../../configuring). +{% endblock final %} diff --git a/install_template/templates/products/hadoop-foreign-data-wrapper/x86_64_index.njk b/install_template/templates/products/hadoop-foreign-data-wrapper/x86_64_index.njk new file mode 100644 index 00000000000..fe70edcb2bd --- /dev/null +++ b/install_template/templates/products/hadoop-foreign-data-wrapper/x86_64_index.njk @@ -0,0 +1,13 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="hadoop" %} + +{% block frontmatter %} +deployPath: hadoop_data_adapter/{{ product.version }}/installing/linux_x86_64/index.mdx +redirects: + - /hadoop_data_adapter/latest/05_installing_the_hadoop_data_adapter/x86_amd64/ +{% endblock frontmatter %} + +{% block final %} +After you complete the installation, see [Initial configuration](../../configuring). +{% endblock final %} diff --git a/install_template/templates/products/migration-toolkit/base.njk b/install_template/templates/products/migration-toolkit/base.njk index 4690b21459a..1b9ba0680f5 100644 --- a/install_template/templates/products/migration-toolkit/base.njk +++ b/install_template/templates/products/migration-toolkit/base.njk @@ -12,10 +12,7 @@ redirects: - migration_toolkit/{{ product.version }}/05_installing_mtk/install_on_linux/{{deploy.expand_arch[platform.arch]}}/mtk55_{{deploy.map_platform_old[platform.name]}}_{{platform.arch | replace(r/_?64/g, "")}}.mdx {% endblock frontmatter %} -{% block prodprereq %} - -{% include "platformBase/_javainstall.njk" %} -{% endblock prodprereq %} +{% block prodprereq %}{% endblock prodprereq %} {% block postinstall %} ## Initial configuration Before invoking Migration Toolkit, you must download and install JDBC drivers for connecting to the source and target databases. See [Installing a JDBC driver](/migration_toolkit/latest/installing/installing_jdbc_driver/) for details. diff --git a/install_template/templates/products/migration-toolkit/index.njk b/install_template/templates/products/migration-toolkit/index.njk new file mode 100644 index 00000000000..25de8450966 --- /dev/null +++ b/install_template/templates/products/migration-toolkit/index.njk @@ -0,0 +1,36 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="mtk" %} + +{% block title %} +navTitle: Installing +title: Installing {{ product.name }} +{% endblock title %} + +{% block frontmatter %} +deployPath: migration_toolkit/{{ product.version }}/installing/index.mdx +redirects: + - /migration_toolkit/latest/05_installing_mtk/install_on_linux + - /migration_toolkit/latest/05_installing_mtk + +legacyRedirects: + - "/edb-docs/d/edb-postgres-migration-toolkit/user-guides/user-guide/55.0.0/installing_on_mac.html" + - "/edb-docs/d/edb-postgres-migration-toolkit/user-guides/user-guide/55.0.0/installing_on_debian_or_ubuntu.html" + - "/edb-docs/d/edb-postgres-migration-toolkit/user-guides/user-guide/55.0.0/installing_on_windows.html" + - "/edb-docs/d/edb-postgres-migration-toolkit/user-guides/user-guide/55.0.0/installing_on_centos_or_rhel_ppcle.html" + - "/edb-docs/d/edb-postgres-migration-toolkit/user-guides/user-guide/55.0.0/installing_on_sles.html" + - "/edb-docs/d/edb-postgres-migration-toolkit/user-guides/user-guide/55.0.0/installing_on_centos_or_rhel.html" +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- install_on_mac +- install_on_windows +- installing_jdbc_driver +{% endblock navigation %} + +{% block otherosinstall %} +## Macintosh +- [Mac OS X](install_on_mac) +## Windows +- [Windows Server 2019](install_on_windows) +{% endblock otherosinstall %} \ No newline at end of file diff --git a/install_template/templates/products/migration-toolkit/ppc64le_index.njk b/install_template/templates/products/migration-toolkit/ppc64le_index.njk new file mode 100644 index 00000000000..da320e92424 --- /dev/null +++ b/install_template/templates/products/migration-toolkit/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="mtk" %} + +{% block frontmatter %} +deployPath: migration_toolkit/{{ product.version }}/installing/linux_ppc64le/index.mdx +redirects: + - /migration_toolkit/latest/05_installing_mtk/install_on_linux/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/migration-toolkit/x86_64_index.njk b/install_template/templates/products/migration-toolkit/x86_64_index.njk new file mode 100644 index 00000000000..5f1e93ae13f --- /dev/null +++ b/install_template/templates/products/migration-toolkit/x86_64_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="mtk" %} + +{% block frontmatter %} +deployPath: migration_toolkit/{{ product.version }}/installing/linux_x86_64/index.mdx +redirects: + - /migration_toolkit/latest/05_installing_mtk/install_on_linux/x86_amd64/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/mongodb-foreign-data-wrapper/index.njk b/install_template/templates/products/mongodb-foreign-data-wrapper/index.njk new file mode 100644 index 00000000000..f258fd25ded --- /dev/null +++ b/install_template/templates/products/mongodb-foreign-data-wrapper/index.njk @@ -0,0 +1,12 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="mongo" %} + +{% block frontmatter %} +deployPath: mongo_data_adapter/{{ product.version }}/installing/index.mdx +redirects: + - /mongo_data_adapter/latest/04_installing_the_mongo_data_adapter/ +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +{% endblock navigation %} diff --git a/install_template/templates/products/mongodb-foreign-data-wrapper/ppc64le_index.njk b/install_template/templates/products/mongodb-foreign-data-wrapper/ppc64le_index.njk new file mode 100644 index 00000000000..4d2eaeacbc9 --- /dev/null +++ b/install_template/templates/products/mongodb-foreign-data-wrapper/ppc64le_index.njk @@ -0,0 +1,13 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="mongo" %} + +{% block frontmatter %} +deployPath: mongo_data_adapter/{{ product.version }}/installing/linux_ppc64le/index.mdx +redirects: + - /mongo_data_adapter/latest/04_installing_the_mongo_data_adapter/ibm_power_ppc64le/ +{% endblock frontmatter %} + +{% block final %} +After you complete the installation, see [Initial configuration](../../configuring). +{% endblock final %} diff --git a/install_template/templates/products/mongodb-foreign-data-wrapper/x86_64_index.njk b/install_template/templates/products/mongodb-foreign-data-wrapper/x86_64_index.njk new file mode 100644 index 00000000000..def62806604 --- /dev/null +++ b/install_template/templates/products/mongodb-foreign-data-wrapper/x86_64_index.njk @@ -0,0 +1,13 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="mongo" %} + +{% block frontmatter %} +deployPath: mongo_data_adapter/{{ product.version }}/installing/linux_x86_64/index.mdx +redirects: + - /mongo_data_adapter/latest/04_installing_the_mongo_data_adapter/x86_amd64/ +{% endblock frontmatter %} + +{% block final %} +After you complete the installation, see [Initial configuration](../../configuring). +{% endblock final %} diff --git a/install_template/templates/products/mysql-foreign-data-wrapper/index.njk b/install_template/templates/products/mysql-foreign-data-wrapper/index.njk new file mode 100644 index 00000000000..5e224a543f5 --- /dev/null +++ b/install_template/templates/products/mysql-foreign-data-wrapper/index.njk @@ -0,0 +1,12 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="mysql" %} + +{% block frontmatter %} +deployPath: mysql_data_adapter/{{ product.version }}/installing/index.mdx +redirects: + - /mysql_data_adapter/latest/04_installing_the_mysql_data_adapter/ +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +{% endblock navigation %} diff --git a/install_template/templates/products/mysql-foreign-data-wrapper/ppc64le_index.njk b/install_template/templates/products/mysql-foreign-data-wrapper/ppc64le_index.njk new file mode 100644 index 00000000000..30a1692880f --- /dev/null +++ b/install_template/templates/products/mysql-foreign-data-wrapper/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="mysql" %} + +{% block frontmatter %} +deployPath: mysql_data_adapter/{{ product.version }}/installing/linux_ppc64le/index.mdx +redirects: + - /mysql_data_adapter/latest/04_installing_the_mysql_data_adapter/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/mysql-foreign-data-wrapper/x86_64_index.njk b/install_template/templates/products/mysql-foreign-data-wrapper/x86_64_index.njk new file mode 100644 index 00000000000..a4bf1a5a748 --- /dev/null +++ b/install_template/templates/products/mysql-foreign-data-wrapper/x86_64_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="mysql" %} + +{% block frontmatter %} +deployPath: mysql_data_adapter/{{ product.version }}/installing/linux_x86_64/index.mdx +redirects: + - /mysql_data_adapter/latest/04_installing_the_mysql_data_adapter/x86_amd64/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/postgis/index.njk b/install_template/templates/products/postgis/index.njk new file mode 100644 index 00000000000..237084b6918 --- /dev/null +++ b/install_template/templates/products/postgis/index.njk @@ -0,0 +1,26 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="postgis" %} + +{% block title %} +navTitle: Installing +title: Installing {{ product.name }} +{% endblock title %} + +{% block frontmatter %} +{{super()}} +redirects: + - /postgis/latest/01a_installing_postgis/ + - /postgis/latest/01a_installing_postgis/installing_on_linux/ +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- windows +- upgrading +- uninstalling +{% endblock navigation %} + +{% block otherosinstall %} +## Windows +- [Windows Server 2019](windows) +{% endblock otherosinstall %} diff --git a/install_template/templates/products/postgis/ppc64le_index.njk b/install_template/templates/products/postgis/ppc64le_index.njk new file mode 100644 index 00000000000..42f42746851 --- /dev/null +++ b/install_template/templates/products/postgis/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="postgis" %} + +{% block frontmatter %} +{{super()}} +redirects: + - /postgis/latest/01a_installing_postgis/installing_on_linux/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/postgis/x86_64_index.njk b/install_template/templates/products/postgis/x86_64_index.njk new file mode 100644 index 00000000000..f9a7eba0006 --- /dev/null +++ b/install_template/templates/products/postgis/x86_64_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="postgis" %} + +{% block frontmatter %} +{{super()}} +redirects: + - /postgis/latest/01a_installing_postgis/installing_on_linux/x86_amd64/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/postgres-enterprise-manager-agent/index.njk b/install_template/templates/products/postgres-enterprise-manager-agent/index.njk new file mode 100644 index 00000000000..2cefd9f9f6c --- /dev/null +++ b/install_template/templates/products/postgres-enterprise-manager-agent/index.njk @@ -0,0 +1,21 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="pem_agent" %} + +{% block title %} +navTitle: Installing the PEM agent +title: Installing {{ product.name }} +{% endblock title %} + +{% block frontmatter %} +deployPath: pem/{{ product.version }}/installing_pem_agent/index.mdx +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- windows_agent +{% endblock navigation %} + +{% block otherosinstall %} +## Windows +- [Windows Server 2019](windows_agent) +{% endblock otherosinstall %} diff --git a/install_template/templates/products/postgres-enterprise-manager-agent/ppc64le_index.njk b/install_template/templates/products/postgres-enterprise-manager-agent/ppc64le_index.njk new file mode 100644 index 00000000000..bf437fb22ea --- /dev/null +++ b/install_template/templates/products/postgres-enterprise-manager-agent/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="pem_agent" %} + +{% block frontmatter %} +deployPath: pem/{{ product.version }}/installing_pem_agent/linux_ppc64le/index.mdx +redirects: +- /pem/latest/installing_pem_agent/installing_on_linux/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/postgres-enterprise-manager-agent/x86_64_index.njk b/install_template/templates/products/postgres-enterprise-manager-agent/x86_64_index.njk new file mode 100644 index 00000000000..e385fab942b --- /dev/null +++ b/install_template/templates/products/postgres-enterprise-manager-agent/x86_64_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="pem_agent" %} + +{% block frontmatter %} +deployPath: pem/{{ product.version }}/installing_pem_agent/linux_x86_64/index.mdx +redirects: +- /pem/latest/installing_pem_agent/installing_on_linux/x86_amd64/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/postgres-enterprise-manager-server/index.njk b/install_template/templates/products/postgres-enterprise-manager-server/index.njk new file mode 100644 index 00000000000..ce362c7fd72 --- /dev/null +++ b/install_template/templates/products/postgres-enterprise-manager-server/index.njk @@ -0,0 +1,27 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="pem" %} + +{% block title %} +navTitle: Installing the PEM server +title: Installing {{ product.name }} +{% endblock title %} + +{% block frontmatter %} +{{super()}} +redirects: +- /pem/latest/installing_pem_server/ +- /pem/latest/installing_pem_server/pem_server_inst_linux/ +{% endblock frontmatter %} +{% block navigation %} +- prerequisites +- linux_x86_64 +- linux_ppc64le +- windows +- creating_pem_repository_in_isolated_network +- configuring_the_pem_server_on_linux +{% endblock navigation %} + +{% block otherosinstall %} +## Windows +- [Windows Server 2019](windows) +{% endblock otherosinstall %} diff --git a/install_template/templates/products/postgres-enterprise-manager-server/ppc64le_index.njk b/install_template/templates/products/postgres-enterprise-manager-server/ppc64le_index.njk new file mode 100644 index 00000000000..2685d3f5d1a --- /dev/null +++ b/install_template/templates/products/postgres-enterprise-manager-server/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="pem" %} + +{% block frontmatter %} +{{super()}} +redirects: + - /pem/latest/installing_pem_server/pem_server_inst_linux/installing_pem_server_using_edb_repository/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/postgres-enterprise-manager-server/x86_64_index.njk b/install_template/templates/products/postgres-enterprise-manager-server/x86_64_index.njk new file mode 100644 index 00000000000..b0c29ccc09d --- /dev/null +++ b/install_template/templates/products/postgres-enterprise-manager-server/x86_64_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="pem" %} + +{% block frontmatter %} +{{super()}} +redirects: + - /pem/latest/installing_pem_server/pem_server_inst_linux/installing_pem_server_using_edb_repository/x86_amd64/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/replication-server/base.njk b/install_template/templates/products/replication-server/base.njk index 0fd2cc646a5..367ae928265 100644 --- a/install_template/templates/products/replication-server/base.njk +++ b/install_template/templates/products/replication-server/base.njk @@ -12,15 +12,7 @@ redirects: - eprs/{{ product.version }}/03_installation/03_installing_rpm_package/{{deploy.expand_arch[platform.arch]}}/eprs_{{deploy.map_platform_old[platform.name]}}_{{platform.arch | replace(r/_?64/g, "")}}.mdx {% endblock frontmatter %} -{% block prodprereq %} - -{% include "platformBase/_javainstall.njk" %} -!!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. -!!! -{% endblock prodprereq %} +{% block prodprereq %}{% endblock prodprereq %} {% block installCommand %} You can install all Replication Server components with a single install command, or you may choose to install selected, individual components by installing only those particular packages. diff --git a/install_template/templates/products/replication-server/index.njk b/install_template/templates/products/replication-server/index.njk new file mode 100644 index 00000000000..cdff2bf4d32 --- /dev/null +++ b/install_template/templates/products/replication-server/index.njk @@ -0,0 +1,28 @@ +{% extends "platformBase/index.njk" %} +{% set productShortname="eprs" %} + +{% block title %} +navTitle: Installing +title: Installing {{ product.name }} +{% endblock title %} + +{% block frontmatter %} +{{super()}} +redirects: + - /eprs/latest/03_installation/ + - /eprs/latest/03_installation/03_installing_rpm_package/ +{% endblock frontmatter %} +{% block navigation %} +- linux_x86_64 +- linux_ppc64le +- windows +- installing_jdbc_driver +- installation_details +- upgrading_replication_server +- uninstalling +{% endblock navigation %} + +{% block otherosinstall %} +## Windows +- [Windows Server 2019](windows) +{% endblock otherosinstall %} diff --git a/install_template/templates/products/replication-server/ppc64le_index.njk b/install_template/templates/products/replication-server/ppc64le_index.njk new file mode 100644 index 00000000000..dc422c814a3 --- /dev/null +++ b/install_template/templates/products/replication-server/ppc64le_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/ppc64le_index.njk" %} +{% set productShortname="eprs" %} + +{% block frontmatter %} +{{super()}} +redirects: + - /eprs/latest/03_installation/03_installing_rpm_package/ibm_power_ppc64le/ +{% endblock frontmatter %} diff --git a/install_template/templates/products/replication-server/x86_64_index.njk b/install_template/templates/products/replication-server/x86_64_index.njk new file mode 100644 index 00000000000..516ac1a3782 --- /dev/null +++ b/install_template/templates/products/replication-server/x86_64_index.njk @@ -0,0 +1,9 @@ + +{% extends "platformBase/x86_64_index.njk" %} +{% set productShortname="eprs" %} + +{% block frontmatter %} +{{super()}} +redirects: + - /eprs/latest/03_installation/03_installing_rpm_package/x86_amd64/ +{% endblock frontmatter %} diff --git a/product_docs/docs/biganimal/release/free_trial/quickstart.mdx b/product_docs/docs/biganimal/release/free_trial/quickstart.mdx index 8c6cc3957ff..8e7ba33a342 100644 --- a/product_docs/docs/biganimal/release/free_trial/quickstart.mdx +++ b/product_docs/docs/biganimal/release/free_trial/quickstart.mdx @@ -8,7 +8,7 @@ tags: - psql --- -This topic provides a quick walk-through of the steps needed to configure a PostgreSQL 14 cluster on BigAnimal running against AWS with a free trial account. +This topic provides a quick walk-through of the steps needed to configure a PostgreSQL 15 cluster on BigAnimal running against AWS with a free trial account. ## Step 1: Create an account and sign into the portal @@ -37,7 +37,7 @@ Then, use your newly created account to access the [BigAnimal free trial portal] 1. Select **PostgreSQL** for **Database Type** This gives you an official build of PostgreSQL. -1. Select **14** for **Postgres Version**. +1. Select **15** for **Postgres Version**. 1. Select **US East 1** for **Region**. 1. For **Instance Type** and **Storage**, only one set of options is available in the trial. Select each option. @@ -55,15 +55,13 @@ Once your first cluster is fully provisioned, your 14-day free trial officially 2. Select the **Overview** tab and copy the **Quick Connect** command. Paste it into a terminal where psql is installed. It will prompt for your password and put you on a SQL command line. ```text - $ psql -W "postgres://edb_admin@[HOST]:5432/edb_admin?sslmode=require" - Password: - psql (13.5 (Ubuntu 13.5-2.pgdg20.04+1), server 14.2.1 (Debian 14.2.1-1+deb10)) - WARNING: psql major version 13, server major version 14. - Some psql features might not work. - SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off) + $ psql -W "postgres://edb_admin@p-qzwv2ns7pj.pg.biganimal.io:5432/edb_admin?sslmode=require" + Password: + psql (15.2) + SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off) Type "help" for help. - edb_admin=> + edb_admin=> ``` !!! Note @@ -76,25 +74,16 @@ Once your first cluster is fully provisioned, your 14-day free trial officially We're going to create some sample math data, so we're going to create a database called `math`. We _could_ use the default `edb_admin` database, but best practice is to isolate data. -1. Create a new role called `math`. +1. Create a new `math` database. ```sql - create user math with password 'math_password'; + create database math; ``` -2. Grant the `math` role to `edb_admin`. + !!! Note + Normally, we would also create a separate, limited-privilege user to own this database. However, the free trial user is unable to create users so we can only create the database. - ```sql - grant math to edb_admin; - ``` - -3. Create a new `math` database. - - ```sql - create database math with owner math; - ``` - -4. Connect to the `math` database. You're prompted for the `edb_admin` password you provided in Step 2 above. +2. Connect to the `math` database. You're prompted for the `edb_admin` password you provided in Step 2 above. ```sql \connect math diff --git a/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_rhel_8.mdx b/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_rhel_8.mdx index bed9049965b..4c1c480f7a9 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_rhel_8.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_rhel_8.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo dnf -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_sles_12.mdx b/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_sles_12.mdx index 00d5d0a0caf..f26b6450de3 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_sles_12.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_sles_12.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_sles_15.mdx b/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_sles_15.mdx index 6ec43efcfde..1a4ede098f9 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_sles_15.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_ppc64le/edbplus_sles_15.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_centos_7.mdx b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_centos_7.mdx index 1a6b13f45ce..95e286e16bf 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_centos_7.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_centos_7.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo yum -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_debian_10.mdx b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_debian_10.mdx index 9c635c52443..e0d45b96eed 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_debian_10.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_debian_10.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_debian_11.mdx b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_debian_11.mdx index d79ff288782..36a37cd7198 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_debian_11.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_debian_11.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_other_linux_8.mdx b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_other_linux_8.mdx index 6b4027d4701..3d54c3bbe42 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_other_linux_8.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_other_linux_8.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo dnf -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_rhel_7.mdx b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_rhel_7.mdx index c34969e58dc..e232375a07b 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_rhel_7.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_rhel_7.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo yum -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_rhel_8.mdx b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_rhel_8.mdx index 05daaf16632..43d66ec96b1 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_rhel_8.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_rhel_8.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo dnf -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_sles_12.mdx b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_sles_12.mdx index 00bb9501623..6998a800cdb 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_sles_12.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_sles_12.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_sles_15.mdx b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_sles_15.mdx index 3ab7cf02ee1..b4fb2112488 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_sles_15.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_sles_15.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_ubuntu_18.mdx b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_ubuntu_18.mdx index 878c9e2a020..52480e90f2e 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_ubuntu_18.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_ubuntu_18.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_ubuntu_20.mdx b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_ubuntu_20.mdx index 9b989c33da1..a5441db7445 100644 --- a/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_ubuntu_20.mdx +++ b/product_docs/docs/edb_plus/41/installing/linux_x86_64/edbplus_ubuntu_20.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/epas/15/epas_compat_ora_dev_guide/index.mdx b/product_docs/docs/epas/15/epas_compat_ora_dev_guide/index.mdx index 81dfa887775..ace759ab8ea 100644 --- a/product_docs/docs/epas/15/epas_compat_ora_dev_guide/index.mdx +++ b/product_docs/docs/epas/15/epas_compat_ora_dev_guide/index.mdx @@ -10,7 +10,9 @@ legacyRedirectsGenerated: -Database compatibility for Oracle means that an application runs in an Oracle environment as well as in the EDB Postgres Advanced Server environment with minimal or no changes to the application code. Developing an application that's compatible with Oracle databases in the EDB Postgres Advanced Server requires special attention to the features used when constructing the application. For example, developing a compatible application means choosing compatible: +EDB Postgres Advanced Server makes Postgres look, feel, and operate more like Oracle, so when you migrate, there is less code to rewrite and you can be up and running quickly. + +You use EDB Postgres Advanced Server features to design an application compatible with Oracle databases. For example, creating a compatible application entails selecting compatible: - System and built-in functions for use in SQL statements and procedural logic - Stored procedure language (SPL) when creating database server-side application logic for stored procedures, functions, triggers, and packages @@ -18,11 +20,9 @@ Database compatibility for Oracle means that an application runs in an Oracle en - SQL statements that are compatible with Oracle SQL - System catalog views that are compatible with Oracle’s data dictionary -For detailed information about the compatible SQL syntax, data types, and views, see [Database Compatibility for Oracle Developers SQL](/epas/latest/epas_compat_sql/). - -For the compatibility offered by the procedures and functions that are part of the built-in packages, see [Database Compatibility for Oracle Developers Built-in Packages](/epas/latest/epas_compat_bip_guide/). - -For information about using the compatible tools and utilities (EDB\*Plus, EDB\*Loader, DRITA, and EDB\*Wrap) that are included with an EDB Postgres Advanced Server installation, see [Tools and utilities](/epas/latest/epas_compat_ora_dev_guide/09_tools_and_utilities/). - -For applications written using the Oracle Call Interface (OCI), EDB’s Open Client Library (OCL) provides interoperability with these applications. For detailed information about using the Open Client Library, see [EDB OCL Connector](/ocl_connector/latest/). +!!!SeeAlso "Further reading" + - Compatible SQL syntax, data types, and views in [Database Compatibility for Oracle Developers: SQL](../epas_compat_sql/). + - Compatibility offered by the procedures and functions that are part of the built-in packages in [Database Compatibility for Oracle Developers: Built-in Packages](../epas_compat_bip_guide/). + - Compatible tools and utilities (EDB\*Plus, EDB\*Loader, DRITA, and EDB\*Wrap) that are included with an EDB Postgres Advanced Server installation in [Tools and utilities](../epas_compat_ora_dev_guide/09_tools_and_utilities/). + - For applications written using the Oracle Call Interface (OCI), EDB’s Open Client Library (OCL) provides interoperability with these applications. See [EDB OCL Connector](/ocl_connector/latest/). diff --git a/product_docs/docs/eprs/7/10_appendix/02_resolving_problems/04_troubleshooting_areas.mdx b/product_docs/docs/eprs/7/10_appendix/02_resolving_problems/04_troubleshooting_areas.mdx index df899522d47..4ffa9d2fff2 100644 --- a/product_docs/docs/eprs/7/10_appendix/02_resolving_problems/04_troubleshooting_areas.mdx +++ b/product_docs/docs/eprs/7/10_appendix/02_resolving_problems/04_troubleshooting_areas.mdx @@ -10,6 +10,12 @@ The following topics provide information on specific problem areas you may encou +## Removing Java can remove Replication Server + +When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. In this situation the JDK is installed as a dependency of the Replication Server. If you subsequently remove the JDK, Replication Server is also removed. + +If Java 1.8 or greater existed before Replication Server was installed, removing the JDK does not remove the Replication Server. + ## Java runtime errors If errors are encountered regarding the Java Runtime Environment such as the Java program cannot be found or Java heap space errors, check the parameters set in the Replication Server configuration file `xdbReplicationServer-xx.config`. See [Replication Server configuration file](../../02_overview/03_replication_server_components_and_architecture/01_physical_components/#xdb_replication_conf_file) for information on this file. diff --git a/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_rhel_8.mdx b/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_rhel_8.mdx index 895ba4132e3..6c87277175b 100644 --- a/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_rhel_8.mdx +++ b/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_rhel_8.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo dnf -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_sles_12.mdx b/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_sles_12.mdx index b1f1d51df98..ca6340e2ab9 100644 --- a/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_sles_12.mdx +++ b/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_sles_12.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_sles_15.mdx b/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_sles_15.mdx index c80ff37b593..659ff208dbf 100644 --- a/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_sles_15.mdx +++ b/product_docs/docs/eprs/7/installing/linux_ppc64le/eprs_sles_15.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_centos_7.mdx b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_centos_7.mdx index 6e62323e582..50428336a1a 100644 --- a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_centos_7.mdx +++ b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_centos_7.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo yum -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_debian_10.mdx b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_debian_10.mdx index 39527ecbe33..980d08f7e17 100644 --- a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_debian_10.mdx +++ b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_debian_10.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_debian_11.mdx b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_debian_11.mdx index 7f54705df86..6a9d7807b9f 100644 --- a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_debian_11.mdx +++ b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_debian_11.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_other_linux_8.mdx b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_other_linux_8.mdx index f6b24cdc363..cfa6d413b7d 100644 --- a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_other_linux_8.mdx +++ b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_other_linux_8.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo dnf -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_rhel_7.mdx b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_rhel_7.mdx index 8c607e82ae7..def66cf7f14 100644 --- a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_rhel_7.mdx +++ b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_rhel_7.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo yum -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_rhel_8.mdx b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_rhel_8.mdx index 59efc8b5404..2ee74a5d0d9 100644 --- a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_rhel_8.mdx +++ b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_rhel_8.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo dnf -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_sles_12.mdx b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_sles_12.mdx index c7033f6829d..324486c8a1a 100644 --- a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_sles_12.mdx +++ b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_sles_12.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_sles_15.mdx b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_sles_15.mdx index c104dafd612..3f3039e80f4 100644 --- a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_sles_15.mdx +++ b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_sles_15.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_ubuntu_18.mdx b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_ubuntu_18.mdx index a616c40b32b..acdf3fd4424 100644 --- a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_ubuntu_18.mdx +++ b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_ubuntu_18.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_ubuntu_20.mdx b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_ubuntu_20.mdx index 81a477e3b01..0c2122754b7 100644 --- a/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_ubuntu_20.mdx +++ b/product_docs/docs/eprs/7/installing/linux_x86_64/eprs_ubuntu_20.mdx @@ -13,18 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - !!!note - When Replication Server is installed on a machine where Java is not present, the JDK is installed as part of the installation process. Since in this case the JDK was installed via Replication Server as its dependency, if you subsequently remove the JDK, Replication Server is also removed. - - If Java 1.8 or greater exists before installing Replication Server, the installed Replication Server is not removed on removal of the JDK. - !!! - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_rhel_8.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_rhel_8.mdx index 5c3fe851c86..ca0634d49f7 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_rhel_8.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_rhel_8.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo dnf -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_sles_12.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_sles_12.mdx index 5a98cadaf26..3ff7acd834f 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_sles_12.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_sles_12.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_sles_15.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_sles_15.mdx index 6872d3ecf4c..a9c9919bb61 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_sles_15.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_ppc64le/mtk_sles_15.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_centos_7.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_centos_7.mdx index 8c218ff11ef..96915b7e1e0 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_centos_7.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_centos_7.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo yum -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_debian_10.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_debian_10.mdx index b1f59a44bab..e56bc2b5c7b 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_debian_10.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_debian_10.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_debian_11.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_debian_11.mdx index d9168d6cf48..4b27b89b2d3 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_debian_11.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_debian_11.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_other_linux_8.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_other_linux_8.mdx index ac1fc85a0f0..2c89ab7d06b 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_other_linux_8.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_other_linux_8.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo dnf -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_rhel_7.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_rhel_7.mdx index 49ca9f4f56f..837be7eb26a 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_rhel_7.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_rhel_7.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo yum -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_rhel_8.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_rhel_8.mdx index 031faa6778a..983d9bb0be4 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_rhel_8.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_rhel_8.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo dnf -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_sles_12.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_sles_12.mdx index 646c538c30c..bbd37c68ee8 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_sles_12.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_sles_12.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_sles_15.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_sles_15.mdx index fa61b9b854d..17058ea214e 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_sles_15.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_sles_15.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo zypper -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_ubuntu_18.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_ubuntu_18.mdx index 963972d27c8..8ba468b80db 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_ubuntu_18.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_ubuntu_18.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_ubuntu_20.mdx b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_ubuntu_20.mdx index 5749b1d0455..1bd340e58a6 100644 --- a/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_ubuntu_20.mdx +++ b/product_docs/docs/migration_toolkit/55/installing/linux_x86_64/mtk_ubuntu_20.mdx @@ -13,12 +13,6 @@ redirects: Before you begin the installation process: -- Install Java (version 1.8 or later) on your server, if not present. - - ```shell - sudo apt-get -y install java - ``` - - Set up the repository Setting up the repository is a one-time task. If you have already set up your repository, you do not need to perform this step. diff --git a/product_docs/docs/pgd/5/appusage.mdx b/product_docs/docs/pgd/5/appusage.mdx index c7356c1d0ae..1bbf68201a1 100644 --- a/product_docs/docs/pgd/5/appusage.mdx +++ b/product_docs/docs/pgd/5/appusage.mdx @@ -4,13 +4,13 @@ redirects: - ../bdr/appusage --- -Learn about the BDR application from a user perspective. +Learn about the PGD application from a user perspective. ## Application behavior -BDR supports replicating changes made on one node to other nodes. +PGD supports replicating changes made on one node to other nodes. -BDRs, by default, replicate all changes from INSERT, UPDATE, DELETE +PGD, by default, replicates all changes from INSERT, UPDATE, DELETE and TRUNCATE operations from the source node to other nodes. Only the final changes are sent, after all triggers and rules are processed. For example, `INSERT ... ON CONFLICT UPDATE` sends either an insert or an update @@ -20,7 +20,7 @@ zero rows, then no changes are sent. INSERT can be replicated without any preconditions. For updates and deletes to replicate on other nodes, we must be able to -identify the unique rows affected. BDR requires that a table have either +identify the unique rows affected. PGD requires that a table have either a PRIMARY KEY defined, a UNIQUE constraint, or an explicit REPLICA IDENTITY defined on specific columns. If one of those isn't defined, a warning is generated, and later updates or deletes are explicitly blocked. @@ -62,7 +62,7 @@ Sequences need special handling, described in [Sequences](sequences). Binary data in BYTEA columns is replicated normally, allowing "blobs" of data up to 1 GB in size. Use of the PostgreSQL "large object" facility isn't -supported in BDR. +supported in PGD. Rules execute only on the origin node so aren't executed during apply, even if they're enabled for replicas. @@ -75,7 +75,7 @@ DML changes that are made through updatable views are resolved to base tables on the origin and then applied to the same base table name on the target. -BDR supports partitioned tables transparently, meaning that a partitioned +PGD supports partitioned tables transparently, meaning that a partitioned table can be added to a replication set and changes that involve any of the partitions are replicated downstream. @@ -92,7 +92,7 @@ table and are currently enabled. Trigger types not executed are: - Statement-level triggers (`FOR EACH STATEMENT`) - Per-column UPDATE triggers (`UPDATE OF column_name [, ...]`) -BDR replication apply uses the system-level default search_path. Replica +PGD replication apply uses the system-level default search_path. Replica triggers, stream triggers, and index expression functions can assume other search_path settings that then fail when they execute on apply. To prevent this from occurring, resolve object references clearly using @@ -100,7 +100,7 @@ either only the default search_path, always use fully qualified references to objects, e.g., schema.objectname, or set the search path for a function using `ALTER FUNCTION ... SET search_path = ...` for the functions affected. -BDR assumes that there are no issues related to text or other +PGD assumes that there are no issues related to text or other collatable datatypes, i.e., all collations in use are available on all nodes, and the default collation is the same on all nodes. Replication of changes uses equality searches to locate Replica Identity values, so this @@ -108,21 +108,21 @@ does't have any effect except where unique indexes are explicitly defined with nonmatching collation qualifiers. Row filters might be affected by differences in collations if collatable expressions were used. -BDR handling of very long "toasted" data in PostgreSQL is transparent to +PGD handling of very long "toasted" data in PostgreSQL is transparent to the user. The TOAST "chunkid" values likely differ between the same row on different nodes, but that doesn't cause any problems. -BDR can't work correctly if Replica Identity columns are marked as external. +PGD can't work correctly if Replica Identity columns are marked as external. PostgreSQL allows CHECK() constraints that contain volatile functions. Since -BDR re-executes CHECK() constraints on apply, any subsequent re-execution that +PGD re-executes CHECK() constraints on apply, any subsequent re-execution that doesn't return the same result as previously causes data divergence. -BDR doesn't restrict the use of foreign keys. Cascading FKs are allowed. +PGD doesn't restrict the use of foreign keys. Cascading FKs are allowed. ## Nonreplicated statements -None of the following user commands are replicated by BDR, so their effects +None of the following user commands are replicated by PGD, so their effects occur on the local/origin node only: - Cursor operations (DECLARE, CLOSE, FETCH) @@ -139,36 +139,36 @@ aren't replicated, notifications aren't reliable in case of failover. This means that notifications can easily be lost at failover if a transaction is committed just when the server crashes. Applications running `LISTEN` might miss notifications in case of failover. -This is true in standard PostgreSQL replication, and BDR doesn't +This is true in standard PostgreSQL replication, and PGD doesn't yet improve on this. CAMO and Eager Replication options don't allow the `NOTIFY` SQL command or the `pg_notify()` function. ## DML and DDL replication -BDR doesn't replicate the DML statement. It replicates the changes +PGD doesn't replicate the DML statement. It replicates the changes caused by the DML statement. For example, an UPDATE that changed two rows replicates two changes, whereas a DELETE that didn't remove any rows doesn't replicate anything. This means that the results of executing volatile statements are replicated, ensuring there's no divergence between nodes as might occur with statement-based replication. -DDL replication works differently to DML. For DDL, BDR replicates the +DDL replication works differently to DML. For DDL, PGD replicates the statement, which then executes on all nodes. So a `DROP TABLE IF EXISTS` might not replicate anything on the local node, but the statement is still sent to other nodes for execution if DDL replication is enabled. Full details are covered in [DDL replication](ddl). -BDR works to ensure that intermixed DML and DDL +PGD works to ensure that intermixed DML and DDL statements work correctly, even in the same transaction. ## Replicating between different release levels -BDR is designed to replicate between nodes that have different major +PGD is designed to replicate between nodes that have different major versions of PostgreSQL. This feature is designed to allow major version upgrades without downtime. -BDR is also designed to replicate between nodes that have different -versions of BDR software. This feature is designed to allow version +PGD is also designed to replicate between nodes that have different +versions of PGD software. This feature is designed to allow version upgrades and maintenance without downtime. However, while it's possible to join a node with a major version in @@ -181,7 +181,7 @@ See [Release notes](/pgd/latest/rel_notes/) for any known incompatibilities. ## Replicating between nodes with differences By default, DDL is automatically sent to all nodes. You can control this manually, as described in [DDL Replication](ddl), and you could use it to create differences between database schemas across nodes. -BDR is designed to allow replication to continue even with minor +PGD is designed to allow replication to continue even with minor differences between nodes. These features are designed to allow application schema migration without downtime or to allow logical standby nodes for reporting or testing. @@ -197,20 +197,20 @@ same on the source and target since dynamic partition routing doesn't need to ex For details, see [Replication sets](repsets). By default, all columns are replicated. -BDR replicates data columns based on the column name. If a column +PGD replicates data columns based on the column name. If a column has the same name but a different datatype, we attempt to cast from the source type to the target type, if casts were defined that allow that. -BDR supports replicating between tables that have a different number of columns. +PGD supports replicating between tables that have a different number of columns. -If the target has missing columns from the source, then BDR raises +If the target has missing columns from the source, then PGD raises a `target_column_missing` conflict, for which the default conflict resolver is `ignore_if_null`. This throws an error if a non-NULL value arrives. Alternatively, you can also configure a node with a conflict resolver of `ignore`. This setting doesn't throw an error but silently ignores any additional columns. -If the target has additional columns not seen in the source record, then BDR +If the target has additional columns not seen in the source record, then PGD raises a `source_column_missing` conflict, for which the default conflict resolver is `use_default_value`. Replication proceeds if the additional columns have a default, either NULL (if nullable) or a default expression, but @@ -252,8 +252,8 @@ subset of nodes or locally. ## Comparison between nodes with differences -LiveCompare is a tool for data comparison on a database, against BDR and -non-BDR nodes. It needs a minimum of two connections to compare against +LiveCompare is a tool for data comparison on a database, against PGD and +non-PGD nodes. It needs a minimum of two connections to compare against and reach a final result. Since LiveCompare 1.3, you can configure with `all_bdr_nodes` set. This @@ -280,14 +280,14 @@ the DML to fix the any differences found. ## General rules for applications -BDR uses replica identity values to identify the rows to +PGD uses replica identity values to identify the rows to change. Applications can cause difficulties if they insert, delete, and then later reuse the same unique identifiers. -This is known as the [ABA problem](https://en.wikipedia.org/wiki/ABA_problem). BDR can't know whether the rows are the +This is known as the [ABA problem](https://en.wikipedia.org/wiki/ABA_problem). PGD can't know whether the rows are the current row, the last row, or much older rows. -Similarly, since BDR uses table names to identify the table against which +Similarly, since PGD uses table names to identify the table against which changes are replayed, a similar ABA problem exists with applications that create, drop, and then later reuse the same object names. @@ -308,21 +308,21 @@ on one node that prevented it from restarting correctly. ## Timing considerations and synchronous replication Being asynchronous by default, peer nodes might lag behind, making it -possible for a client connected to multiple BDR nodes or switching +possible for a client connected to multiple PGD nodes or switching between them to read stale data. A [queue wait function](functions#bdrwait_for_apply_queue) is provided for clients or proxies to prevent such stale reads. -The synchronous replication features of Postgres are available to BDR -as well. In addition, BDR provides multiple variants for more synchronous +The synchronous replication features of Postgres are available to PGD +as well. In addition, PGD provides multiple variants for more synchronous replication. See [Durability and performance options](durability) for an overview and comparison of all variants available and its different modes. ## Application testing -You can test BDR applications using the following programs, +You can test PGD applications using the following programs, in addition to other techniques. - [Trusted Postgres Architect](#trusted-postgres-architect) @@ -349,7 +349,7 @@ of the application. ### pgbench with CAMO/Failover options In EDB Postgres Extended, the pgbench was extended to allow users to -run failover tests while using CAMO or regular BDR deployments. The following options were added: +run failover tests while using CAMO or regular PGD deployments. The following options were added: ``` -m, --mode=regular|camo|failover @@ -365,7 +365,7 @@ form](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRIN - Use `-m camo` or `-m failover` to specify the mode for pgbench. You can use The `-m failover` specification to test failover in - regular BDR deployments. + regular PGD deployments. - Use `--retry` to specify whether to retry transactions when failover happens with `-m failover` mode. This option is enabled by default @@ -389,7 +389,7 @@ this scenario there's no way to find the status of in-flight transactions. ### isolationtester with multi-node access isolationtester was extended to allow users to run tests on multiple -sessions and on multiple nodes. This is used for internal BDR testing, +sessions and on multiple nodes. This is used for internal PGD testing, although it's also available for use with user application testing. ``` @@ -508,7 +508,7 @@ tester runs: Each selected step is sent to the connection associated with its session. -To run isolation tests in a BDR environment that ran all prerequisite make +To run isolation tests in a PGD environment that ran all prerequisite make commands: 1. Run `make isolationcheck-install` to install the isolationtester submodule. @@ -521,7 +521,7 @@ commands: To run `isolationcheck-installcheck`, you need to have two or more postgresql servers running. Pass the conninfo of each server to `pg_isolation_regress` -in the BDR makefile. +in the PGD makefile. Ex: `pg_isolation_regress --server 'd1=host=myhost dbname=mydb port=5434' --server 'd2=host=myhost1 dbname=mydb port=5432'` @@ -533,10 +533,10 @@ Then run `make isolationcheck-installcheck` `Isolationcheck-makecheck` currently supports running isolation tests on a -single instance by setting up BDR between multiple databases. +single instance by setting up PGD between multiple databases. You need to pass appropriate database names and the conninfo of bdr instances -to `pg_isolation_regress` in the BDR makefile as follows: +to `pg_isolation_regress` in the PGD makefile as follows: `pg_isolation_regress --dbname=db1,db2 --server 'd1=dbname=db1' --server 'd2=dbname=db2'` @@ -558,7 +558,7 @@ blocks on heavyweight locks are detected. ## Performance testing and tuning -BDR allows you to issue write transactions onto multiple master nodes. +PGD allows you to issue write transactions onto multiple master nodes. Bringing those writes back together onto each node has a cost in performance. @@ -583,7 +583,7 @@ allows you to write custom test scripts specific to your use case so you can understand the overheads of your SQL and measure the impact of concurrent execution. -If BDR is running slow, then we suggest the following: +If PGD is running slow, then we suggest the following: 1. Write a custom test script for pgbench, as close as you can make it to the production system's problem case. @@ -601,26 +601,26 @@ of critical parts of your application. ## Assessing suitability -BDR is compatible with PostgreSQL, but not all PostgreSQL applications are +PGD is compatible with PostgreSQL, but not all PostgreSQL applications are suitable for use on distributed databases. Most applications are already or -can easily be modified to become BDR compliant. You can undertake an -assessment activity in which you can point your application to a BDR-enabled -setup. BDR provides a few knobs that can be set during the assessment period. +can easily be modified to become PGD compliant. You can undertake an +assessment activity in which you can point your application to a PGD-enabled +setup. PGD provides a few knobs that can be set during the assessment period. These aid in the process of deciding suitability of your application in -a BDR-enabled environment. +a PGD-enabled environment. ### Assessing updates of primary key/replica identity -BDR can't currently perform conflict resolution where the PRIMARY KEY is changed +PGD can't currently perform conflict resolution where the PRIMARY KEY is changed by an UPDATE operation. You can update the primary key, but you must ensure that no conflict with existing values is possible. -BDR provides the following configuration parameter to assess how frequently +PGD provides the following configuration parameter to assess how frequently the primary key/replica identity of any table is being subjected to update operations. Use these configuration parameters only for assessment. -You can use them on a single node BDR instance, but don't use them on a production +You can use them on a single node PGD instance, but don't use them on a production EDB Postgres Distributed cluster with two or more nodes replicating to each other. In fact, a node might fail to start or a new node fail to join the cluster if any of the assessment parameters are set to anything other than `IGNORE`. @@ -646,11 +646,11 @@ Apply worker processes always ignore any settings for this parameter. ### Assessing use of LOCK on tables or in SELECT queries -Because BDR writer processes operate much like normal user sessions, they're subject to -the usual rules around row and table locking. This can sometimes lead to BDR writer +Because PGD writer processes operate much like normal user sessions, they're subject to +the usual rules around row and table locking. This can sometimes lead to PGD writer processes waiting on locks held by user transactions or even by each other. -BDR provides the following configuration parameter to assess if the application +PGD provides the following configuration parameter to assess if the application is taking explicit locks: ```sql diff --git a/product_docs/docs/pgd/5/backup.mdx b/product_docs/docs/pgd/5/backup.mdx index fd61bdc2c20..1f7f577b088 100644 --- a/product_docs/docs/pgd/5/backup.mdx +++ b/product_docs/docs/pgd/5/backup.mdx @@ -4,13 +4,11 @@ originalFilePath: backup.md --- -In this chapter we discuss the backup and restore of a EDB Postgres Distributed cluster. - -BDR is designed to be a distributed, highly available system. If +PGD is designed to be a distributed, highly available system. If one or more nodes of a cluster are lost, the best way to replace them is to clone new nodes directly from the remaining nodes. -The role of backup and recovery in BDR is to provide for Disaster +The role of backup and recovery in PGD is to provide for Disaster Recovery (DR), such as in the following situations: - Loss of all nodes in the cluster @@ -23,10 +21,10 @@ Recovery (DR), such as in the following situations: ### `pg_dump` `pg_dump`, sometimes referred to as "logical backup", can be used -normally with BDR. +normally with PGD. Note that `pg_dump` dumps both local and global sequences as if -they were local sequences. This is intentional, to allow a BDR +they were local sequences. This is intentional, to allow a PGD schema to be dumped and ported to other PostgreSQL databases. This means that sequence kind metadata is lost at the time of dump, so a restore would effectively reset all sequence kinds to @@ -46,7 +44,7 @@ Note that if `pg_dump` is run using `bdr.crdt_raw_value = on` then the dump can only be reloaded with `bdr.crdt_raw_value = on`. Technical Support recommends the use of physical backup techniques for -backup and recovery of BDR. +backup and recovery of PGD. ### Physical Backup @@ -54,20 +52,20 @@ Physical backups of a node in a EDB Postgres Distributed cluster can be taken us standard PostgreSQL software, such as [Barman](https://www.enterprisedb.com/docs/supported-open-source/barman/). -A physical backup of a BDR node can be performed with the same -procedure that applies to any PostgreSQL node: a BDR node is just a +A physical backup of a PGD node can be performed with the same +procedure that applies to any PostgreSQL node: a PGD node is just a PostgreSQL node running the BDR extension. There are some specific points that must be considered when applying -PostgreSQL backup techniques to BDR: +PostgreSQL backup techniques to PGD: -- BDR operates at the level of a single database, while a physical +- PGD operates at the level of a single database, while a physical backup includes all the databases in the instance; you should plan your databases to allow them to be easily backed-up and restored. - Backups will make a copy of just one node. In the simplest case, every node has a copy of all data, so you would need to backup only - one node to capture all data. However, the goal of BDR will not be + one node to capture all data. However, the goal of PGD will not be met if the site containing that single copy goes down, so the minimum should be at least one node backup per site (obviously with many copies etc.). @@ -131,11 +129,11 @@ To request this, use the standard syntax: recovery_target_time = T1 ``` -BDR allows for changes from multiple masters, all recorded within the +PGD allows for changes from multiple masters, all recorded within the WAL log for one node, separately identified using replication origin identifiers. -BDR allows PITR of all or some replication origins to a specific point in time, +PGD allows PITR of all or some replication origins to a specific point in time, providing a fully consistent viewpoint across all subsets of nodes. Thus for multi-origins, we view the WAL stream as containing multiple @@ -202,41 +200,41 @@ of changes arriving from a single master in COMMIT order. While you can take a physical backup with the same procedure as a standard PostgreSQL node, what is slightly more complex is -**restoring** the physical backup of a BDR node. +**restoring** the physical backup of a PGD node. ### EDB Postgres Distributed Cluster Failure or Seeding a New Cluster from a Backup The most common use case for restoring a physical backup involves the failure -or replacement of all the BDR nodes in a cluster, for instance in the event of +or replacement of all the PGD nodes in a cluster, for instance in the event of a datacentre failure. You may also want to perform this procedure to clone the current contents of a EDB Postgres Distributed cluster to seed a QA or development instance. -In that case, BDR capabilities can be restored based on a physical backup -of a single BDR node, optionally plus WAL archives: +In that case, PGD capabilities can be restored based on a physical backup +of a single PGD node, optionally plus WAL archives: -- If you still have some BDR nodes live and running, fence off the host you - restored the BDR node to, so it cannot connect to any surviving BDR nodes. +- If you still have some PGD nodes live and running, fence off the host you + restored the PGD node to, so it cannot connect to any surviving PGD nodes. This ensures that the new node does not confuse the existing cluster. - Restore a single PostgreSQL node from a physical backup of one of - the BDR nodes. + the PGD nodes. - If you have WAL archives associated with the backup, create a suitable `recovery.conf` and start PostgreSQL in recovery to replay up to the latest state. You can specify a alternative `recovery_target` here if needed. - Start the restored node, or promote it to read/write if it was in standby recovery. Keep it fenced from any surviving nodes! -- Clean up any leftover BDR metadata that was included in the physical backup, +- Clean up any leftover PGD metadata that was included in the physical backup, as described below. - Fully stop and restart the PostgreSQL instance. -- Add further BDR nodes with the standard procedure based on the +- Add further PGD nodes with the standard procedure based on the `bdr.join_node_group()` function call. -#### Cleanup BDR Metadata +#### Cleanup PGD Metadata -The cleaning of leftover BDR metadata is achieved as follows: +The cleaning of leftover PGD metadata is achieved as follows: -1. Drop the BDR node using `bdr.drop_node` +1. Drop the PGD node using `bdr.drop_node` 2. Fully stop and re-start PostgreSQL (important!). #### Cleanup of Replication Origins @@ -247,7 +245,7 @@ therefore included in the backup and in the restored instance. They are not removed automatically when dropping the BDR extension, because they are not explicitly recorded as its dependencies. -BDR creates one replication origin for each remote master node, to +PGD creates one replication origin for each remote master node, to track progress of incoming replication in a crash-safe way. Therefore we need to run: @@ -262,7 +260,7 @@ be listed as follows: SELECT * FROM pg_replication_origin; ``` -...and those created by BDR are easily recognized by their name, as in +...and those created by PGD are easily recognized by their name, as in the example shown above. #### Cleanup of Replication Slots @@ -283,4 +281,4 @@ you can add a `WHERE slot_name LIKE 'bdr%'` clause, but this is rarely useful. !!! Warning - Never run this on a live BDR node. + Never run this on a live PGD node. diff --git a/product_docs/docs/pgd/5/catalogs.mdx b/product_docs/docs/pgd/5/catalogs.mdx index 8545da73252..8dc9f3e02d5 100644 --- a/product_docs/docs/pgd/5/catalogs.mdx +++ b/product_docs/docs/pgd/5/catalogs.mdx @@ -120,7 +120,7 @@ This view lists DDL replication configuration as set up by current [DDL filters] ### `bdr.depend` -This table tracks internal object dependencies inside BDR catalogs. +This table tracks internal object dependencies inside PGD catalogs. ### `bdr.global_consensus_journal` @@ -160,12 +160,12 @@ their payloads. | origin_id | oid | ID of the node where the request originated | | req_payload | bytea | Payload of the request | | origin_node_name | name | Name of the node where the request originated | -| message_type_no | oid | ID of the BDR message type for the request | -| message_type | text | Name of the BDR message type for the request | -| message_payload | text | BDR message payload for the request | -| response_message_type_no | oid | ID of the BDR message type for the response | -| response_message_type | text | Name of the BDR message type for the response | -| response_payload | text | BDR message payload for the response | +| message_type_no | oid | ID of the PGD message type for the request | +| message_type | text | Name of the PGD message type for the request | +| message_payload | text | PGD message payload for the request | +| response_message_type_no | oid | ID of the PGD message type for the response | +| response_message_type | text | Name of the PGD message type for the response | +| response_payload | text | PGD message payload for the response | | response_errcode_no | text | SQLSTATE for the response | | response_errcode | text | Error code for the response | | response_message | text | Error message for the response | @@ -198,7 +198,7 @@ For monitoring usage, the [`bdr.global_locks`](#bdrglobal_locks) view is preferable because the visible rows in `bdr.global_lock` don't necessarily reflect all global locking activity. -Don't modify the contents of this table. It is an important BDR catalog. +Don't modify the contents of this table. It is an important PGD catalog. #### `bdr.global_lock` columns @@ -217,8 +217,8 @@ Don't modify the contents of this table. It is an important BDR catalog. ### `bdr.global_locks` A view containing active global locks on this node. The [`bdr.global_locks`](#bdrglobal_locks) view -exposes BDR's shared-memory lock state tracking, giving administrators greater -insight into BDR's global locking activity and progress. +exposes PGD's shared-memory lock state tracking, giving administrators greater +insight into PGD's global locking activity and progress. See [Monitoring global locks](monitoring/sql#monitoring-global-locks) for more information about global locking. @@ -339,7 +339,7 @@ A catalog view that stores user-defined information on network costs between nod | Name | Type | Description | | --------------- | ------- | ------------------------------------------ | -| node_group_name | name | Name of the BDR group | +| node_group_name | name | Name of the PGD group | | node_region1 | text | Node region name, from bdr.node_location | | node_region2 | text | Node region name, from bdr.node_location | | node_location1 | text | Node location name, from bdr.node_location | @@ -348,7 +348,7 @@ A catalog view that stores user-defined information on network costs between nod ### `bdr.node` -This table lists all the BDR nodes in the cluster. +This table lists all the PGD nodes in the cluster. #### `bdr.node` columns @@ -401,7 +401,7 @@ Currently configured conflict resolution for all known conflict types. ### `bdr.node_group` -This catalog table lists all the BDR node groups. +This catalog table lists all the PGD node groups. #### `bdr.node_group` columns @@ -424,14 +424,14 @@ This catalog table lists all the BDR node groups. ### `bdr.node_group_replication_sets` -A view showing default replication sets create for BDR groups. See also +A view showing default replication sets create for PGD groups. See also `bdr.replication_sets`. #### `bdr.node_group_replication_sets` columns | Name | Type | Description | | ------------------ | ------- | ------------------------------------------------------------------------------------ | -| node_group_name | name | Name of the BDR group | +| node_group_name | name | Name of the PGD group | | def_repset | name | Name of the default repset | | def_repset_ops | text\[] | Actions replicated by the default repset | | def_repset_ext | name | Name of the default "external" repset (usually same as def_repset) | @@ -459,7 +459,7 @@ A catalog view that stores user-defined information on node locations. | Name | Type | Description | | --------------- | ---- | --------------------------- | -| node_group_name | name | Name of the BDR group | +| node_group_name | name | Name of the PGD group | | node_id | oid | ID of the node | | node_region | text | User-supplied region name | | node_location | text | User-supplied location name | @@ -546,7 +546,7 @@ given node. ### `bdr.node_slots` This view contains information about replication slots used in the current -database by BDR. +database by PGD. See [Monitoring outgoing replication](monitoring/sql#monitoring-outgoing-replication) for guidance on the use and interpretation of this view's fields. @@ -556,13 +556,13 @@ for guidance on the use and interpretation of this view's fields. | Name | Type | Description | | ------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------- | | target_dbname | name | Database name on the target node | -| node_group_name | name | Name of the BDR group | -| node_group_id | oid | The OID of the BDR group | +| node_group_name | name | Name of the PGD group | +| node_group_id | oid | The OID of the PGD group | | origin_name | name | Name of the origin node | | target_name | name | Name of the target node | | origin_id | oid | The OID of the origin node | | target_id | oid | The OID of the target node | -| local_slot_name | name | Name of the replication slot according to BDR | +| local_slot_name | name | Name of the replication slot according to PGD | | slot_name | name | Name of the slot according to Postgres (same as above) | | is_group_slot | boolean | True if the slot is the node-group crash recovery slot for this node (see ["Group Replication Slot"]\(nodes#Group Replication Slot)) | | is_decoder_slot | boolean | Is this slot used by Decoding Worker | @@ -607,7 +607,7 @@ for guidance on the use and interpretation of this view's fields. ### `bdr.node_summary` -This view contains summary information about all BDR nodes known to the local +This view contains summary information about all PGD nodes known to the local node. #### `bdr.node_summary` columns @@ -615,14 +615,14 @@ node. | Name | Type | Description | | ---------------------- | ---- | --------------------------------------------------------------------------- | | node_name | name | Name of the node | -| node_group_name | name | Name of the BDR group the node is part of | +| node_group_name | name | Name of the PGD group the node is part of | | interface_connstr | text | Connection string to the node | | peer_state_name | text | Consistent state of the node in human readable form | | peer_target_state_name | text | State that the node is trying to reach (during join or promotion) | | node_seq_id | int4 | Sequence identifier of the node used for generating unique sequence numbers | | node_local_dbname | name | Database name of the node | | node_id | oid | The OID of the node | -| node_group_id | oid | The OID of the BDR node group | +| node_group_id | oid | The OID of the PGD node group | | node_kind_name | oid | Node kind name | ### `bdr.queue` @@ -689,7 +689,7 @@ instead checking the `bdr.ddl_replication` view. ### `bdr.replication_sets` -A view showing replication sets defined in the BDR group, even if they aren't +A view showing replication sets defined in the PGD group, even if they aren't currently used by any node. #### `bdr.replication_sets` columns @@ -707,7 +707,7 @@ currently used by any node. ### `bdr.schema_changes` -A simple view to show all the changes to schemas win BDR. +A simple view to show all the changes to schemas win PGD. #### `bdr.schema_changes` columns @@ -737,7 +737,7 @@ A view to see the allocation details for galloc sequences. ### `bdr.schema_changes` -A simple view to show all the changes to schemas in BDR. +A simple view to show all the changes to schemas in PGD. #### `bdr.schema_changes` columns @@ -768,7 +768,7 @@ A view to see the sequences allocated. ### `bdr.sequences` This view lists all sequences with their kind, excluding sequences -for internal BDR bookkeeping. +for internal PGD bookkeeping. #### `bdr.sequences` columns @@ -783,7 +783,7 @@ for internal BDR bookkeeping. Dynamic activity for each backend or worker process. This contains the same information as `pg_stat_activity`, except `wait_event` -is set correctly when the wait relates to BDR. +is set correctly when the wait relates to PGD. ### `bdr.stat_relation` @@ -853,7 +853,7 @@ is enabled. ### `bdr.subscription` -This catalog table lists all the subscriptions owned by the local BDR +This catalog table lists all the subscriptions owned by the local PGD node and their modes. #### `bdr.subscription` columns @@ -878,14 +878,14 @@ node and their modes. ### `bdr.subscription_summary` -This view contains summary information about all BDR subscriptions that the +This view contains summary information about all PGD subscriptions that the local node has to other nodes. #### `bdr.subscription_summary` columns | Name | Type | Description | | -------------------------- | ----------- | ---------------------------------------------------------------------------------------- | -| node_group_name | name | Name of the BDR group the node is part of | +| node_group_name | name | Name of the PGD group the node is part of | | sub_name | name | Name of the subscription | | origin_name | name | Name of the origin node | | target_name | name | Name of the target node (normally local node) | @@ -897,7 +897,7 @@ local node has to other nodes. | sub_origin_name | name | Replication origin name used by this subscription | | bdr_subscription_mode | char | Subscription mode | | subscription_status | text | Status of the subscription worker | -| node_group_id | oid | The OID of the BDR group the node is part of | +| node_group_id | oid | The OID of the PGD group the node is part of | | sub_id | oid | The OID of the subscription | | origin_id | oid | The OID of the origin node | | target_id | oid | The OID of the target node | @@ -988,10 +988,10 @@ An expanded view of `bdr.trigger` with columns that are easier to read. ### `bdr.workers` -Information about running BDR worker processes. +Information about running PGD worker processes. This can be joined with `bdr.stat_activity` using pid to get even more insight -into the state of BDR workers. +into the state of PGD workers. #### `bdr.workers` Columns @@ -1004,7 +1004,7 @@ into the state of BDR workers. ### `bdr.writers` -Specific information about BDR writer processes. +Specific information about PGD writer processes. #### `bdr.writers` columns @@ -1026,12 +1026,12 @@ Specific information about BDR writer processes. ### `bdr.worker_tasks` -The `bdr.worker_tasks` view shows BDR's current worker launch rate +The `bdr.worker_tasks` view shows PGD's current worker launch rate limiting state as well as some basic statistics on background worker launch and registration activity. Unlike the other views listed here, it isn't specific to the current database -and BDR node. State for all BDR nodes on the current PostgreSQL +and PGD node. State for all PGD nodes on the current PostgreSQL instance is shown. Join on the current database to filter it. `bdr.worker_tasks` doesn't track walsenders and output plugins. @@ -1195,13 +1195,13 @@ Uses `bdr.run_on_all_nodes` to gather Raft Consensus status from all nodes. ### `bdr.group_replslots_details` -Uses `bdr.run_on_all_nodes` to gather BDR slot information from all nodes. +Uses `bdr.run_on_all_nodes` to gather PGD slot information from all nodes. #### `bdr.group_replslots_details` columns | Name | Type | Description | | --------------- | -------- | ------------------------------------------------------------------------------- | -| node_group_name | text | Name of the BDR group | +| node_group_name | text | Name of the PGD group | | origin_name | text | Name of the origin node | | target_name | text | Name of the target node | | slot_name | text | Slot name on the origin node used by this subscription | @@ -1230,7 +1230,7 @@ Uses `bdr.run_on_all_nodes` to gather subscription status from all nodes. ### `bdr.group_versions_details` -Uses `bdr.run_on_all_nodes` to gather BDR information from all nodes. +Uses `bdr.run_on_all_nodes` to gather PGD information from all nodes. #### `bdr.group_versions_details` columns @@ -1239,7 +1239,7 @@ Uses `bdr.run_on_all_nodes` to gather BDR information from all nodes. | node_id | oid | Internal node ID | | node_name | name | Name of the node | | postgres_version | text | PostgreSQL version on the node | -| bdr_version | text | BDR version on the node | +| bdr_version | text | PGD version on the node | ## Internal catalogs and views @@ -1276,14 +1276,14 @@ An internal state table storing the type of each nonlocal sequence. We recommend ### `bdr.event_history` -Internal catalog table that tracks cluster membership events for a given BDR +Internal catalog table that tracks cluster membership events for a given PGD node. Specifically, it tracks: * Node joins (to the cluster) * Raft state changes (i.e. whenever the node changes its role in the consensus protocol - leader, follower or candidate to leader) - see [Monitoring Raft Consensus](monitoring/sql#monitoring-raft-consensus) * Whenever a worker has errored out (see [bdr.workers](#bdrworkers) -and [Monitoring BDR Replication Workers](monitoring/sql#monitoring-bdr-replication-workers)) +and [Monitoring PGD Replication Workers](monitoring/sql#monitoring-pgd-replication-workers)) | Name | Type | Description | | -------------- | ----------- | ----------------------------------------------------------------------------------- | diff --git a/product_docs/docs/pgd/5/cli/index.mdx b/product_docs/docs/pgd/5/cli/index.mdx index 7f2a2f9ad8e..44462edf138 100644 --- a/product_docs/docs/pgd/5/cli/index.mdx +++ b/product_docs/docs/pgd/5/cli/index.mdx @@ -10,19 +10,18 @@ directoryDefaults: description: "The PGD Command Line Interface (CLI) is a tool to manage your EDB Postgres Distributed cluster" --- -The EDB Postgres Distributed Command Line Interface (PGD CLI) is a tool to manage your EDB Postgres Distributed cluster. It allows you to run commands against EDB Postgres Distributed clusters. +The EDB Postgres Distributed Command Line Interface (PGD CLI) is a tool for managing your EDB Postgres Distributed cluster. It allows you to run commands against EDB Postgres Distributed clusters. -See the [Command reference](command_ref) for the available commands to inspect, manage, and get information on cluster resources. +See the [Command reference](command_ref) for the available commands to inspect, manage, and get information about cluster resources. See [Installing PGD CLI](installing_cli) for information about how Trusted Platform Architect deploys PGD CLI, how to install PGD CLI on a standalone server manually, and specifying connection strings. ## Requirements -The PGD CLI requires postgres superuser privileges to run. +The PGD CLI requires Postgres superuser privileges to run. ## Using the PGD CLI -`pgd` is the command name for the PGD command line interface. See [pgd](command_ref) in the Command reference for a description of the command options. See the following sections for sample use cases. - +`pgd` is the command name for the PGD command line interface. See [pgd](command_ref) in the command reference for a description of the command options. ## Specifying a configuration file @@ -39,6 +38,7 @@ Use the `--dsn` flag to pass a database connection string directly to a command. ```sh pgd show-nodes --dsn "host=bdr-a1 port=5432 dbname=bdrdb user=postgres " ``` + ## Specifying the output format The PGD CLI supports the following output formats: @@ -46,14 +46,15 @@ The PGD CLI supports the following output formats: | Format | Considerations | | ------- | -------------- | | tabular | Default format. Presents the data in tabular form.| -| json | Presents the raw data with no formatting. For some commands, the json output may show more data than shown in the tabular output such as extra fields and more detailed messages. | -| yaml | Same as json except field order is alphabetical. Experimental and may not be fully supported in future versions. | +| json | Presents the raw data with no formatting. For some commands, the json output might show more data than in the tabular output, such as extra fields and more detailed messages. | +| yaml | Same as json except field order is alphabetical. Experimental and might not be fully supported in future versions. | Use the `-o` or `--output` flag to change the default output format to json or yaml. For example: ```sh pgd show-nodes -o json ``` + ## Accessing the command line help To list the supported commands, enter: diff --git a/product_docs/docs/pgd/5/cli/installing_cli.mdx b/product_docs/docs/pgd/5/cli/installing_cli.mdx index a60971ef227..861b99a462f 100644 --- a/product_docs/docs/pgd/5/cli/installing_cli.mdx +++ b/product_docs/docs/pgd/5/cli/installing_cli.mdx @@ -4,7 +4,7 @@ navTitle: "Installing PGD CLI" --- -Trusted Platform Architect installs and configures PGD CLI on each PGD node, by default. If you wish to install PGD CLI on any non-PGD instance in the cluster, you simply attach the pgdcli role to that instance in TPA's configuration file before deploying. See [Trusted Postgres Architect](/tpa/latest/) for more information. +By default, Trusted Postgres Architect installs and configures PGD CLI on each PGD node. If you want to install PGD CLI on any non-PGD instance in the cluster, attach the pgdcli role to that instance in Trusted Postgres Architect's configuration file before deploying. See [Trusted Postgres Architect](/tpa/latest/) for more information. ## Installing manually @@ -15,16 +15,16 @@ You can manually install the PGD CLI on any Linux machine using `.deb` and `.rpm sudo apt-get install edb-pgd5-cli ``` -When the PGD CLI is configured by TPA, it connects automatically, but with a manual installation to a standalone EDB Postgres Distributed cluster you need to provide a connection string. +When Trusted Postgres Architect configures the PGD CLI, it connects automatically. With a manual installation to a standalone EDB Postgres Distributed cluster, you need to provide a connection string. ### Specifying database connection strings -You can use a configuration file to specify the database connection strings for your cluster. Alternatively, you can pass the connection string directly to a command. For details, see the [sample use case](./#passing-a-database-connection-string). +You can use a configuration file to specify the database connection strings for your cluster. Alternatively, you can pass the connection string directly to a command. For details, see the [sample use case](/pgd/latest/cli/#passing-a-database-connection-string). #### Using a configuration file -Use the `pgd-cli-config.yml` configuration file to specify the database connection string for your cluster. The configuration file must contain the database connection string for at least one BDR node in the cluster. The cluster name is optional and isn't validated. +Use the `pgd-cli-config.yml` configuration file to specify the database connection string for your cluster. The configuration file must contain the database connection string for at least one PGD node in the cluster. The cluster name is optional and isn't validated. For example: @@ -37,9 +37,9 @@ cluster: - "host=bdr-c1 port=5432 dbname=bdrdb user=postgres " ``` -By default, `pgd-cli-config.yml` is located in the `/etc/edb/pgd-cli` directory. In v1, the file was named `pgd-config.yml` and default location was `/etc/edb`. The PGD CLI searches for `pgd-cli-config.yml` in the following locations. Precedence order is high to low. +By default, `pgd-cli-config.yml` is located in the `/etc/edb/pgd-cli` directory. The PGD CLI searches for `pgd-cli-config.yml` in the following locations. Precedence order is high to low. 1. `/etc/edb/pgd-cli` (default) 2. `$HOME/.edb/pgd-cli` -If you rename the file or move it to another location, specify the new name and location using the optional `-f` or `--config-file` flag when entering a command. See the [sample use case](./#passing-a-database-connection-string). +If you rename the file or move it to another location, specify the new name and location using the optional `-f` or `--config-file` flag when entering a command. See the [sample use case](/pgd/latest/cli/#passing-a-database-connection-string). diff --git a/product_docs/docs/pgd/5/configuration.mdx b/product_docs/docs/pgd/5/configuration.mdx index 4c83ed9c3b9..8a34fdc71b5 100644 --- a/product_docs/docs/pgd/5/configuration.mdx +++ b/product_docs/docs/pgd/5/configuration.mdx @@ -67,9 +67,9 @@ limitations. in a similar way to [physical replication](https://www.postgresql.org/docs/11/runtime-config-wal.html#GUC-SYNCHRONOUS-COMMIT). - `synchronous_standby_names` — Same as above. -## BDR-specific settings +## PGD-specific settings -You can also set BDR-specific configuration settings. +You can also set PGD-specific configuration settings. Unless noted otherwise, you can set the values at any time. ### Conflict handling @@ -101,7 +101,7 @@ Unless noted otherwise, you can set the values at any time. See [PostgreSQL documentation](https://www.postgresql.org/docs/current/sql-altertable.html#SQL-CREATETABLE-REPLICA-IDENTITY) for more details. - BDR can't replicate `UPDATE` and `DELETE` operations on tables without a `PRIMARY KEY` + PGD can't replicate `UPDATE` and `DELETE` operations on tables without a `PRIMARY KEY` or `UNIQUE` constraint. The exception is when the replica identity for the table is `FULL`, either by table-specific configuration or by `bdr.default_replica_identity`. @@ -118,14 +118,14 @@ Unless noted otherwise, you can set the values at any time. This parameter can be set only by bdr_superuser or superuser roles. - Running DDL or calling BDR administration functions with + Running DDL or calling PGD administration functions with `bdr.ddl_replication = off` can create situations where replication stops until an administrator can intervene. See [DDL replication](ddl) for details. A `LOG`-level log message is emitted to the PostgreSQL server logs whenever `bdr.ddl_replication` is set to `off`. Additionally, a `WARNING-level` - message is written whenever replication of captured DDL commands or BDR + message is written whenever replication of captured DDL commands or PGD replication functions is skipped due to this setting. - `bdr.role_replication` — Automatically replicate ROLE commands across nodes @@ -177,7 +177,7 @@ Unless noted otherwise, you can set the values at any time. by global locks). Can be `DEBUG`, `LOG`, `WARNING` (default), or `ERROR`. Predictive checks are early validations for expected cluster state when doing certain operations. You can use them for those operations for fail early rather than wait for - timeouts. In global lock terms, BDR checks that there are enough nodes + timeouts. In global lock terms, PGD checks that there are enough nodes connected and withing reasonable lag limit for getting quorum needed by the global lock. @@ -193,7 +193,7 @@ Unless noted otherwise, you can set the values at any time. ### Generic replication - `bdr.writers_per_subscription` — Default number of writers per - subscription (in BDR, you can also change this with + subscription (in PGD, you can also change this with `bdr.alter_node_group_config` for a group). - `bdr.max_writers_per_subscription` — Maximum number of writers @@ -203,7 +203,7 @@ Unless noted otherwise, you can set the values at any time. Turning this off makes the whole transaction local only, which means the transaction isn't visible to logical decoding by - BDR and all other downstream targets of logical decoding. Data isn't + PGD and all other downstream targets of logical decoding. Data isn't transferred to any other node, including logical standby nodes. This parameter can be set only by the bdr_superuser or superuser roles. @@ -267,7 +267,7 @@ Unless noted otherwise, you can set the values at any time. - `WAIT` — Wait until the current local timestamp is no longer older than remote commit timestamp minus the `bdr.maximum_clock_skew`. -- `bdr.accept_connections` — Option to enable or disable connections to BDR. +- `bdr.accept_connections` — Option to enable or disable connections to PGD. Defaults to `on`. Requires `bdr_superuser` or PostgreSQL superuser. @@ -275,18 +275,18 @@ Unless noted otherwise, you can set the values at any time. ### `bdr.standby_slot_names` This option is typically used in failover configurations to ensure that the -failover-candidate streaming physical replicas for this BDR node +failover-candidate streaming physical replicas for this PGD node have received and flushed all changes before they ever become visible to subscribers. That guarantees that a commit can't vanish on failover to a standby for the provider. Replication slots whose names are listed in the comma-separated `bdr.standby_slot_names` list are treated specially by the walsender -on a BDR node. +on a PGD node. -BDR's logical replication walsenders ensures that all local changes +PGD's logical replication walsenders ensures that all local changes are sent and flushed to the replication slots in `bdr.standby_slot_names` -before the node sends those changes to any other BDR replication +before the node sends those changes to any other PGD replication clients. Effectively, it provides a synchronous replication barrier between the named list of slots and all other replication clients. @@ -311,14 +311,14 @@ of listed nodes are not keeping up. Monitoring is thus essential. Another use case where `bdr.standby_slot_names` is useful is when using a subscriber-only node, to ensure that it does not move ahead of -any of the regular BDR nodes. This can best be achieved by listing the -logical slots of all regular BDR peer nodes in combination with +any of the regular PGD nodes. This can best be achieved by listing the +logical slots of all regular PGD peer nodes in combination with setting `bdr.standby_slots_min_confirmed` to at least one. ### `bdr.standby_slots_min_confirmed` Controls how many of the `bdr.standby_slot_names` have to confirm before -we send data to BDR subscribers. +we send data to PGD subscribers. ### `bdr.writer_input_queue_size` @@ -340,7 +340,7 @@ KB. ### `bdr.min_worker_backoff_delay` -Rate limit BDR background worker launches by preventing a given worker +Rate limit PGD background worker launches by preventing a given worker from being relaunched more often than every `bdr.min_worker_backoff_delay` milliseconds. On repeated errors, the backoff increases exponentially with added jitter up to maximum of @@ -453,12 +453,12 @@ and receivers don't have a writer ID. ### Monitoring and logging -- `bdr.debug_level` — Defines the log level that BDR uses to write +- `bdr.debug_level` — Defines the log level that PGD uses to write its debug messages. The default value is `debug2`. If you want to see - detailed BDR debug output, set `bdr.debug_level = 'log'`. + detailed PGD debug output, set `bdr.debug_level = 'log'`. - `bdr.trace_level` — Similar to the above, this defines the log level - to use for BDR trace messages. Enabling tracing on all nodes of a + to use for PGD trace messages. Enabling tracing on all nodes of a EDB Postgres Distributed cluster might help EDB Support to diagnose issues. You can set this only at Postgres server start. @@ -496,14 +496,14 @@ and receivers don't have a writer ID. `INFO` message if the time exceeds this parameter. Default value of this parameter is 5000 ms. - `bdr.raft_group_max_connections` — The maximum number of connections - across all BDR groups for a Postgres server. These connections carry + across all PGD groups for a Postgres server. These connections carry bdr consensus requests between the groups' nodes. Default value of this parameter is 100 connections. You can set it only at Postgres server start. - `bdr.backwards_compatibility` — Specifies the version to be backward compatible to, in the same numerical format as used by `bdr.bdr_version_num`, e.g., `30618`. Enables exact behavior of a - former BDR version, even if this has generally unwanted effects. - Defaults to the current BDR version. Since this changes from release + former PGD version, even if this has generally unwanted effects. + Defaults to the current PGD version. Since this changes from release to release, we advise against explicit use in the configuration file unless the value is different from the current version. - `bdr.track_replication_estimates` — Track replication estimates in terms diff --git a/product_docs/docs/pgd/5/consistency/column-level-conflicts.mdx b/product_docs/docs/pgd/5/consistency/column-level-conflicts.mdx index 5d2736bdc5c..9860ad521ed 100644 --- a/product_docs/docs/pgd/5/consistency/column-level-conflicts.mdx +++ b/product_docs/docs/pgd/5/consistency/column-level-conflicts.mdx @@ -5,72 +5,41 @@ redirects: - /pgd/latest/bdr/column-level-conflicts/ --- -By default, conflicts are resolved at row level. That is, when changes -from two nodes conflict, we pick either the local or remote tuple and -discard the other one. For example, we might compare commit timestamps for -the two conflicting changes and keep the newer one. This ensures that all -nodes converge to the same result and establishes commit-order-like -semantics on the whole cluster. +By default, conflicts are resolved at row level. When changes from two nodes conflict, either the local or remote tuple is selected and the other is discarded. For example, commit timestamps for the two conflicting changes might be compared and the newer one kept. This approach ensures that all nodes converge to the same result and establishes commit-order-like semantics on the whole cluster. -However, in some cases it might be appropriate to resolve conflicts at -the column level rather than the row level. +However, in some cases it might be appropriate to resolve conflicts at the column level rather than the row level. -Consider a simple example, where we have a table t with two integer -columns a and b and a single row `(1,1)`. Assume that on one node -we execute: +Consider a simple example, in which table t has two integer columns a and b and a single row `(1,1)`. On one node execute: ```sql UPDATE t SET a = 100 ``` -On another node we concurrently (before receiving the preceding -`UPDATE`) execute: +On another node, before receiving the preceding `UPDATE`, concurrently execute: ```sql UPDATE t SET b = 100 ``` -This results in an `UPDATE-UPDATE` conflict. With the `update_if_newer` -conflict resolution, we compare the commit timestamps and keep the new -row version. Assuming the second node committed last, we end up with -`(1,100)`, effectively discarding the change to column a. +This sequence results in an `UPDATE-UPDATE` conflict. With the `update_if_newer` conflict resolution, the commit timestamps are compared, and the new row version is kept. Assuming the second node committed last, the result is `(1,100)`, which effectively discards the change to column a. -For many use cases, this is the desired and expected behavior, but for -some this might be an issue. Consider, for example, a multi-node cluster -where each part of the application is connected to a different node, -updating a dedicated subset of columns in a shared table. In that case, -the different components might step on each other's toes, overwriting -their changes. +For many use cases, this behavior is the desired and expected. However, for some use cases, this might be an issue. Consider, for example, a multi-node cluster where each part of the application is connected to a different node, updating a dedicated subset of columns in a shared table. In that case, the different components might conflict and overwrite changes. -For such use cases, it might be more appropriate to resolve conflicts on -a given table at the column level. To achieve that, BDR tracks -the timestamp of the last change for each column separately and uses that -to pick the most recent value (essentially `update_if_newer`). +For such use cases, it might be more appropriate to resolve conflicts on a given table at the column level. To achieve that, PGD tracks the timestamp of the last change for each column separately and uses that to pick the most recent value, essentially performing `update_if_newer`. -Applied to the previous example, we'll end up with `(100,100)` on both -nodes, despite neither of the nodes ever seeing such a row. +Applied to the previous example, the result is `(100,100)` on both nodes, despite neither of the nodes ever seeing such a row. -When thinking about column-level conflict resolution, it can be useful -to see tables as vertically partitioned, so that each update affects -data in only one slice. This approach eliminates conflicts between changes to -different subsets of columns. In fact, vertical partitioning can even -be a practical alternative to column-level conflict resolution. +When thinking about column-level conflict resolution, it can be useful to see tables as vertically partitioned, so that each update affects data in only one slice. This approach eliminates conflicts between changes to different subsets of columns. In fact, vertical partitioning can even be a practical alternative to column-level conflict resolution. -Column-level conflict resolution requires the table to have -`REPLICA IDENTITY FULL`. The `bdr.alter_table_conflict_detection` function does check -that and fails with an error otherwise. +Column-level conflict resolution requires the table to have `REPLICA IDENTITY FULL`. The `bdr.alter_table_conflict_detection` function checks that and fails with an error if this setting is missing. ## Enabling and disabling column-level conflict resolution -The column-level conflict resolution is managed by the -[bdr.alter_table_conflict_detection()](conflicts#bdralter_table_conflict_detection) -function. +The [bdr.alter_table_conflict_detection()](conflicts#bdralter_table_conflict_detection) function manages column-level conflict resolution. ### Example -To see how the `bdr.alter_table_conflict_detection()` is used, consider -this example that creates a trivial table `test_table` and then enables -column-level conflict resolution on it: +This example creates a table `test_table` and then enables column-level conflict resolution on it: ```sql db=# CREATE TABLE my_app.test_table (id SERIAL PRIMARY KEY, val INT); @@ -80,7 +49,8 @@ db=# ALTER TABLE my_app.test_table REPLICA IDENTITY FULL; ALTER TABLE db=# SELECT bdr.alter_table_conflict_detection( -db(# 'my_app.test_table'::regclass, 'column_modify_timestamp', 'cts'); +db(# 'my_app.test_table'::regclass, +db(# 'column_modify_timestamp', 'cts'); alter_table_conflict_detection -------------------------------- t @@ -88,26 +58,16 @@ db(# 'my_app.test_table'::regclass, 'column_modify_timestamp', 'cts'); db=# \d my_app.test_table ``` -The function adds a new `cts` column (as specified in -the function call), but it also created two triggers (`BEFORE INSERT` -and `BEFORE UPDATE`) that are responsible for maintaining timestamps -in the new column before each change. +The function adds a `cts` column as specified in the function call. It also creates two triggers (`BEFORE INSERT` and `BEFORE UPDATE`) that are responsible for maintaining timestamps in the new column before each change. -Also, the new column specifies `NOT NULL` -with a default value, which means that `ALTER TABLE ... ADD COLUMN` -doesn't perform a table rewrite. +The new column specifies `NOT NULL` with a default value, which means that `ALTER TABLE ... ADD COLUMN` doesn't perform a table rewrite. !!! Note - We discourage using columns with the `bdr.column_timestamps` data type - for other purposes as it can have negative effects. - For example, it switches the table to column-level conflict resolution, which doesn't - work correctly without the triggers. + Avoid using columns with the `bdr.column_timestamps` data type for other purposes, as doing so can have negative effects. For example, it switches the table to column-level conflict resolution, which doesn't work correctly without the triggers. ### Listing table with column-level conflict resolution -You can list tables having column-level conflict resolution enabled -with the following query. This query detects the presence of a column of -type `bdr.column_timestamp`. +You can list tables having column-level conflict resolution enabled with the following query. This query detects the presence of a column of type `bdr.column_timestamp`. ```sql SELECT nc.nspname, c.relname @@ -125,8 +85,7 @@ WHERE NOT pg_is_other_temp_schema(nc.oid) ### bdr.column_timestamps_create -This function creates column-level conflict resolution. It's called within -`column_timestamp_enable`. +This function creates column-level conflict resolution. It's called within `column_timestamp_enable`. #### Synopsis @@ -137,50 +96,28 @@ bdr.column_timestamps_create(p_source cstring, p_timestamp timestampstz) #### Parameters - `p_source` — The two options are `current` or `commit`. -- `p_timestamp` — Timestamp depends on the source chosen. If `commit`, - then `TIMESTAMP_SOURCE_COMMIT`. If `current`, then `TIMESTAMP_SOURCE_CURRENT`. +- `p_timestamp` — Timestamp depends on the source chosen. If `commit`, then `TIMESTAMP_SOURCE_COMMIT`. If `current`, then `TIMESTAMP_SOURCE_CURRENT`. ## DDL locking -When enabling or disabling column timestamps on a table, the code uses -DDL locking to ensure that there are no pending changes from before the -switch. This approach ensures we see only conflicts with timestamps in both -tuples or in neither of them. Otherwise, the code might unexpectedly see -timestamps in the local tuple and NULL in the remote one. It also -ensures that the changes are resolved the same way (column-level or -row-level) on all nodes. +When enabling or disabling column timestamps on a table, the code uses DDL locking to ensure that there are no pending changes from before the switch. This approach ensures only conflicts with timestamps in both tuples or in neither of them are seen. Otherwise, the code might unexpectedly see timestamps in the local tuple and NULL in the remote one. It also ensures that the changes are resolved the same way (column-level or row-level) on all nodes. ## Current versus commit timestamp An important decision is the timestamp to assign to modified columns. -By default, the timestamp assigned to modified columns is the current -timestamp, as if obtained from `clock_timestamp`. This is simple, and -for many cases it is perfectly correct (for example, when the conflicting rows -modify non-overlapping subsets of columns). +By default, the timestamp assigned to modified columns is the current timestamp, as if obtained from `clock_timestamp`. This is simple, and for many cases it is correct (for example, when the conflicting rows modify non-overlapping subsets of columns). It can, however, have various unexpected effects: -- The timestamp changes during statement execution, so if an `UPDATE` - affects multiple rows, each gets a slightly different timestamp. - This means that the effects of concurrent changes might get "mixed" in various - ways (depending on how exactly the changes performed on different - nodes interleave). +- The timestamp changes during statement execution. So, if an `UPDATE` affects multiple rows, each gets a slightly different timestamp. This means that the effects of concurrent changes might get "mixed" in various ways, depending on how the changes performed on different nodes interleave. -- The timestamp is unrelated to the commit timestamp, and using it to - resolve conflicts means that the result isn't equivalent to the commit order, - which means it likely can't be serialized. +- The timestamp is unrelated to the commit timestamp. Using it to resolve conflicts means that the result isn't equivalent to the commit order, which means it likely can't be serialized. !!! Note - We might add statement and transaction timestamps in the future, - which would address issues with mixing effects of concurrent statements or - transactions. Still, neither of these options can ever produce results - equivalent to commit order. + Statement and transaction timestamps might be added in the future, which will address issues with mixing effects of concurrent statements or transactions. Still, neither of these options can ever produce results equivalent to commit order. -It's possible to also use the actual commit timestamp, although this -feature is currently considered experimental. To use the commit timestamp, -set the last parameter to `true` when enabling column-level conflict -resolution: +You can also use the actual commit timestamp, although this feature is considered experimental. To use the commit timestamp, set the last parameter to `true` when enabling column-level conflict resolution: ```sql SELECT bdr.column_timestamps_enable('test_table'::regclass, 'cts', true); @@ -188,15 +125,11 @@ SELECT bdr.column_timestamps_enable('test_table'::regclass, 'cts', true); You can disable it using `bdr.column_timestamps_disable`. -Commit timestamps currently have restrictions that are -explained in [Notes](#notes). +Commit timestamps currently have restrictions that are explained in [Notes](#notes). ## Inspecting column timestamps -The column storing timestamps for modified columns is maintained -automatically by triggers. Don't modify it directly. It can -be useful to inspect the current timestamps value, for example, while -investigating how a conflict was resolved. +The column storing timestamps for modified columns is maintained by triggers. Don't modify it directly. It can be useful to inspect the current timestamps value, for example, while investigating how a conflict was resolved. Three functions are useful for this purpose: @@ -235,10 +168,7 @@ db=# select jsonb_pretty(cts::jsonb) from test_table; - `bdr.column_timestamps_resolve(bdr.column_timestamps, xid)` - This function updates the mapping with the commit timestamp for the attributes modified - by the most recent transaction (if it already committed). This - matters only when using the commit timestamp. For example, in this case, the last - transaction updated the second attribute (with `attnum = 2`): + This function updates the mapping with the commit timestamp for the attributes modified by the most recent transaction if it already committed. This matters only when using the commit timestamp. For example, in this case, the last transaction updated the second attribute (with `attnum = 2`): ```sql test=# select cts::jsonb from test_table; @@ -256,81 +186,44 @@ db=# select bdr.column_timestamps_resolve(cts, xmin)::jsonb from test_table; ## Handling column conflicts using CRDT data types -By default, column-level conflict resolution picks the value with -a higher timestamp and discards the other one. You can, however, -reconcile the conflict in different, more elaborate ways. For example, you can use -CRDT types that allow merging the conflicting values without -discarding any information. +By default, column-level conflict resolution picks the value with a higher timestamp and discards the other one. You can, however, reconcile the conflict in different, more elaborate ways. For example, you can use CRDT types that allow merging the conflicting values without discarding any information. ## Notes -- The attributes modified by an `UPDATE` are determined by comparing the - old and new row in a trigger. This means that if the attribute doesn't - change a value, it isn't detected as modified even if it's - explicitly set. For example, `UPDATE t SET a = a` doesn't mark `a` as - modified for any row. Similarly, `UPDATE t SET a = 1` doesn't mark - `a` as modified for rows that are already set to `1`. - -- For `INSERT` statements, we don't have any old row to compare the new - one to, so we consider all attributes to be modified and assign them - a new timestamp. This applies even for columns that weren't included - in the `INSERT` statement and received default values. We can detect - which attributes have a default value but can't know if - it was included automatically or specified explicitly. - - This effectively means column-level conflict resolution doesn't work - for `INSERT-INSERT` conflicts even if the `INSERT` statements specify - different subsets of columns. The newer row has - timestamps that are all newer than the older row. - -- By treating the columns independently, it's easy to violate constraints - in a way that isn't possible when all changes happen on the same - node. Consider, for example, a table like this: +- The attributes modified by an `UPDATE` are determined by comparing the old and new row in a trigger. This means that if the attribute doesn't change a value, it isn't detected as modified even if it's explicitly set. For example, `UPDATE t SET a = a` doesn't mark `a` as modified for any row. Similarly, `UPDATE t SET a = 1` doesn't mark `a` as modified for rows that are already set to `1`. + +- For `INSERT` statements, there's no old row to compare the new one to, so all attributes are considered to be modified, and they are assigned a new timestamp. This condition applies even for columns that weren't included in the `INSERT` statement and received default values. PGD can detect the attributes that have a default value but can't know if it was included automatically or specified explicitly. + + This situation effectively means column-level conflict resolution doesn't work for `INSERT-INSERT` conflicts even if the `INSERT` statements specify different subsets of columns. The newer row has timestamps that are all newer than the older row. + +- By treating the columns independently, it's easy to violate constraints in a way that isn't possible when all changes happen on the same node. Consider, for example, a table like this: ```sql CREATE TABLE t (id INT PRIMARY KEY, a INT, b INT, CHECK (a > b)); INSERT INTO t VALUES (1, 1000, 1); ``` -Assume one node does: + Assume one node does: ```sql UPDATE t SET a = 100; ``` -Another node concurrently does: + Another node concurrently does: ```sql UPDATE t SET b = 500; ``` - Each of those updates is valid when executed on the initial row and - so passes on each node. But when replicating to the other node, - the resulting row violates the `CHECK (A > b)` constraint, and the - replication stops until the issue is resolved manually. - -- The column storing timestamp mapping is managed automatically. Don't - specify or override the value in your queries, as it can result in - unpredictable effects. (We do ignore the value where possible anyway.) - -- The timestamp mapping is maintained by triggers, but the order in which - triggers execute matters. So if you have custom triggers that modify - tuples and are executed after the `pgl_clcd_` triggers, the modified - columns aren't detected correctly. - -- When using regular timestamps to order changes/commits, it's possible - that the conflicting changes have exactly the same timestamp (because - two or more nodes happened to generate the same timestamp). This risk - isn't unique to column-level conflict resolution, as it can happen - even for regular row-level conflict resolution. We use node id as a - tie-breaker in this situation (the higher node id wins), which ensures that the - same changes are applied on all nodes. - -- It is possible that there is a clock skew between different nodes. While it - can induce somewhat unexpected behavior (discarding seemingly newer - changes because the timestamps are inverted), you can manage clock skew between nodes - using the parameters `bdr.maximum_clock_skew` and - `bdr.maximum_clock_skew_action`. + Each of those updates is valid when executed on the initial row and so passes on each node. But when replicating to the other node, the resulting row violates the `CHECK (A > b)` constraint, and the replication stops until the issue is resolved manually. + +- The column storing timestamp mapping is managed automatically. Don't specify or override the value in your queries, as the results can be unpredictable. (The value is ignored where possible.) + +- The timestamp mapping is maintained by triggers, but the order in which triggers execute matters. So if you have custom triggers that modify tuples and are executed after the `pgl_clcd_` triggers, the modified columns aren't detected correctly. + +- When using regular timestamps to order changes or commits, the conflicting changes might have exactly the same timestamp because two or more nodes happened to generate the same timestamp. This risk isn't unique to column-level conflict resolution, as it can happen even for regular row-level conflict resolution. The node id is the tie breaker in this situation. The higher node id wins. This approach ensures that the same changes are applied on all nodes. + +- A clock skew can occur between different nodes. It can induce somewhat unexpected behavior, discarding seemingly newer changes because the timestamps are inverted. However, you can manage clock skew between nodes using the parameters `bdr.maximum_clock_skew` and `bdr.maximum_clock_skew_action`. ```sql SELECT bdr.alter_node_group_config('group', ignore_redundant_updates := false); diff --git a/product_docs/docs/pgd/5/consistency/conflicts.mdx b/product_docs/docs/pgd/5/consistency/conflicts.mdx index 18c3d01259f..e4b4aa2ed9d 100644 --- a/product_docs/docs/pgd/5/consistency/conflicts.mdx +++ b/product_docs/docs/pgd/5/consistency/conflicts.mdx @@ -4,76 +4,40 @@ redirects: - /pgd/latest/bdr/conflicts/ --- -EDB Postgres Distributed is an active/active or multi-master DBMS. If used -asynchronously, writes to the same or related rows from multiple different -nodes can result in data conflicts when using standard data types. - -Conflicts aren't errors. In most cases, they are events that PGD can detect -and resolve as they occur. Resolution depends on the -nature of the application and the meaning of the data, so it's important that -PGD provides the application a range of choices as to how to resolve conflicts. - -By default, conflicts are resolved at the row level. When changes from two -nodes conflict, either the local or remote tuple is picked and the other -is discarded. For example, the commit timestamps might be compared for the two conflicting -changes and the newer one kept. This approach ensures that all nodes converge to the -same result and establishes commit-order-like semantics on the whole cluster. - -Conflict handling is configurable, as described in [Conflict resolution](#conflict-resolution). -Conflicts can be detected and handled differently for each table using -conflict triggers, described in [Stream triggers](../striggers). - -Column-level conflict detection and resolution is available with BDR, -described in [CLCD](column-level-conflicts). - -By default, all conflicts are logged to `bdr.conflict_history`. If conflicts -are possible, then table owners must monitor for them and analyze how to -avoid them or make plans to handle them regularly as an application task. -The [LiveCompare](/livecompare/latest) tool is also available to scan regularly for divergence. - -Some clustering systems use distributed lock mechanisms to prevent -concurrent access to data. These can perform reasonably when servers are -very close to each other but can't support geographically distributed applications where -very low latency is critical for acceptable performance. - -Distributed locking is essentially a pessimistic approach. PGD -advocates an optimistic approach, which is to avoid conflicts where possible but allow -some types of conflicts to occur and resolve them when they arise. +EDB Postgres Distributed is an active/active or multi-master DBMS. If used asynchronously, writes to the same or related rows from multiple different nodes can result in data conflicts when using standard data types. + +Conflicts aren't errors. In most cases, they are events that PGD can detect and resolve as they occur. Resolving them depends on the nature of the application and the meaning of the data, so it's important for +PGD to provide the application a range of choices for how to resolve conflicts. + +By default, conflicts are resolved at the row level. When changes from two nodes conflict, PGD picks either the local or remote tuple and the discards the other. For example, the commit timestamps might be compared for the two conflicting changes and the newer one kept. This approach ensures that all nodes converge to the same result and establishes commit-order-like semantics on the whole cluster. + +Conflict handling is configurable, as described in [Conflict resolution](#conflict-resolution). PGD can detect conflicts and handle them differently for each table using conflict triggers, described in [Stream triggers](../striggers). + +Column-level conflict detection and resolution is available with PGD, described in [CLCD](column-level-conflicts). + +By default, all conflicts are logged to `bdr.conflict_history`. If conflicts are possible, then table owners must monitor for them and analyze how to avoid them or make plans to handle them regularly as an application task. The [LiveCompare](/livecompare/latest) tool is also available to scan regularly for divergence. + +Some clustering systems use distributed lock mechanisms to prevent concurrent access to data. These can perform reasonably when servers are very close to each other but can't support geographically distributed applications where very low latency is critical for acceptable performance. + +Distributed locking is essentially a pessimistic approach. PGD advocates an optimistic approach, which is to avoid conflicts where possible but allow some types of conflicts to occur and resolve them when they arise. ## How conflicts happen -Inter-node conflicts arise as a result of sequences of events that can't -happen if all the involved transactions happen concurrently on the same -node. Because the nodes exchange changes only after the transactions commit, -each transaction is individually valid on the node it committed on. It isn't -valid if applied on another node that did other conflicting work -at the same time. - -Since BDR replication essentially replays the transaction on the other nodes, -the replay operation can fail if there's a conflict between a transaction -being applied and a transaction that was committed on the receiving node. - -Most conflicts can't happen when all transactions run on a single -node because Postgres has inter-transaction communication mechanisms -to prevent it such as `UNIQUE` indexes, `SEQUENCE` operations, row and relation locking, and -`SERIALIZABLE` dependency tracking. All of these mechanisms are ways -to communicate between ongoing transactions to prevent undesirable concurrency +Inter-node conflicts arise as a result of sequences of events that can't happen if all the involved transactions happen concurrently on the same node. Because the nodes exchange changes only after the transactions commit, each transaction is individually valid on the node it committed on. It isn't +valid if applied on another node that did other conflicting work at the same time. + +Since PGD replication essentially replays the transaction on the other nodes, the replay operation can fail if there's a conflict between a transaction being applied and a transaction that was committed on the receiving node. + +Most conflicts can't happen when all transactions run on a single node because Postgres has inter-transaction communication mechanisms to prevent it. Examples of these mechanisms are `UNIQUE` indexes, `SEQUENCE` operations, row and relation locking, and `SERIALIZABLE` dependency tracking. All of these mechanisms are ways to communicate between ongoing transactions to prevent undesirable concurrency issues. -BDR doesn't have a distributed transaction manager or lock manager. -That's part of why it performs well with latency and network partitions. As -a result, transactions on different nodes execute entirely independently -from each other when using the default, lazy replication. Less independence -between nodes can avoid conflicts altogether, which is why BDR also offers -Eager Replication for when this is important. +PGD doesn't have a distributed transaction manager or lock manager. That's part of why it performs well with latency and network partitions. As a result, transactions on different nodes execute entirely independently from each other when using the default, which is lazy replication. Less independence between nodes can avoid conflicts altogether, which is why PGD also offers eager replication for when this is important. ## Types of conflict ### PRIMARY KEY or UNIQUE conflicts -The most common conflicts are row conflicts, where two operations affect a -row with the same key in ways they can't on a single node. BDR can -detect most of those and applies the `update_if_newer` conflict resolver. +The most common conflicts are row conflicts, where two operations affect a row with the same key in ways they can't on a single node. PGD can detect most of those and applies the `update_if_newer` conflict resolver. Row conflicts include: @@ -84,79 +48,46 @@ Row conflicts include: - `INSERT` versus `DELETE` - `DELETE` versus `DELETE` -The view `bdr.node_conflict_resolvers` provides information on how -conflict resolution is currently configured for all known conflict types. +The view `bdr.node_conflict_resolvers` provides information on how conflict resolution is currently configured for all known conflict types. #### INSERT/INSERT conflicts -The most common conflict, `INSERT`/`INSERT`, arises where `INSERT` operations on two -different nodes create a tuple with the same `PRIMARY KEY` values (or if no -`PRIMARY KEY` exists, the same values for a single `UNIQUE` constraint). +The most common conflict, `INSERT`/`INSERT`, arises where `INSERT` operations on two different nodes create a tuple with the same `PRIMARY KEY` values (or if no `PRIMARY KEY` exists, the same values for a single `UNIQUE` constraint). -BDR handles this situation by retaining the most recently inserted tuple of the two -according to the originating node's timestamps, unless this behavior is overridden by a -user-defined conflict handler. +PGD handles this situation by retaining the most recently inserted tuple of the two according to the originating node's timestamps. (A user-defined conflict handler can override this behavior.) -This conflict generates the `insert_exists` conflict type, which is by -default resolved by choosing the newer (based on commit time) row and keeping -only that one (`update_if_newer` resolver). You can configure other resolvers. -See [Conflict resolution](#conflict-resolution) for details. +This conflict generates the `insert_exists` conflict type, which is by default resolved by choosing the newer row, based on commit time, and keeping only that one (`update_if_newer` resolver). You can configure other resolvers. See [Conflict resolution](#conflict-resolution) for details. -To resolve this conflict type, you can also use column-level conflict -resolution and user-defined conflict triggers. +To resolve this conflict type, you can also use column-level conflict resolution and user-defined conflict triggers. -You can effectively eliminate this type of conflict by using -[global sequences](../sequences). +You can effectively eliminate this type of conflict by using [global sequences](../sequences). #### INSERT operations that violate multiple UNIQUE constraints -An `INSERT`/`INSERT` conflict can violate more than one `UNIQUE` constraint -(of which one might be the `PRIMARY KEY`). If a new row violates more than -one `UNIQUE` constraint and that results in a conflict against more than one -other row, then the apply of the replication change produces a -`multiple_unique_conflicts` conflict. +An `INSERT`/`INSERT` conflict can violate more than one `UNIQUE` constraint, of which one might be the `PRIMARY KEY`. If a new row violates more than one `UNIQUE` constraint and that results in a conflict against more than one other row, then applying the replication change produces a `multiple_unique_conflicts` conflict. -In case of such a conflict, you must remove some rows for replication -to continue. Depending on the resolver setting for `multiple_unique_conflicts`, -the apply process either exits with error, skips the incoming row, or deletes -some of the rows. The deletion tries to -preserve the row with the correct `PRIMARY KEY` and delete the others. +In case of such a conflict, you must remove some rows for replication to continue. Depending on the resolver setting for `multiple_unique_conflicts`, the apply process either exits with error, skips the incoming row, or deletes some of the rows. The deletion tries to preserve the row with the correct `PRIMARY KEY` and delete the others. !!! Warning - In case of multiple rows conflicting this way, if the result of conflict - resolution is to proceed with the insert operation, some of the data - is always deleted. + In case of multiple rows conflicting this way, if the result of conflict resolution is to proceed with the insert operation, some of the data is always deleted. -It's also possible to define a different behavior using a conflict trigger. +You can also define a different behavior using a conflict trigger. #### UPDATE/UPDATE conflicts -Where two concurrent `UPDATE` operations on different nodes change the same tuple -(but not its `PRIMARY KEY`), an `UPDATE`/`UPDATE` conflict can occur on replay. +Where two concurrent `UPDATE` operations on different nodes change the same tuple but not its `PRIMARY KEY`, an `UPDATE`/`UPDATE` conflict can occur on replay. -These can generate different conflict kinds based on the configuration and -situation. If the table is configured with [row version conflict detection](#row-version-conflict-detection), -then the original (key) row is compared with the local row. -If they're different, the `update_differing` conflict is generated. -When using [Origin conflict detection](#origin-conflict-detection), -the origin of the row is checked (the origin is the node that the current -local row came from). If that changed, the `update_origin_change` conflict -is generated. In all other cases, the `UPDATE` is normally applied without -generating a conflict. +These can generate different conflict kinds based on the configuration and situation. If the table is configured with [row version conflict detection](#row-version-conflict-detection), then the original (key) row is compared with the local row. If they're different, the `update_differing` conflict is generated. When using [origin conflict detection](#origin-conflict-detection), the origin of the row is checked. (The origin is the node that the current local row came from.) If that changed, the `update_origin_change` conflict is generated. In all other cases, the `UPDATE` is normally applied without generating a conflict. Both of these conflicts are resolved the same way as `insert_exists`, described in [INSERT/INSERT conflicts](#insertinsert-conflicts). #### UPDATE conflicts on the PRIMARY KEY -BDR can't currently perform conflict resolution where the `PRIMARY KEY` -is changed by an `UPDATE` operation. You can update the primary -key, but you must ensure that no conflict with existing values is possible. +PGD can't currently perform conflict resolution where the `PRIMARY KEY` is changed by an `UPDATE` operation. You can update the primary key, but you must ensure that no conflict with existing values is possible. -Conflicts on the update of the primary key are [Divergent conflicts](#divergent-conflicts) and -require manual intervention. +Conflicts on the update of the primary key are [divergent conflicts](#divergent-conflicts) and require manual intervention. -Updating a primary key is possible in Postgres, but there are -issues in both Postgres and BDR. +Updating a primary key is possible in Postgres, but there are issues in both Postgres and PGD. A simple schema provides an example that explains: @@ -171,13 +102,13 @@ Updating the Primary Key column is possible, so this SQL succeeds: UPDATE pktest SET pk=2 WHERE pk=1; ``` -However, suppose there are multiple rows in the table: +However, suppose the table has multiple rows: ```sql INSERT INTO pktest VALUES (3,3); ``` -Some UPDATEs succeed: +Some UPDATE operations succeed: ```sql UPDATE pktest SET pk=4 WHERE pk=3; @@ -190,7 +121,7 @@ SELECT * FROM pktest; (2 rows) ``` -Other UPDATEs fail with constraint errors: +Other UPDATE operations fail with constraint errors: ```sql UPDATE pktest SET pk=4 WHERE pk=2; @@ -198,11 +129,9 @@ ERROR: duplicate key value violates unique constraint "pktest_pkey" DETAIL: Key (pk)=(4) already exists ``` -So for Postgres applications that update primary keys, be -careful to avoid runtime errors, even without BDR. +So for Postgres applications that update primary keys, be careful to avoid runtime errors, even without PGD. -With BDR, the situation becomes more complex if UPDATEs are -allowed from multiple locations at same time. +With PGD, the situation becomes more complex if UPDATE operations are allowed from multiple locations at same time. Executing these two changes concurrently works: @@ -218,10 +147,7 @@ SELECT * FROM pktest; (2 rows) ``` -Executing these next two changes concurrently causes -a divergent error, since both changes are accepted. But applying -the changes on the other node results in -`update_missing` conflicts. +Executing these next two changes concurrently causes a divergent error, since both changes are accepted. But applying the changes on the other node results in `update_missing` conflicts. ```sql node1: UPDATE pktest SET pk=1 WHERE pk = 3; @@ -250,254 +176,146 @@ SELECT * FROM pktest; You can identify and resolve this situation using [LiveCompare](/livecompare/latest). -Concurrent conflicts present problems. Executing these two changes -concurrently isn't easy to resolve: +Concurrent conflicts present problems. Executing these two changes concurrently isn't easy to resolve: ```sql node1: UPDATE pktest SET pk=6, val=8 WHERE pk = 5; node2: UPDATE pktest SET pk=6, val=9 WHERE pk = 5; ``` -Both changes are applied locally, causing a divergence between -the nodes. But then apply on the target fails on both nodes with -a duplicate key-value violation error, which causes the replication -to halt and requires manual resolution. +Both changes are applied locally, causing a divergence between the nodes. But the apply on the target fails on both nodes with a duplicate key-value violation error. This error causes the replication to halt and requires manual resolution. -This duplicate key violation error can now be avoided, -and replication doesn't break if you set the conflict_type -`update_pkey_exists` to `skip`, `update`, or `update_if_newer`. This -can still lead to divergence depending on the nature of the update. +You can avoid this duplicate key violation error, and replication doesn't break, if you set the conflict_type `update_pkey_exists` to `skip`, `update`, or `update_if_newer`. This approach can still lead to divergence depending on the nature of the update. -You can avoid divergence in cases where the same -old key is being updated by the same new key concurrently by setting -`update_pkey_exists` to `update_if_newer`. However, in certain situations, -divergence occurs even with `update_if_newer`, namely when two different -rows both are updated concurrently to the same new primary key. +You can avoid divergence in cases where the same old key is being updated by the same new key concurrently by setting `update_pkey_exists` to `update_if_newer`. However, in certain situations, +divergence occurs even with `update_if_newer`, namely when two different rows both are updated concurrently to the same new primary key. -As a result, we recommend strongly against allowing primary key UPDATE operations -in your applications, especially with BDR. If parts -of your application change primary keys, then to avoid concurrent -changes, make those changes using Eager Replication. +As a result, we recommend strongly against allowing primary key UPDATE operations in your applications, especially with PGD. If parts of your application change primary keys, then to avoid concurrent +changes, make those changes using eager replication. !!! Warning - In case the conflict resolution of `update_pkey_exists` conflict results - in update, one of the rows is always deleted. + In case the conflict resolution of `update_pkey_exists` conflict results in update, one of the rows is always deleted. #### UPDATE operations that violate multiple UNIQUE constraints -Like [INSERT operations that violate multiple UNIQUE constraints](#insert-operations-that-violate-multiple-unique-constraints), where an incoming -`UPDATE` violates more than one `UNIQUE` index (or the `PRIMARY KEY`), BDR -raises a `multiple_unique_conflicts` conflict. +Like [INSERT operations that violate multiple UNIQUE constraints](#insert-operations-that-violate-multiple-unique-constraints), when an incoming `UPDATE` violates more than one `UNIQUE` index (or the `PRIMARY KEY`), PGD raises a `multiple_unique_conflicts` conflict. -BDR supports deferred unique constraints. If a transaction can commit on the -source, then it applies cleanly on target, unless it sees conflicts. -However, a deferred primary key can't be used as a REPLICA IDENTITY, so -the use cases are already limited by that and the warning about using -multiple unique constraints. +PGD supports deferred unique constraints. If a transaction can commit on the source, then it applies cleanly on target, unless it sees conflicts. However, you can't use a deferred primary key as a REPLICA IDENTITY, so the use cases are already limited by that and the warning about using multiple unique constraints. #### UPDATE/DELETE conflicts -It's possible for one node to update a row that another node simultaneously -deletes. In this case an `UPDATE`/`DELETE` conflict can occur on replay. - -If the deleted row is still detectable (the deleted row wasn't removed by `VACUUM`), -the `update_recently_deleted` conflict is generated. By default the -`UPDATE` is skipped, but you can configure the resolution for this. -See [Conflict resolution](#conflict-resolution) for details. - -The deleted row can be cleaned up from the database by the time the `UPDATE` -is received in case the local node is lagging behind in replication. In this -case, BDR can't differentiate between `UPDATE`/`DELETE` -conflicts and [INSERT/UPDATE conflicts](#insertupdate-conflicts) and generates the -`update_missing` conflict. - -Another type of conflicting `DELETE` and `UPDATE` is a `DELETE` -that comes after the row was updated locally. In this situation, the -outcome depends on the type of conflict detection used. When using the -default, [origin conflict detection](#origin-conflict-detection), no conflict is detected at all, -leading to the `DELETE` being applied and the row removed. If you enable -[row version conflict detection](#row-version-conflict-detection), a `delete_recently_updated` conflict is -generated. The default resolution for this conflict type is to apply the -`DELETE` and remove the row, but you can configure this or this can be handled by -a conflict trigger. +One node can update a row that another node deletes at ths same time. In this case an `UPDATE`/`DELETE` conflict can occur on replay. + +If the deleted row is still detectable (the deleted row wasn't removed by `VACUUM`), the `update_recently_deleted` conflict is generated. By default, the `UPDATE` is skipped, but you can configure the resolution for this. See [Conflict resolution](#conflict-resolution) for details. + +The database can clean up the deleted row by the time the `UPDATE` is received in case the local node is lagging behind in replication. In this case, PGD can't differentiate between `UPDATE`/`DELETE` conflicts and [INSERT/UPDATE conflicts](#insertupdate-conflicts). It generates the `update_missing` conflict. + +Another type of conflicting `DELETE` and `UPDATE` is a `DELETE` that comes after the row was updated locally. In this situation, the outcome depends on the type of conflict detection used. When using the +default, [origin conflict detection](#origin-conflict-detection), no conflict is detected, leading to the `DELETE` being applied and the row removed. If you enable [row version conflict detection](#row-version-conflict-detection), a `delete_recently_updated` conflict is generated. The default resolution for this conflict type is to apply the `DELETE` and remove the row. However, you can configure this or a conflict trigger can handled it. #### INSERT/UPDATE conflicts -When using the default asynchronous mode of operation, a node might receive an -`UPDATE` of a row before the original `INSERT` was received. This can -happen only with three or more nodes being active (see [Conflicts with three or more nodes](#conflicts-with-three-or-more-nodes)). +When using the default asynchronous mode of operation, a node might receive an `UPDATE` of a row before the original `INSERT` was received. This can happen only when three or more nodes are active (see [Conflicts with three or more nodes](#conflicts-with-three-or-more-nodes)). -When this happens, the `update_missing` conflict is generated. The default -conflict resolver is `insert_or_skip`, though you can use `insert_or_error` or `skip` -instead. Resolvers that do insert-or-action first -try to `INSERT` a new row based on data -from the `UPDATE` when possible (when the whole row was received). For the -reconstruction of the row to be possible, the table either needs to have +When this happens, the `update_missing` conflict is generated. The default conflict resolver is `insert_or_skip`, though you can use `insert_or_error` or `skip` instead. Resolvers that do insert-or-action first try to `INSERT` a new row based on data from the `UPDATE` when possible (when the whole row was received). For reconstructing the row to be possible, the table either needs to have `REPLICA IDENTITY FULL` or the row must not contain any toasted data. See [TOAST support details](#toast-support-details) for more info about toasted data. #### INSERT/DELETE conflicts -Similar to the `INSERT`/`UPDATE` conflict, the node might also receive a -`DELETE` operation on a row for which it didn't yet receive an `INSERT`. This -is again possible only with three or more nodes set up (see [Conflicts with three or more nodes](#conflicts-with-three-or-more-nodes)). +Similar to the `INSERT`/`UPDATE` conflict, the node might also receive a `DELETE` operation on a row for which it didn't yet receive an `INSERT`. This is again possible only with three or more nodes set up (see [Conflicts with three or more nodes](#conflicts-with-three-or-more-nodes)). -BDR can't currently detect this conflict type. The `INSERT` operation -doesn't generate any conflict type and the `INSERT` is applied. +PGD can't currently detect this conflict type. The `INSERT` operation doesn't generate any conflict type, and the `INSERT` is applied. -The `DELETE` operation always generates a `delete_missing` conflict, which -is by default resolved by skipping the operation. +The `DELETE` operation always generates a `delete_missing` conflict, which is by default resolved by skipping the operation. #### DELETE/DELETE conflicts -A `DELETE`/`DELETE` conflict arises when two different nodes concurrently -delete the same tuple. +A `DELETE`/`DELETE` conflict arises when two different nodes concurrently delete the same tuple. -This always generates a `delete_missing` conflict, which is by default -resolved by skipping the operation. +This scenario always generates a `delete_missing` conflict, which is by default resolved by skipping the operation. -This conflict is harmless since both `DELETE` operations have the same effect. One -of them can be safely ignored. +This conflict is harmless since both `DELETE` operations have the same effect. You can safely ignroe one of them. #### Conflicts with three or more nodes -If one node inserts a row that is then replayed to a second node and updated -there, a third node can receive the `UPDATE` from the second node before it -receives the `INSERT` from the first node. This scenario is an `INSERT`/`UPDATE` conflict. +If one node inserts a row that's then replayed to a second node and updated there, a third node can receive the `UPDATE` from the second node before it receives the `INSERT` from the first node. This scenario is an `INSERT`/`UPDATE` conflict. -These conflicts are handled by discarding the `UPDATE`. This can lead to -different data on different nodes. These are [divergent conflicts](#divergent conflicts). +These conflicts are handled by discarding the `UPDATE`, which can lead to different data on different nodes. These are [divergent conflicts](#divergent-conflicts). -This conflict type can happen only with three or more masters, of which at -least two must be actively writing. +This conflict type can happen only with three or more masters. At least two masters must be actively writing. -Also, the replication lag from node 1 to node 3 must be high enough to -allow the following sequence of actions: +Also, the replication lag from node 1 to node 3 must be high enough to allow the following sequence of actions: 1. node 2 receives INSERT from node 1 2. node 2 performs UPDATE 3. node 3 receives UPDATE from node 2 4. node 3 receives INSERT from node 1 -Using `insert_or_error` (or in some cases the `insert_or_skip` conflict resolver -for the `update_missing` conflict type) is a viable mitigation strategy for -these conflicts. However, enabling this option opens the door for -`INSERT`/`DELETE` conflicts: +Using `insert_or_error` (or in some cases the `insert_or_skip` conflict resolver for the `update_missing` conflict type) is a viable mitigation strategy for these conflicts. However, enabling this option opens the door for `INSERT`/`DELETE` conflicts: 1. node 1 performs UPDATE 2. node 2 performs DELETE 3. node 3 receives DELETE from node 2 4. node 3 receives UPDATE from node 1, turning it into an INSERT -If these are problems, we recommend tuning freezing settings for a table -or database so that they are correctly detected as `update_recently_deleted`. +If these are problems, we recommend tuning freezing settings for a table or database so that they're correctly detected as `update_recently_deleted`. -Another alternative is to use [Eager Replication](eager) to prevent these conflicts. +Another alternative is to use [eager replication](eager) to prevent these conflicts. -`INSERT`/`DELETE` conflicts can also occur with three or more nodes. -Such a conflict is identical to `INSERT`/`UPDATE` except with the -`UPDATE` replaced by a `DELETE`. This can result in a `delete_missing` +`INSERT`/`DELETE` conflicts can also occur with three or more nodes. Such a conflict is identical to `INSERT`/`UPDATE` except with the `UPDATE` replaced by a `DELETE`. This can result in a `delete_missing` conflict. -BDR could choose to make each INSERT into a check-for-recently -deleted, as occurs with an `update_missing` conflict. However, the -cost of doing this penalizes the majority of users, so at this time -it simply logs `delete_missing`. +PGD could choose to make each `INSERT` into a check-for-recently deleted, as occurs with an `update_missing` conflict. However, the cost of doing this penalizes the majority of users, so at this time it instead logs `delete_missing`. -Later releases will automatically resolve `INSERT`/`DELETE` anomalies -via rechecks using [LiveCompare](/latest/livecompare) when `delete_missing` conflicts occur. -These can be performed manually by applications by checking -the `bdr.conflict_history_summary` view. +Future releases will automatically resolve `INSERT`/`DELETE` anomalies by way of rechecks using [LiveCompare](/latest/livecompare) when `delete_missing` conflicts occur. Applications can perform these manually by checking the `bdr.conflict_history_summary` view. These conflicts can occur in two main problem use cases: - `INSERT` followed rapidly by a `DELETE`, as can be used in queuing applications - Any case where the primary key identifier of a table is reused -Neither of these cases is common. We recommend not replicating -the affected tables if these problem use cases occur. +Neither of these cases is common. We recommend not replicating the affected tables if these problem use cases occur. -BDR has problems with the latter case because BDR relies on the -uniqueness of identifiers to make replication work correctly. +PGD has problems with the latter case because PGD relies on the uniqueness of identifiers to make replication work correctly. -Applications that insert, delete, and -then later reuse the same unique identifiers can cause difficulties. -This is known as the [ABA problem](https://en.wikipedia.org/wiki/ABA_problem). BDR has no way of knowing whether -the rows are the current row, the last row, or much older rows. +Applications that insert, delete, and then later reuse the same unique identifiers can cause difficulties. This is known as the [ABA problem](https://en.wikipedia.org/wiki/ABA_problem). PGD has no way of knowing whether the rows are the current row, the last row, or much older rows. -Unique identifier reuse is also a business problem, since it is -prevents unique identification over time, which prevents auditing, -traceability, and sensible data quality. Applications don't need -to reuse unique identifiers. +Unique identifier reuse is also a business problem, since it is prevents unique identification over time, which prevents auditing, traceability, and sensible data quality. Applications don't need to reuse unique identifiers. -Any identifier reuse that occurs in the time interval it takes for -changes to pass across the system causes difficulties. Although that -time might be short in normal operation, down nodes can extend that +Any identifier reuse that occurs in the time interval it takes for changes to pass across the system causes difficulties. Although that time might be short in normal operation, down nodes can extend that interval to hours or days. -We recommend that applications don't reuse unique identifiers, but if they -do, take steps to avoid reuse within a period of less than a year. +We recommend that applications don't reuse unique identifiers. If they do, take steps to avoid reuse in less than a year. This problem doesn't occur in applications that use sequences or UUIDs. ### Foreign key constraint conflicts -Conflicts between a remote transaction being applied and existing local data -can also occur for `FOREIGN KEY` (FK) constraints. - -BDR applies changes with `session_replication_role = 'replica'`, so foreign -keys aren't rechecked when applying changes. -In an active/active environment, this can result in FK violations if deletes -occur to the referenced table at the same time as inserts into the referencing -table. This is similar to an `INSERT`/`DELETE` conflict. - -In single-master Postgres, any `INSERT`/`UPDATE` that refers to a value in the -referenced table must wait for `DELETE` operations to finish before they can gain -a row-level lock. If a `DELETE` removes a referenced value, then the `INSERT`/`UPDATE` fails the FK check. - -In multi-master BDR. there are no inter-node row-level locks. An `INSERT` on -the referencing table doesn't wait behind a `DELETE` on the referenced table, -so both actions can occur concurrently. Thus an `INSERT`/`UPDATE` on one node -on the referencing table can use a value at the same time as a `DELETE` -on the referenced table on another node. This then results in a value -in the referencing table that's no longer present in the referenced -table. - -In practice, this occurs if the `DELETE` operations occurs on referenced tables -in separate transactions from `DELETE` operations on referencing tables. This isn't -a common operation. - -In a parent-child relationship such as Orders -> OrderItems, it isn't typical to -do this. It's more likely to mark an OrderItem as canceled than to remove it -completely. For reference/lookup data, it's unusual to completely -remove entries at the same time as using those same values for new fact data. - -While there's a possibility of dangling FKs, the risk of this in general -is very low and so BDR doesn't impose a generic solution to cover this case. -Once you understand the situation in which this occurs, two solutions are -possible. - -The first solution is to restrict the use of FKs to closely -related entities that are generally modified from only one node at a time, are -infrequently modified, or where the modification's concurrency is -application-mediated. This avoids any FK violations at the application -level. - -The second solution is to add triggers to protect against this case using -the BDR-provided functions `bdr.ri_fkey_trigger()` and -`bdr.ri_fkey_on_del_trigger()`. When called as `BEFORE` triggers, these -functions use `FOREIGN KEY` information to avoid FK anomalies by -setting referencing columns to NULL, much as if you had a SET NULL constraint. -This rechecks all FKs in one trigger, so you need to add only one -trigger per table to prevent FK violation. - -As an example, suppose you have two tables: Fact and RefData. Fact has an FK that -references RefData. Fact is the referencing table and RefData is the referenced -table. You need to add one trigger to each table. - -Add a trigger that sets columns to NULL in Fact if the referenced row -in RefData was already deleted. +Conflicts between a remote transaction being applied and existing local data can also occur for `FOREIGN KEY` (FK) constraints. + +PGD applies changes with `session_replication_role = 'replica'`, so foreign keys aren't rechecked when applying changes. In an active/active environment, this situation can result in FK violations if deletes occur to the referenced table at the same time as inserts into the referencing table. This scenario is similar to an `INSERT`/`DELETE` conflict. + +In single-master Postgres, any `INSERT`/`UPDATE` that refers to a value in the referenced table must wait for `DELETE` operations to finish before they can gain a row-level lock. If a `DELETE` removes a referenced value, then the `INSERT`/`UPDATE` fails the FK check. + +In multi-master PGD. there are no inter-node row-level locks. An `INSERT` on the referencing table doesn't wait behind a `DELETE` on the referenced table, so both actions can occur concurrently. Thus an `INSERT`/`UPDATE` on one node on the referencing table can use a value at the same time as a `DELETE` +on the referenced table on another node. The result, then, is a value in the referencing table that's no longer present in the referenced table. + +In practice, this situation occurs if the `DELETE` operations occurs on referenced tables in separate transactions from `DELETE` operations on referencing tables, which isn't a common operation. + +In a parent-child relationship such as Orders -> OrderItems, it isn't typical to do this. It's more likely to mark an OrderItem as canceled than to remove it completely. For reference/lookup data, it's unusual to completely remove entries at the same time as using those same values for new fact data. + +While dangling FKs are possible, the risk of this in general is very low. Thus PGD doesn't impose a generic solution to cover this case. Once you understand the situation in which this occurs, two solutions are possible. + +The first solution is to restrict the use of FKs to closely related entities that are generally modified from only one node at a time, are infrequently modified, or where the modification's concurrency is +application mediated. This approach avoids any FK violations at the application level. + +The second solution is to add triggers to protect against this case using the PGD-provided functions `bdr.ri_fkey_trigger()` and `bdr.ri_fkey_on_del_trigger()`. When called as `BEFORE` triggers, these functions use `FOREIGN KEY` information to avoid FK anomalies by setting referencing columns to NULL, much as if you had a SET NULL constraint. This approach rechecks all FKs in one trigger, so you need to add only one trigger per table to prevent FK violation. + +As an example, suppose you have two tables: Fact and RefData. Fact has an FK that references RefData. Fact is the referencing table, and RefData is the referenced table. You need to add one trigger to each table. + +Add a trigger that sets columns to NULL in Fact if the referenced row in RefData was already deleted: ```sql CREATE TRIGGER bdr_replica_fk_iu_trg @@ -509,8 +327,7 @@ ALTER TABLE fact ENABLE REPLICA TRIGGER bdr_replica_fk_iu_trg; ``` -Add a trigger that sets columns to NULL in Fact at the time a DELETE occurs -on the RefData table. +Add a trigger that sets columns to NULL in Fact at the time a DELETE occurs on the RefData table: ```sql CREATE TRIGGER bdr_replica_fk_d_trg @@ -526,230 +343,120 @@ Adding both triggers avoids dangling foreign keys. ### TRUNCATE conflicts -`TRUNCATE` behaves similarly to a `DELETE` of all rows but performs this -action by physically removing the table data rather than row-by-row -deletion. As a result, row-level conflict handling isn't available, so -`TRUNCATE` commands don't generate conflicts with other DML actions, -even when there's a clear conflict. +`TRUNCATE` behaves similarly to a `DELETE` of all rows but performs this action by physically removing the table data rather than row-by-row deletion. As a result, row-level conflict handling isn't available, so `TRUNCATE` commands don't generate conflicts with other DML actions, even when there's a clear conflict. -As a result, the ordering of replay can cause divergent changes if -another DML is executed concurrently on other nodes to the `TRUNCATE`. +As a result, the ordering of replay can cause divergent changes if another DML is executed concurrently on other nodes to the `TRUNCATE`. You can take one of the following actions: -- Ensure `TRUNCATE` isn't executed alongside other concurrent DML. - Rely on [LiveCompare](/livecompare/latest) to highlight any such inconsistency. +- Ensure `TRUNCATE` isn't executed alongside other concurrent DML. Rely on [LiveCompare](/livecompare/latest) to highlight any such inconsistency. -- Replace `TRUNCATE` with a `DELETE` statement with no `WHERE` clause. - This approach is likely to have very poor performance on - larger tables. +- Replace `TRUNCATE` with a `DELETE` statement with no `WHERE` clause. This approach is likely to have poor performance on larger tables. -- Set `bdr.truncate_locking = 'on'` to set the `TRUNCATE` command’s - locking behavior. This setting determines whether `TRUNCATE` obeys the `bdr.ddl_locking` - setting. This - isn't the default behavior for `TRUNCATE` since it requires all nodes - to be up. This configuration might not be possible or wanted in all cases. +- Set `bdr.truncate_locking = 'on'` to set the `TRUNCATE` command’s locking behavior. This setting determines whether `TRUNCATE` obeys the `bdr.ddl_locking` setting. This isn't the default behavior for `TRUNCATE` since it requires all nodes to be up. This configuration might not be possible or wanted in all cases. ### Exclusion constraint conflicts -BDR doesn't support exclusion constraints and prevents their creation. +PGD doesn't support exclusion constraints and prevents their creation. -If an existing standalone database is converted to a BDR database, then -drop all exclusion constraints manually. +If an existing standalone database is converted to a PGD database, then drop all exclusion constraints manually. -In a distributed asynchronous system, you can't ensure that no -set of rows that violate the constraint exists, because all transactions -on different nodes are fully isolated. Exclusion constraints lead to -replay deadlocks where replay can't progress from any node to any -other node because of exclusion constraint violations. +In a distributed asynchronous system, you can't ensure that no set of rows that violate the constraint exists because all transactions on different nodes are fully isolated. Exclusion constraints lead to replay deadlocks where replay can't progress from any node to any other node because of exclusion constraint violations. -If you force BDR to create an exclusion constraint, or you don't drop -existing ones when converting a standalone database to BDR, -expect replication to break. To get it to progress again, remove or alter the -local tuples that an incoming remote tuple conflicts with so that the remote -transaction can be applied. +If you force PGD to create an exclusion constraint, or you don't drop existing ones when converting a standalone database to PGD, expect replication to break. To get it to progress again, remove or alter the +local tuples that an incoming remote tuple conflicts with so that the remote transaction can be applied. ### Data conflicts for roles and tablespace differences -Conflicts can also arise where nodes have global (Postgres-system-wide) -data, like roles, that differ. This can result in operations—mainly -`DDL`—that can run successfully and commit on one node but then -fail to apply to other nodes. +Conflicts can also arise where nodes have global (Postgres-system-wide) data, like roles, that differ. This conflict can result in operations—mainly `DDL`—that can run successfully and commit on one node but then fail to apply to other nodes. -For example, node1 might have a user named fred, and that user wasn't -created on node2. If fred on node1 creates a table, the table is -replicated with its owner set to fred. When the DDL command is applied to -node2, the DDL fails because there's no user named fred. This failure -emits an error in the Postgres logs. +For example, node1 might have a user named fred, and that user wasn't created on node2. If fred on node1 creates a table, the table is replicated with its owner set to fred. When the DDL command is applied to +node2, the DDL fails because there's no user named fred. This failure generates an error in the Postgres logs. -Administrator intervention is required to resolve this conflict -by creating the user fred in the database where BDR is running. -You can set `bdr.role_replication = on` to resolve this in future. +Administrator intervention is required to resolve this conflict by creating the user fred in the database where PGD is running. You can set `bdr.role_replication = on` to resolve this in future. ### Lock conflicts and deadlock aborts -Because BDR writer processes operate much like normal user sessions, they're -subject to the usual rules around row and table locking. This can sometimes -lead to BDR writer processes waiting on locks held by user transactions or -even by each other. +Because PGD writer processes operate much like normal user sessions, they're subject to the usual rules around row and table locking. This can sometimes lead to PGD writer processes waiting on locks held by user transactions or even by each other. Relevant locking includes: - Explicit table-level locking (`LOCK TABLE ...`) by user sessions - Explicit row-level locking (`SELECT ... FOR UPDATE/FOR SHARE`) by user sessions -- Implicit locking because of row `UPDATE`, `INSERT`, or `DELETE` operations, either - from local activity or from replication from other nodes - -A BDR writer process can deadlock with a user -transaction, where the user transaction is waiting on a lock held -by the writer process and vice versa. Two writer processes can also -deadlock with each other. Postgres's deadlock detector steps in and -terminates one of the problem transactions. If the BDR writer process is -terminated, it retries and generally succeeds. - -All these issues are transient and generally require no administrator -action. If a writer process is stuck for a long time behind a lock -on an idle user session, the administrator can terminate -the user session to get replication flowing again, but this is -no different from a user holding a long lock that impacts another -user session. - -Use of the [log_lock_waits](https://www.postgresql.org/docs/current/runtime-config-logging.html#GUC-LOG-LOCK-WAITS) -facility in Postgres can help identify locking related replay stalls. +- Implicit locking because of row `UPDATE`, `INSERT`, or `DELETE` operations, either from local activity or from replication from other nodes + +A PGD writer process can deadlock with a user transaction, where the user transaction is waiting on a lock held by the writer process and vice versa. Two writer processes can also deadlock with each other. Postgres's deadlock detector steps in and terminates one of the problem transactions. If the PGD writer process is terminated, it retries and generally succeeds. + +All these issues are transient and generally require no administrator action. If a writer process is stuck for a long time behind a lock on an idle user session, the administrator can terminate the user session to get replication flowing again. However, this is no different from a user holding a long lock that impacts another user session. + +Use of the [log_lock_waits](https://www.postgresql.org/docs/current/runtime-config-logging.html#GUC-LOG-LOCK-WAITS) facility in Postgres can help identify locking related replay stalls. ### Divergent conflicts -Divergent conflicts arise when data that should be the same on different -nodes differs unexpectedly. Divergent conflicts should not occur, but not -all such conflicts can be reliably prevented at the time of writing. +Divergent conflicts arise when data that should be the same on different nodes differs unexpectedly. Divergent conflicts shouldn't occur, but not all such conflicts can be reliably prevented at the time of writing. -Changing the `PRIMARY KEY` of a row can lead to a divergent conflict if -another node changes the key of the same row before all nodes have replayed -the change. Avoid changing primary keys, or change them only on one designated -node. +Changing the `PRIMARY KEY` of a row can lead to a divergent conflict if another node changes the key of the same row before all nodes have replayed the change. Avoid changing primary keys, or change them only on one designated node. -Divergent conflicts involving row data generally require administrator -action to manually adjust the data on one of the nodes to be consistent -with the other one. Such conflicts don't arise so long as you use BDR as documented -and avoid settings or functions marked as unsafe. +Divergent conflicts involving row data generally require administrator action to manually adjust the data on one of the nodes to be consistent with the other one. Such conflicts don't arise so long as you use PGD as documented and avoid settings or functions marked as unsafe. -The administrator must manually resolve such conflicts. You might need to use the -advanced options such as `bdr.ddl_replication` and `bdr.ddl_locking` depending on the -nature of the conflict. However, careless use of -these options can make things much worse and create a conflict that generic instructions can't address. +The administrator must manually resolve such conflicts. You might need to use the advanced options such as `bdr.ddl_replication` and `bdr.ddl_locking` depending on the nature of the conflict. However, careless use of these options can make things much worse and create a conflict that generic instructions can't address. ### TOAST support details -Postgres uses out-of-line storage for larger columns called -[TOAST](https://www.postgresql.org/docs/current/storage-toast.html). +Postgres uses out-of-line storage for larger columns called [TOAST](https://www.postgresql.org/docs/current/storage-toast.html). -The TOAST values handling in logical decoding (which BDR is built on top of) -and logical replication is different from inline data stored as part of the -main row in the table. +The TOAST values handling in logical decoding (which PGD is built on top of) and logical replication is different from inline data stored as part of the main row in the table. -The TOAST value is logged into the transaction log (WAL) only if the value -has changed. This can cause problems, especially when handling UPDATE conflicts -because an `UPDATE` statement that didn't change a value of a toasted column -produces a row without that column. As mentioned in -[INSERT/UPDATE conflicts](#insertupdate-conflicts), BDR reports an error if an `update_missing` -conflict is resolved using `insert_or_error` and there are missing TOAST columns. +The TOAST value is logged into the transaction log (WAL) only if the value changed. This can cause problems, especially when handling UPDATE conflicts, because an `UPDATE` statement that didn't change a value of a toasted column produces a row without that column. As mentioned in [INSERT/UPDATE conflicts](#insertupdate-conflicts), PGD reports an error if an `update_missing` conflict is resolved using `insert_or_error` and there are missing TOAST columns. -However, there are more subtle issues than this one in case of concurrent -workloads with asynchronous replication (Eager transactions aren't affected). -Imagine, for example, the following workload on a EDB Postgres Distributed cluster with three nodes called -A, B, and C: +However, more subtle issues than this one occur in case of concurrent workloads with asynchronous replication. (Eager transactions aren't affected.) Imagine, for example, the following workload on an EDB Postgres Distributed cluster with three nodes called A, B, and C: 1. On node A: txn A1 does an UPDATE SET col1 = 'toast data...' and commits first. 2. On node B: txn B1 does UPDATE SET other_column = 'anything else'; and commits after A1. 3. On node C: the connection to node A lags behind. -4. On node C: txn B1 is applied first, it misses the TOASTed column in col1, - but gets applied without conflict. +4. On node C: txn B1 is applied first, it misses the TOASTed column in col1, but gets applied without conflict. 5. On node C: txn A1 conflicts (on update_origin_change) and is skipped. 6. Node C misses the toasted data from A1 forever. -This scenario isn't usually a problem when using BDR. (It is when using -either built-in logical replication or plain pglogical for multi-master.) -BDR adds its own logging of TOAST columns when it detects a local UPDATE -to a row that recently replicated a TOAST column modification and the local -UPDATE isn't modifying the TOAST. Thus BDR prevents any inconsistency for -toasted data across different nodes. This situation causes increased WAL logging -when updates occur on multiple nodes (that is, when origin changes for a tuple). -Additional WAL overhead is zero if all updates are made from a single node, -as is normally the case with BDR AlwaysOn architecture. +This scenario isn't usually a problem when using PGD. (It is when using either built-in logical replication or plain pglogical for multi-master.) PGD adds its own logging of TOAST columns when it detects a local `UPDATE` to a row that recently replicated a TOAST column modification and the local +`UPDATE` isn't modifying the TOAST. Thus PGD prevents any inconsistency for toasted data across different nodes. This situation causes increased WAL logging when updates occur on multiple nodes, that is, when origin changes for a tuple. Additional WAL overhead is zero if all updates are made from a single node, +as is normally the case with PGD AlwaysOn architecture. !!! Note - Running `VACUUM FULL` or `CLUSTER` on just the TOAST table without - also doing same on the main table removes metadata needed for the - extra logging to work. This means that, for a short period of time after - such a statement, the protection against these concurrency issues isn't - be present. + Running `VACUUM FULL` or `CLUSTER` on just the TOAST table without doing same on the main table removes metadata needed for the extra logging to work. This means that, for a short period after such a statement, the protection against these concurrency issues isn't present. !!! Warning - The additional WAL logging of TOAST is done using the `BEFORE UPDATE` - trigger on standard Postgres. This trigger must be sorted alphabetically - last (based on trigger name) among all `BEFORE UPDATE` triggers on the - table. It's prefixed with `zzzz_bdr_` to make this easier, but make sure - you don't create any trigger with a name that sorts after it. Otherwise - you won't have the protection against the concurrency issues. - -For the `insert_or_error` conflict resolution, the use of -`REPLICA IDENTITY FULL` is, however, still required. - -None of these problems associated with toasted columns affect tables with -`REPLICA IDENTITY FULL`. This setting always logs a toasted value as -part of the key since the whole row is considered to be part of the key. BDR -can reconstruct the new row, filling the -missing data from the key row. As a result, using -`REPLICA IDENTITY FULL` can increase WAL size significantly. + The additional WAL logging of TOAST is done using the `BEFORE UPDATE` trigger on standard Postgres. This trigger must be sorted alphabetically last based on trigger name among all `BEFORE UPDATE` triggers on the table. It's prefixed with `zzzz_bdr_` to make this easier, but make sure + you don't create any trigger with a name that sorts after it. Otherwise you won't have the protection against the concurrency issues. + +For the `insert_or_error` conflict resolution, the use of `REPLICA IDENTITY FULL` is still required. + +None of these problems associated with toasted columns affect tables with `REPLICA IDENTITY FULL`. This setting always logs a toasted value as part of the key since the whole row is considered to be part of the key. PGD can reconstruct the new row, filling the missing data from the key row. As a result, using `REPLICA IDENTITY FULL` can increase WAL size significantly. ## Avoiding or tolerating conflicts In most cases, you can design the application to avoid or tolerate conflicts. -Conflicts can happen only if things are happening at the same time on -multiple nodes. The simplest way to avoid conflicts is to only ever write -to one node or to only ever write to a specific row in a specific way from -one specific node at a time. - -This happens naturally in many applications. For example, many -consumer applications allow data to be changed only by the owning user, such as -changing the default billing address on your account. Such data changes seldom -have update conflicts. - -You might make a change just before a node goes down, so the -change seems to be lost. You might then make the same change again, -leading to two updates on different nodes. When the down node comes back up, -it tries to send the older change to other nodes, but it's rejected -because the last update of the data is kept. - -For `INSERT`/`INSERT` conflicts, use [global sequences](../sequences) -to prevent this type of conflict. - -For applications that assign relationships between objects, such as a room -booking application, applying `update_if_newer` might not give an acceptable -business outcome. That is, it isn't useful to confirm to two people separately -that they have booked the same room. The simplest resolution is to use Eager -Replication to ensure that only one booking succeeds. More complex ways -might be possible depending on the application. For example, you can assign 100 seats -to each node and allow those to be booked by a writer on that node. But if -none are available locally, use a distributed locking scheme or Eager -Replication once most seats are reserved. - -Another technique for ensuring certain types of updates occur only from one -specific node is to route different types of transactions through -different nodes. For example: +Conflicts can happen only if things are happening at the same time on multiple nodes. The simplest way to avoid conflicts is to only ever write to one node or to only ever write to a specific row in a specific way from one specific node at a time. + +This avoidance happens naturally in many applications. For example, many consumer applications allow only the owning user to change data, such as changing the default billing address on an account. Such data changes seldom have update conflicts. + +You might make a change just before a node goes down, so the change seems to be lost. You might then make the same change again, leading to two updates on different nodes. When the down node comes back up, it tries to send the older change to other nodes. It's rejected because the last update of the data is kept. + +For `INSERT`/`INSERT` conflicts, use [global sequences](../sequences) to prevent this type of conflict. + +For applications that assign relationships between objects, such as a room-booking application, applying `update_if_newer` might not give an acceptable business outcome. That is, it isn't useful to confirm to two people separately that they have booked the same room. The simplest resolution is to use eager replication to ensure that only one booking succeeds. More complex ways might be possible depending on the application. For example, you can assign 100 seats to each node and allow those to be booked by a writer on that node. But if none are available locally, use a distributed locking scheme or eager replication after most seats are reserved. + +Another technique for ensuring certain types of updates occur only from one specific node is to route different types of transactions through different nodes. For example: - Receiving parcels on one node but delivering parcels using another node -- A service application where orders are input on one node, work is - prepared on a second node, and then served back to customers on another +- A service application where orders are input on one node and work is prepared on a second node and then served back to customers on another -Frequently, the best course is to allow conflicts to occur and -design the application to work with BDR's conflict resolution -mechanisms to cope with the conflict. +Frequently, the best course is to allow conflicts to occur and design the application to work with PGD's conflict resolution mechanisms to cope with the conflict. ## Conflict detection -BDR provides these mechanisms for conflict detection: +PGD provides these mechanisms for conflict detection: - [Origin conflict detection](#origin-conflict-detection) (default) - [Row version conflict detection](#row-version-conflict-detection) @@ -757,58 +464,30 @@ BDR provides these mechanisms for conflict detection: ### Origin conflict detection -Origin conflict detection uses and relies on commit timestamps as -recorded on the node the transaction originates from. This -requires clocks to be in sync to work correctly or to be within a -tolerance of the fastest message between two nodes. If this -isn't the case, conflict resolution tends to favor the node that's -further ahead. You can manage clock skew between nodes using the -parameters `bdr.maximum_clock_skew` and `bdr.maximum_clock_skew_action`. +Origin conflict detection uses and relies on commit timestamps as recorded on the node the transaction originates from. This requires clocks to be in sync to work correctly or to be within a tolerance of the fastest message between two nodes. If this isn't the case, conflict resolution tends to favor the node that's further ahead. You can manage clock skew between nodes using the parameters `bdr.maximum_clock_skew` and `bdr.maximum_clock_skew_action`. Row origins are available only if `track_commit_timestamp = on`. -Conflicts are initially detected based on whether the replication -origin changed, so conflict triggers are called in -situations that might turn out not to be conflicts. Hence, this -mechanism isn't precise, since it can generate false-positive conflicts. +Conflicts are first detected based on whether the replication origin changed, so conflict triggers are called in situations that might not turn out to be conflicts. Hence, this mechanism isn't precise, since it can generate false-positive conflicts. -Origin info is available only up to the point where a row is frozen. -Updates arriving for a row after it was frozen don't raise -a conflict so are applied in all cases. This is the normal case -when adding a new node by `bdr_init_physical`, so raising conflicts -causes many false-positive results in that case. +Origin info is available only up to the point where a row is frozen. Updates arriving for a row after it was frozen don't raise a conflict so are applied in all cases. This is the normal case when adding a new node by `bdr_init_physical`, so raising conflicts causes many false-positive results in that case. -When a node that was offline reconnects and -begins sending data changes, this can cause divergent -errors if the newly arrived updates are older than the -frozen rows that they update. Inserts and deletes aren't affected by this situation. +A node that was offline that reconnects and begins sending data changes can cause divergent +errors if the newly arrived updates are older than the frozen rows that they update. Inserts and deletes aren't affected by this situation. -We suggest that you don't leave down nodes for extended outages, -as discussed in [Node restart and down node recovery](../nodes). +We suggest that you don't leave down nodes for extended outages, as discussed in [Node restart and down node recovery](../nodes). -On EDB Postgres Extended Server and EDB Postgres Advanced Server, BDR -holds back the freezing of rows while a node is down. This mechanism handles -this situation gracefully so you don't need to change parameter settings. +On EDB Postgres Extended Server and EDB Postgres Advanced Server, PGD holds back the freezing of rows while a node is down. This mechanism handles this situation gracefully so you don't need to change parameter settings. -On other variants of Postgres, you might need to manage this situation with -some care. +On other variants of Postgres, you might need to manage this situation with some care. -Freezing normally occurs when a row being vacuumed is older than -`vacuum_freeze_min_age` xids from the current xid, which means that you -need to configure suitably high values for these parameters: +Freezing normally occurs when a row being vacuumed is older than `vacuum_freeze_min_age` xids from the current xid, which means that you need to configure suitably high values for these parameters: - `vacuum_freeze_min_age` - `vacuum_freeze_table_age` - `autovacuum_freeze_max_age` -Choose values based on the transaction rate, giving -a grace period of downtime before removing any conflict data -from the database node. For example, when `vacuum_freeze_min_age` is set to 500 million, a node performing -1000 TPS can be down for just over 5.5 days before conflict -data is removed. -The CommitTS data structure takes on-disk space of 5 GB with -that setting, so lower transaction rate systems can benefit from -lower settings. +Choose values based on the transaction rate, giving a grace period of downtime before removing any conflict data from the database node. For example, when `vacuum_freeze_min_age` is set to 500 million, a node performing 1000 TPS can be down for just over 5.5 days before conflict data is removed. The CommitTS data structure takes on-disk space of 5 GB with that setting, so lower transaction rate systems can benefit from lower settings. Initially recommended settings are: @@ -825,46 +504,30 @@ vacuum_freeze_table_age = 900000000 Note that: - You can set `autovacuum_freeze_max_age` only at node start. -- You can set `vacuum_freeze_min_age`, so using a - low value freezes rows early and can result in conflicts being - ignored. You can also set `autovacuum_freeze_min_age` and `toast.autovacuum_freeze_min_age` - for individual tables. -- Running the CLUSTER or VACUUM FREEZE commands also - freezes rows early and can result in conflicts being ignored. +- You can set `vacuum_freeze_min_age`, so using a low value freezes rows early and can result in conflicts being ignored. You can also set `autovacuum_freeze_min_age` and `toast.autovacuum_freeze_min_age` for individual tables. +- Running the `CLUSTER` or `VACUUM FREEZE` commands also freezes rows early and can result in conflicts being ignored. ### Row version conflict detection -Alternatively, BDR provides the option to use row versioning and make -conflict detection independent of the nodes' system clock. +PGD provides the option to use row versioning and make conflict detection independent of the nodes' system clock. -Row version conflict detection requires that you enable three things. If any of these -steps aren't performed correctly then [origin conflict detection](#origin-conflict-detection) is used. +Row version conflict detection requires that you enable three things. If any of these steps aren't performed correctly then [origin conflict detection](#origin-conflict-detection) is used. -1. `check_full_tuple` must be enabled for the BDR node group. +- Enable `check_full_tuple` or the PGD node group. -2. `REPLICA IDENTITY FULL` must be enabled on all tables that use - row version conflict detection. +- Enable `REPLICA IDENTITY FULL` on all tables that use row version conflict detection. -3. Row Version Tracking must be enabled on the table by using - `bdr.alter_table_conflict_detection`. This function adds a column - (with a name you specify) and an `UPDATE` trigger that manages the new - column value. The column is created as `INTEGER` type. +- Enable row version tracking on the table by using `bdr.alter_table_conflict_detection`. This function adds a column with a name you specify and an `UPDATE` trigger that manages the new column value. The column is created as `INTEGER` type. -Although the counter is incremented only on `UPDATE`, this technique allows -conflict detection for both `UPDATE` and `DELETE`. +Although the counter is incremented only on `UPDATE`, this technique allows conflict detection for both `UPDATE` and `DELETE`. -This approach resembles Lamport timestamps and fully prevents -the ABA problem for conflict detection. +This approach resembles Lamport timestamps and fully prevents the ABA problem for conflict detection. !!! Note - The row-level conflict resolution is still handled based on the - [conflict resolution](#conflict-resolution) configuration even with row versioning. The way - the row version is generated is useful only for detecting conflicts. - Don't rely on it as authoritative information about which + The row-level conflict resolution is still handled based on the [conflict resolution](#conflict-resolution) configuration even with row versioning. The way the row version is generated is useful only for detecting conflicts. Don't rely on it as authoritative information about which version of row is newer. -To determine the current conflict resolution strategy used for a specific -table, refer to the column `conflict_detection` of the view `bdr.tables`. +To determine the current conflict resolution strategy used for a specific table, refer to the column `conflict_detection` of the view `bdr.tables`. ### bdr.alter_table_conflict_detection @@ -882,95 +545,57 @@ bdr.alter_table_conflict_detection(relation regclass, - `relation` — Name of the relation for which to set the new conflict detection method. - `method` — The conflict detection method to use. -- `column_name` — The column to use for storing the column detection data. - This can be skipped, in which case the column name is chosen based - on the conflict detection method. The `row_origin` method doesn't require an - extra column for metadata storage. +- `column_name` — The column to use for storing the column detection data. This can be skipped, in which case the column name is chosen based on the conflict detection method. The `row_origin` method doesn't require an extra column for metadata storage. The recognized methods for conflict detection are: -- `row_origin` — Origin of the previous change made on the tuple (see - [Origin conflict detection](#origin-conflict-detection)). This is the only method supported that - doesn't require an extra column in the table. +- `row_origin` — Origin of the previous change made on the tuple (see [Origin conflict detection](#origin-conflict-detection)). This is the only method supported that doesn't require an extra column in the table. - `row_version` — Row version column (see [Row version conflict detection](#row-version-conflict-detection)). -- `column_commit_timestamp` — Per-column commit timestamps (described in - [CLCD](column-level-conflicts)). -- `column_modify_timestamp` — Per-column modification timestamp (described in - [CLCD](column-level-conflicts)). +- `column_commit_timestamp` — Per-column commit timestamps (described in [CLCD](column-level-conflicts)). +- `column_modify_timestamp` — Per-column modification timestamp (described in [CLCD](column-level-conflicts)). #### Notes -For more information about the difference between `column_commit_timestamp` -and `column_modify_timestamp` conflict detection methods, see -[Current versus commit timestamp](column-level-conflicts#current-versus-commit-timestamp). +For more information about the difference between `column_commit_timestamp` and `column_modify_timestamp` conflict detection methods, see [Current versus commit timestamp](column-level-conflicts#current-versus-commit-timestamp). -This function uses the same replication mechanism as `DDL` statements. This -means the replication is affected by the [ddl filters](../repsets#ddl-replication-filtering) -configuration. +This function uses the same replication mechanism as `DDL` statements. This means the replication is affected by the [ddl filters](../repsets#ddl-replication-filtering) configuration. -The function takes a `DML` global lock on the relation for which -column-level conflict resolution is being enabled. +The function takes a `DML` global lock on the relation for which column-level conflict resolution is being enabled. -This function is transactional. You can roll back the effects back with the -`ROLLBACK` of the transaction, and the changes are visible to the current -transaction. +This function is transactional. You can roll back the effects with the `ROLLBACK` of the transaction, and the changes are visible to the current transaction. -The `bdr.alter_table_conflict_detection` function can be executed only by -the owner of the `relation`, unless `bdr.backwards_compatibility` is -set to 30618 or below. +Only the owner of the `relation` can execute the `bdr.alter_table_conflict_detection` function unless `bdr.backwards_compatibility` is set to 30618 or less. !!! Warning - When changing the conflict detection method from one that - uses an extra column to store metadata, that column is dropped. + When changing the conflict detection method from one that uses an extra column to store metadata, that column is dropped. !!! Warning - This function disables CAMO (together with a warning, as - long as these aren't disabled with `bdr.camo_enable_client_warnings`). + This function disables CAMO and gives a warning, as long as warnings aren't disabled with `bdr.camo_enable_client_warnings`. ### List of conflict types -BDR recognizes the following conflict types, which can be used as the -`conflict_type` parameter: - -- `insert_exists` — An incoming insert conflicts with an existing row via a - primary key or a unique key/index. -- `update_differing` — An incoming update's key row differs from a local - row. This can happen only when using [row version conflict detection](#row-version-conflict-detection). -- `update_origin_change` — An incoming update is modifying a row that was - last changed by a different node. -- `update_missing` — An incoming update is trying to modify a row that doesn't - exist. -- `update_recently_deleted` — An incoming update is trying to modify a row - that was recently deleted. -- `update_pkey_exists` — An incoming update has modified the `PRIMARY KEY` to - a value that already exists on the node that's applying the change. -- `multiple_unique_conflicts` — The incoming row conflicts with multiple - UNIQUE constraints/indexes in the target table. -- `delete_recently_updated` — An incoming delete with an older commit timestamp - than the most recent update of the row on the current node, or when - using [Row version conflict detection]. -- `delete_missing` — An incoming delete is trying to remove a row that doesn't - exist. -- `target_column_missing` — The target table is missing one or more columns - present in the incoming row. -- `source_column_missing` — The incoming row is missing one or more columns - that are present in the target table. +PGD recognizes the following conflict types, which can be used as the `conflict_type` parameter: + +- `insert_exists` — An incoming insert conflicts with an existing row by way of a primary key or a unique key/index. +- `update_differing` — An incoming update's key row differs from a local row. This can happen only when using [row version conflict detection](#row-version-conflict-detection). +- `update_origin_change` — An incoming update is modifying a row that was last changed by a different node. +- `update_missing` — An incoming update is trying to modify a row that doesn't exist. +- `update_recently_deleted` — An incoming update is trying to modify a row that was recently deleted. +- `update_pkey_exists` — An incoming update has modified the `PRIMARY KEY` to a value that already exists on the node that's applying the change. +- `multiple_unique_conflicts` — The incoming row conflicts with multiple UNIQUE constraints/indexes in the target table. +- `delete_recently_updated` — An incoming delete with an older commit timestamp than the most recent update of the row on the current node or when using [row version conflict detection](#row-version-conflict-detection). +- `delete_missing` — An incoming delete is trying to remove a row that doesn't exist. +- `target_column_missing` — The target table is missing one or more columns present in the incoming row. +- `source_column_missing` — The incoming row is missing one or more columns that are present in the target table. - `target_table_missing` — The target table is missing. -- `apply_error_ddl` — An error was thrown by Postgres when applying a - replicated DDL command. +- `apply_error_ddl` — An error was thrown by Postgres when applying a replicated DDL command. ## Conflict resolution -Most conflicts can be resolved automatically. BDR defaults to a -last-update-wins mechanism or, more accurately, the `update_if_newer` -conflict resolver. This mechanism retains the most recently -inserted or changed row of the two conflicting ones based on the same -commit timestamps used for conflict detection. The behavior in certain corner-case -scenarios depends on the settings used for bdr.create_node_group and -alternatively for bdr.alter_node_group. +Most conflicts can be resolved automatically. PGD defaults to a last-update-wins mechanism or, more accurately, the `update_if_newer` conflict resolver. This mechanism retains the most recently inserted or changed row of the two conflicting ones based on the same commit timestamps used for conflict detection. The behavior in certain corner-case scenarios depends on the settings used for `bdr.create_node_group` and +alternatively for `bdr.alter_node_group`. -BDR lets you override the default behavior of conflict resolution by using the -following function: +PGD lets you override the default behavior of conflict resolution by using the following function. ### bdr.alter_node_set_conflict_resolver @@ -987,86 +612,38 @@ bdr.alter_node_set_conflict_resolver(node_name text, #### Parameters - `node_name` — Name of the node that's being changed. -- `conflict_type` — Conflict type for which to apply the setting - (see [List of conflict types](#list-of-conflict-types)). -- `conflict_resolver` — Resolver to use for the given conflict type - (see [List of conflict resolvers](#list-of-conflict-resolvers)). +- `conflict_type` — Conflict type for which to apply the setting (see [List of conflict types](#list-of-conflict-types)). +- `conflict_resolver` — Resolver to use for the given conflict type (see [List of conflict resolvers](#list-of-conflict-resolvers)). #### Notes -Currently you can change only the local node. The function call isn't -replicated. If you want to change settings on multiple nodes, you must run the function -on each of them. +Currently you can change only the local node. The function call isn't replicated. If you want to change settings on multiple nodes, you must run the function on each of them. -The configuration change made by this function overrides any -default behavior of conflict resolutions specified by bdr.create_node_group -or `bdr.alter_node_group`. +The configuration change made by this function overrides any default behavior of conflict resolutions specified by `bdr.create_node_group` or `bdr.alter_node_group`. -This function is transactional. You can roll back the changes, and -they are visible to the current transaction. +This function is transactional. You can roll back the changes, and they are visible to the current transaction. ### List of conflict resolvers -Several conflict resolvers are available in BDR, with differing coverages -of the conflict types they can handle: - -- `error` — Throws error and stops replication. - Can be used for any conflict type. -- `skip` — Skips processing the remote change and continues replication - with the next change. - Can be used for `insert_exists`, `update_differing`, `update_origin_change`, - `update_missing`, `update_recently_deleted`, `update_pkey_exists`, - `delete_recently_updated`, `delete_missing`, `target_table_missing`, - `target_column_missing`, and `source_column_missing` conflict types. -- `skip_if_recently_dropped` — Skip the remote change if it's for a table that - doesn't exist downstream because it was recently (within - one day) dropped on the downstream; throw an error otherwise. Can be used for - the `target_table_missing` conflict type. `skip_if_recently_dropped` conflict - resolver can pose challenges if a table with the same name is re-created shortly - after it's dropped. In that case, one of the nodes might see the DMLs on the - re-created table before it sees the DDL to re-create the table. It then - incorrectly skips the remote data, assuming that the table is recently dropped, - and causes data loss. We hence recommend that you don't reuse the object namesq - immediately after they are dropped along with this conflict resolver. -- `skip_transaction` — Skips the whole transaction that generated the - conflict. Can be used for `apply_error_ddl` conflict. -- `update_if_newer` — Update if the remote row was committed later (as - determined by the wall clock of the originating node) than the conflicting - local row. If the timestamps are same, the node id is used as a tie-breaker - to ensure that same row is picked on all nodes (higher nodeid wins). - Can be used for `insert_exists`, `update_differing`, `update_origin_change`, - and `update_pkey_exists` conflict types. -- `update` — Always perform the replicated action. - Can be used for `insert_exists` (turns the `INSERT` into `UPDATE`), - `update_differing`, `update_origin_change`, `update_pkey_exists`, - and `delete_recently_updated` (performs the delete). -- `insert_or_skip` — Try to build a new row from available information sent by - the origin and INSERT it. If there isn't enough information available to build - a full row, skip the change. - Can be used for `update_missing` and `update_recently_deleted` conflict types. -- `insert_or_error` — Try to build new row from available information sent by - origin and insert it. If there isn't enough information available to build - full row, throw an error and stop the replication. - Can be used for `update_missing` and `update_recently_deleted` conflict types. -- `ignore` — Ignore any missing target column and continue processing. - Can be used for the `target_column_missing` conflict type. -- `ignore_if_null` — Ignore a missing target column if the extra column in the - remote row contains a NULL value. Otherwise, throw an error and stop replication. - Can be used for the `target_column_missing` conflict type. -- `use_default_value` — Fill the missing column value with the default (including - NULL if that's the column default) and continue processing. Any error while - processing the default or violation of constraints (i.e., NULL default on - NOT NULL column) stops replication. - Can be used for the `source_column_missing` conflict type. - -The `insert_exists`, `update_differing`, `update_origin_change`, -`update_missing`, `multiple_unique_conflicts`, `update_recently_deleted`, -`update_pkey_exists`, `delete_recently_updated, and `delete_missing` conflict -types can also be resolved by user-defined logic using +Several conflict resolvers are available in PGD, with differing coverages of the conflict types they can handle: + +- `error` — Throws error and stops replication. Can be used for any conflict type. +- `skip` — Skips processing the remote change and continues replication with the next change. Can be used for `insert_exists`, `update_differing`, `update_origin_change`, `update_missing`, `update_recently_deleted`, `update_pkey_exists`, `delete_recently_updated`, `delete_missing`, `target_table_missing`, `target_column_missing`, and `source_column_missing` conflict types. +- `skip_if_recently_dropped` — Skips the remote change if it's for a table that doesn't exist downstream because it was recently (within one day) dropped on the downstream. Throw an error otherwise. Can be used for the `target_table_missing` conflict type. `skip_if_recently_dropped` conflict +resolver can pose challenges if a table with the same name is re-created shortly after it's dropped. In that case, one of the nodes might see the DMLs on the re-created table before it sees the DDL to re-create the table. It then incorrectly skips the remote data, assuming that the table is recently dropped, and causes data loss. We hence recommend that you don't reuse the object names immediately after they're dropped along with this conflict resolver. +- `skip_transaction` — Skips the whole transaction that generated the conflict. Can be used for `apply_error_ddl` conflict. +- `update_if_newer` — Updates if the remote row was committed later (as determined by the wall clock of the originating node) than the conflicting local row. If the timestamps are same, the node id is used as a tie-breaker to ensure that same row is picked on all nodes (higher nodeid wins). Can be used for `insert_exists`, `update_differing`, `update_origin_change`, and `update_pkey_exists` conflict types. +- `update` — Always performs the replicated action. Can be used for `insert_exists` (turns the `INSERT` into `UPDATE`), `update_differing`, `update_origin_change`, `update_pkey_exists`, and `delete_recently_updated` (performs the delete). +- `insert_or_skip` — Tries to build a new row from available information sent by the origin and INSERT it. If there isn't enough information available to build a full row, skips the change. Can be used for `update_missing` and `update_recently_deleted` conflict types. +- `insert_or_error` — Tries to build new row from available information sent by origin and insert it. If there isn't enough information available to build full row, throws an error and stops the replication. Can be used for `update_missing` and `update_recently_deleted` conflict types. +- `ignore` — Ignores any missing target column and continues processing. Can be used for the `target_column_missing` conflict type. +- `ignore_if_null` — Ignores a missing target column if the extra column in the remote row contains a NULL value. Otherwise, throws an error and stops replication. Can be used for the `target_column_missing` conflict type. +- `use_default_value` — Fills the missing column value with the default (including NULL if that's the column default) and continues processing. Any error while processing the default or violation of constraints (that is, NULL default on NOT NULL column) stops replication. Can be used for the `source_column_missing` conflict type. + +The `insert_exists`, `update_differing`, `update_origin_change`, `update_missing`, `multiple_unique_conflicts`, `update_recently_deleted`, `update_pkey_exists`, `delete_recently_updated`, and `delete_missing` conflict types can also be resolved by user-defined logic using [Conflict triggers](../striggers). -This matrix helps you individuate the conflict types the conflict -resolvers can handle. +This matrix helps you individuate the conflict types the conflict resolvers can handle. | | insert_exists | update_differing | update_origin_change | update_missing | update_recently_deleted | update_pkey_exists | delete_recently_updated | delete_missing | target_column_missing | source_column_missing | target_table_missing | multiple_unique_conflicts | | :----------------------- | ------------- | ---------------- | -------------------- | -------------- | ----------------------- | ------------------ | ----------------------- | -------------- | --------------------- | --------------------- | -------------------- | ------------------------- | @@ -1102,25 +679,18 @@ resolvers can handle. ### List of conflict resolutions -The conflict resolution represents the kind of resolution chosen by the -conflict resolver and corresponds to the specific action that was -taken to resolve the conflict. +The conflict resolution represents the kind of resolution chosen by the conflict resolver and corresponds to the specific action that was taken to resolve the conflict. -The following conflict resolutions are currently supported for the -`conflict_resolution` parameter: +The following conflict resolutions are currently supported for the `conflict_resolution` parameter: - `apply_remote` — The remote (incoming) row was applied. -- `skip` — Processing of the row was skipped (no change was made - locally). +- `skip` — Processing of the row was skipped (no change was made locally). - `merge` — A new row was created, merging information from remote and local row. -- `user` — User code (a conflict trigger) produced the row that was written - to the target table. +- `user` — User code (a conflict trigger) produced the row that was written to the target table. ## Conflict logging -To ease the diagnosis and handling of multi-master conflicts, BDR, by default, logs every conflict -into the `bdr.conflict_history` table. -You can change this behavior with more granularity with the following functions. +To ease diagnosing and handling multi-master conflicts, PGD, by default, logs every conflict into the `bdr.conflict_history` table. You can change this behavior with more granularity with the following functions. ### bdr.alter_node_set_log_config @@ -1142,58 +712,33 @@ bdr.alter_node_set_log_config(node_name text, - `log_to_file` — Whether to log to the node log file. - `log_to_table` — Whether to log to the `bdr.conflict_history` table. - `conflict_type` — Conflict types to log. NULL (the default) means all. -- `conflict_resolution` — Conflict resolutions to log. NULL - (the default) means all. +- `conflict_resolution` — Conflict resolutions to log. NULL (the default) means all. #### Notes -Only the local node can be changed. The function call isn't -replicated. If you want to change settings on multiple nodes, you must run the function -on each of them. +You can change only the local node. The function call isn't replicated. If you want to change settings on multiple nodes, you must run the function on each of them. -This function is transactional. You can roll back the changes, and -they are visible to the current transaction. +This function is transactional. You can roll back the changes, and they're visible to the current transaction. #### Listing conflict logging configurations -The view `bdr.node_log_config` shows all the logging configurations. -It lists the name of the logging configuration, where it logs, and the -conflict type and resolution it logs. +The view `bdr.node_log_config` shows all the logging configurations. It lists the name of the logging configuration, where it logs, and the conflict type and resolution it logs. #### Logging conflicts to a table -Conflicts are logged to a table if `log_to_table` is set to true. -The target table for conflict logging is `bdr.conflict_history`. - -This table is range partitioned on the column `local_time`. The table is -managed by Autopartition. By default, a new partition is created for every day, and -conflicts of the last one month are maintained. After that, the old partitions -are dropped automatically. Autopartition creates between 7 and 14 -partitions in advance. bdr_superuser can change these defaults. - -Since conflicts generated for all tables managed by BDR are logged to this -table, it's important to ensure that only legitimate users can read the -conflicted data. BDR does this by defining ROW LEVEL SECURITY policies on the -`bdr.conflict_history` table. Only owners of the tables are allowed to read conflicts -on the respective tables. If the underlying tables have RLS policies -defined, enabled, and enforced, then even owners can't read the conflicts. RLS -policies created with the FORCE option also apply to owners of the table. In that -case, some or all rows in the underlying table might not be readable even to the -owner. So BDR also enforces a stricter policy on the conflict log table. - -The default role `bdr_read_all_conflicts` can be granted to users who -need to see all conflict details logged to the `bdr.conflict_history` table -without also granting them `bdr_superuser` role. - -The default role `bdr_read_all_stats` has access to a catalog view called -`bdr.conflict_history_summary`, which doesn't contain user data, allowing -monitoring of any conflicts logged. +If `log_to_table` is set to true, conflicts are logged to a table. The target table for conflict logging is `bdr.conflict_history`. + +This table is range partitioned on the column `local_time`. The table is managed by autopartition. By default, a new partition is created for every day, and conflicts of the last one month are maintained. After that, the old partitions are dropped automatically. Autopartition creates between 7 and 14 partitions in advance. bdr_superuser can change these defaults. + +Since conflicts generated for all tables managed by PGD are logged to this table, it's important to ensure that only legitimate users can read the conflicted data. PGD does this by defining ROW LEVEL SECURITY policies on the `bdr.conflict_history` table. Only owners of the tables are allowed to read conflicts on the respective tables. If the underlying tables have RLS policies defined, enabled, and enforced, then even owners can't read the conflicts. RLS policies created with the FORCE option also apply to owners of the table. In that case, some or all rows in the underlying table might not be readable even to the owner. So PGD also enforces a stricter policy on the conflict log table. + +The default role `bdr_read_all_conflicts` can be granted to users who need to see all conflict details logged to the `bdr.conflict_history` table without also granting them `bdr_superuser` role. + +The default role `bdr_read_all_stats` has access to a catalog view called `bdr.conflict_history_summary`, which doesn't contain user data, allowing monitoring of any conflicts logged. ### Conflict reporting -Conflicts logged to tables can be summarized in reports. Reports allow -application owners to identify, understand, and resolve conflicts -and introduce application changes to prevent them. +You can summarize conflicts logged to tables in reports. Reports allow application owners to identify, understand, and resolve conflicts and introduce application changes to prevent them. ```sql SELECT nspname, relname @@ -1212,26 +757,15 @@ ORDER BY 1,2; ## Data verification with LiveCompare -LiveCompare is a utility program designed -to compare any two databases to verify that they are identical. +LiveCompare is a utility program designed to compare any two databases to verify that they are identical. -LiveCompare is included as part of the BDR stack and can be -aimed at any pair of BDR nodes. By default, it compares all replicated tables and reports differences. -LiveCompare also works with non-BDR data sources such as Postgres -and Oracle. +LiveCompare is included as part of the PGD stack and can be aimed at any pair of PGD nodes. By default, it compares all replicated tables and reports differences. LiveCompare also works with non-PGD data sources such as Postgres and Oracle. -You can also use LiveCompare to continuously monitor incoming rows. -You can stop and start it without losing context information, -so you can run it at convenient times. +You can also use LiveCompare to continuously monitor incoming rows. You can stop and start it without losing context information, so you can run it at convenient times. -LiveCompare allows concurrent checking of multiple tables. You can -configure it to allow checking of a few tables or just -a section of rows within a table. -Checks are performed by first comparing whole -row hashes. If different, LiveCompare then compares whole rows. -LiveCompare avoids overheads by comparing rows in useful-sized batches. +LiveCompare allows concurrent checking of multiple tables. You can configure it to allow checking of a few tables or just a section of rows in a table. Checks are performed by first comparing whole +row hashes. If different, LiveCompare then compares whole rows. LiveCompare avoids overheads by comparing rows in useful-sized batches. -If differences are found, they can be rechecked over a period, -allowing for the delays of eventual consistency. +If differences are found, they can be rechecked over time, allowing for the delays of eventual consistency. -Refer to the [LiveCompare](/livecompare/latest/) documentation for further details. +See the [LiveCompare](/livecompare/latest/) documentation for further details. diff --git a/product_docs/docs/pgd/5/consistency/crdt.mdx b/product_docs/docs/pgd/5/consistency/crdt.mdx index 0d41f1bf369..8be332eb8a9 100644 --- a/product_docs/docs/pgd/5/consistency/crdt.mdx +++ b/product_docs/docs/pgd/5/consistency/crdt.mdx @@ -5,21 +5,14 @@ redirects: - /pgd/latest/bdr/crdt/ --- -Conflict-free replicated data types (CRDT) support merging values -from concurrently modified rows instead of discarding one of the rows as traditional resolution does. +Conflict-free replicated data types (CRDT) support merging values from concurrently modified rows instead of discarding one of the rows as traditional resolution does. -Each CRDT type is implemented as a separate PostgreSQL data type with -an extra callback added to the `bdr.crdt_handlers` catalog. The merge -process happens inside the BDR writer on the apply side without any user +Each CRDT type is implemented as a separate PostgreSQL data type with an extra callback added to the `bdr.crdt_handlers` catalog. The merge process happens inside the PGD writer on the apply side without any user action needed. -CRDTs require the table to have column-level conflict resolution enabled, -as documented in [CLCD](column-level-conflicts). +CRDTs require the table to have column-level conflict resolution enabled, as described in [CLCD](column-level-conflicts). -The only action you need to take is to use a particular data type -in CREATE/ALTER TABLE rather than standard built-in data types such as -integer. For example, consider the following table with one regular integer -counter and a single row: +The only action you need to take is to use a particular data type in CREATE/ALTER TABLE rather than standard built-in data types such as integer. For example, consider the following table with one regular integer counter and a single row: ``` CREATE TABLE non_crdt_example ( @@ -48,9 +41,7 @@ SELECT * FROM non_crdt_example WHERE id = 1; (1 row) ``` -This code shows that you lost one of the increments due to the `update_if_newer` -conflict resolver. If you use the CRDT counter data type instead, -the result looks like this: +This code shows that you lost one of the increments due to the `update_if_newer` conflict resolver. If you use the CRDT counter data type instead, the result looks like this: ``` CREATE TABLE crdt_example ( @@ -66,8 +57,7 @@ SELECT bdr.alter_table_conflict_detection('crdt_example', INSERT INTO crdt_example (id) VALUES (1); ``` -Again issue the following SQL on two nodes at same time, -and then wait for the changes to be applied: +Again issue the following SQL on two nodes at same time, and then wait for the changes to be applied: ``` UPDATE crdt_example @@ -81,33 +71,19 @@ SELECT id, counter FROM crdt_example WHERE id = 1; (1 row) ``` -This example shows that CRDTs correctly allow accumulator columns to work, even -in the face of asynchronous concurrent updates that otherwise conflict. +This example shows that CRDTs correctly allow accumulator columns to work, even in the face of asynchronous concurrent updates that otherwise conflict. -The `crdt_gcounter` type is an example of state-based CRDT types that -work only with reflexive UPDATE SQL, such as `x = x + 1`, as the example shows. +The `crdt_gcounter` type is an example of state-based CRDT types that work only with reflexive UPDATE SQL, such as `x = x + 1`, as the example shows. -The `bdr.crdt_raw_value` configuration option determines whether queries -return the current value or the full internal state of the CRDT type. By -default, only the current numeric value is returned. When set to `true`, -queries return representation of the full state. You can use the special hash operator -(`#`) to request only the current numeric value without using the -special operator (the default behavior). If the full state is -dumped using `bdr.crdt_raw_value = on`, then the value can -reload only with `bdr.crdt_raw_value = on`. +The `bdr.crdt_raw_value` configuration option determines whether queries return the current value or the full internal state of the CRDT type. By default, only the current numeric value is returned. When set to `true`, queries return representation of the full state. You can use the special hash operator +(`#`) to request only the current numeric value without using the special operator (the default behavior). If the full state is dumped using `bdr.crdt_raw_value = on`, then the value can reload only with `bdr.crdt_raw_value = on`. !!! Note - The `bdr.crdt_raw_value` applies formatting only of data returned - to clients, that is, simple column references in the select list. Any column - references in other parts of the query (such as `WHERE` clause or even - expressions in the select list) might still require use of the `#` operator. + The `bdr.crdt_raw_value` applies formatting only of data returned to clients, that is, simple column references in the select list. Any column references in other parts of the query (such as `WHERE` clause or even expressions in the select list) might still require use of the `#` operator. -Another class of CRDT data types is referred to *delta CRDT* -types. These are a special subclass of operation-based CRDTs. +Another class of CRDT data types is referred to as *delta CRDT* types. These are a special subclass of operation-based CRDTs. -With delta CRDTs, any update to a value is compared to the -previous value on the same node. Then a change is applied as a delta -on all other nodes. +With delta CRDTs, any update to a value is compared to the previous value on the same node. Then a change is applied as a delta on all other nodes. ``` CREATE TABLE crdt_delta_example ( @@ -141,65 +117,39 @@ SELECT id, counter FROM crdt_delta_example WHERE id = 1; (1 row) ``` -With a regular `integer` column, the result is `2`. But -when you update the row with a delta CRDT counter, you start with the OLD -row version, make a NEW row version, and send both to the remote node. -There, compare them with the version found there (e.g., -the LOCAL version). Standard CRDTs merge the NEW and the LOCAL version, -while delta CRDTs compare the OLD and NEW versions and apply the delta +With a regular `integer` column, the result is `2`. But when you update the row with a delta CRDT counter, you start with the OLD row version, make a NEW row version, and send both to the remote node. There, compare them with the version found there (e.g., the LOCAL version). Standard CRDTs merge the NEW and the LOCAL version, while delta CRDTs compare the OLD and NEW versions and apply the delta to the LOCAL version. -The CRDT types are installed as part of `bdr` into the `bdr` schema. -For convenience, the basic operators (`+`, `#` and `!`) and a number -of common aggregate functions (`min`, `max`, `sum`, and `avg`) are -created in `pg_catalog`. This makes them available without having to tweak -`search_path`. +The CRDT types are installed as part of `bdr` into the `bdr` schema. For convenience, the basic operators (`+`, `#` and `!`) and a number of common aggregate functions (`min`, `max`, `sum`, and `avg`) are created in `pg_catalog`. Thus they are available without having to tweak `search_path`. -An important question is how query planning and optimization works with these -new data types. CRDT types are handled transparently. Both `ANALYZE` and -the optimizer work, so estimation and query planning works fine without -having to do anything else. +An important question is how query planning and optimization works with these new data types. CRDT types are handled transparently. Both `ANALYZE` and the optimizer work, so estimation and query planning works fine without having to do anything else. ## State-based and operation-based CRDTs -Following the notation from [1], both operation-based -and state-based CRDTs are implemented. +Following the notation from [1], both operation-based and state-based CRDTs are implemented. ### Operation-based CRDT types (CmCRDT) -The implementation of operation-based types is trivial because -the operation isn't transferred explicitly but computed from the old -and new row received from the remote node. +The implementation of operation-based types is trivial because the operation isn't transferred explicitly but computed from the old and new row received from the remote node. Currently, these operation-based CRDTs are implemented: - `crdt_delta_counter` — `bigint` counter (increments/decrements) - `crdt_delta_sum` — `numeric` sum (increments/decrements) -These types leverage existing data types (for example, `crdt_delta_counter` is -a domain on a `bigint`) with a little bit of code to compute the delta. +These types leverage existing data types with a little bit of code to compute the delta. For example, `crdt_delta_counter` is a domain on a `bigint`. -This approach is possible only for types for which the method for computing -the delta is known, but the result is simple and cheap (both in terms of -space and CPU) and has a couple of additional benefits. For example, it can -leverage operators/syntax for the underlying data type. +This approach is possible only for types for which the method for computing the delta is known, but the result is simple and cheap (both in terms of space and CPU) and has a couple of added benefits. For example, it can leverage operators/syntax for the underlying data type. -The main disadvantage is that you can't reset this value reliably -in an asynchronous and concurrent environment. +The main disadvantage is that you can't reset this value reliably in an asynchronous and concurrent environment. !!! Note - Implementing more complicated operation-based types by - creating custom data types is possible, storing the state and the last operation. - (Every change is decoded and transferred, so multiple - operations aren't needed). But at that point, the main benefits (simplicity, - reuse of existing data types) are lost without gaining any advantage compared to - state-based types (for example, still no capability to reset) except for the - space requirements. (A per-node state isn't needed.) + Implementing more complicated operation-based types by creating custom data types is possible, storing the state and the last operation. (Every change is decoded and transferred, so multiple + operations aren't needed). But at that point, the main benefits (simplicity, reuse of existing data types) are lost without gaining any advantage compared to state-based types (for example, still no capability to reset) except for the space requirements. (A per-node state isn't needed.) ### State-based CRDT types (CvCRDT) -State-based types require a more complex internal state and so can't -use the regular data types directly the way operation-based types do. +State-based types require a more complex internal state and so can't use the regular data types directly the way operation-based types do. Currently, four state-based CRDTs are implemented: @@ -208,57 +158,37 @@ Currently, four state-based CRDTs are implemented: - `crdt_pncounter` — `bigint` counter (increments/decrements) - `crdt_pnsum` — `numeric` sum/counter (increments/decrements) -The internal state typically includes per-node information, increasing -the on-disk size but allowing added benefits. The need to implement -custom data types implies more code (in/out functions and operators). +The internal state typically includes per-node information, increasing the on-disk size but allowing added benefits. The need to implement custom data types implies more code (in/out functions and operators). -The advantage is the ability to reliably reset the values, a somewhat -self-healing nature in the presence of lost changes (which doesn't -happen in a cluster that operates properly), and the ability to receive changes -from other than source nodes. +The advantage is the ability to reliably reset the values, a somewhat self-healing nature in the presence of lost changes (which doesn't happen in a cluster that operates properly), and the ability to receive changes from other than source nodes. -Consider, for example, that a value is modified on node A, and the change -gets replicated to B but not C due to network issue between A and C. -If B modifies the value and this change gets replicated to C, it -includes even the original change from A. With operation-based CRDTs, -node C doesn't receive the change until the A-C network connection -starts working again. +Consider, for example, that a value is modified on node A, and the change gets replicated to B but not C due to network issue between A and C. If B modifies the value and this change gets replicated to C, it +includes even the original change from A. With operation-based CRDTs, node C doesn't receive the change until the A-C network connection starts working again. -The main disadvantages of CvCRDTs are higher costs in terms of -disk space and CPU usage. A bit of information for each node is needed, including nodes -that were already removed from the cluster. The complex nature of -the state (serialized into varlena types) means increased CPU use. +The main disadvantages of CvCRDTs are higher costs in terms of disk space and CPU usage. A bit of information for each node is needed, including nodes that were already removed from the cluster. The complex nature of the state (serialized into varlena types) means increased CPU use. ## Disk-space requirements -An important consideration is the overhead associated with CRDT types, -particularly the on-disk size. +An important consideration is the overhead associated with CRDT types, particularly the on-disk size. -For operation-based types, this is trivial, because the types -are merely domains on top of other types and so have the same disk -space requirements no matter how many nodes are there. +For operation-based types, this is trivial because the types are merely domains on top of other types. They have the same disk space requirements no matter how many nodes are there: - `crdt_delta_counter` — Same as `bigint` (8 bytes) - `crdt_delta_sum` — Same as `numeric` (variable, depending on precision and scale) -There's no dependency on the number of nodes because operation-based -CRDT types don't store any per-node information. +There's no dependency on the number of nodes because operation-based CRDT types don't store any per-node information. -For state-based types, the situation is more complicated. All the types -are variable-length (stored essentially as a `bytea` column) and consist -of a header and a certain amount of per-node information for each node -that modified the value. +For state-based types, the situation is more complicated. All the types are variable length (stored essentially as a `bytea` column) and consist of a header and a certain amount of per-node information for each node that modified the value. -For the `bigint` variants, formulas computing approximate size are (`N` -denotes the number of nodes that modified this value): +For the `bigint` variants, formulas computing approximate size are: - `crdt_gcounter` — `32B (header) + N * 12B (per-node)` - `crdt_pncounter` -—`48B (header) + N * 20B (per-node)` -For the `numeric` variants, there's no exact formula because both the -header and per-node parts include `numeric` variable-length values. To -give you an idea of how many such values you need to keep: + `N` denotes the number of nodes that modified this value. + +For the `numeric` variants, there's no exact formula because both the header and per-node parts include `numeric` variable-length values. To give you an idea of how many such values you need to keep: - `crdt_gsum` - fixed: `20B (header) + N * 4B (per-node)` @@ -268,64 +198,41 @@ give you an idea of how many such values you need to keep: - variable: `(4 + 2 * N)` `numeric` values !!! Note - It doesn't matter how many nodes are in the cluster if the - values are never updated on multiple nodes. It also doesn't matter whether - the updates were concurrent (causing a conflict). + It doesn't matter how many nodes are in the cluster if the values are never updated on multiple nodes. It also doesn't matter whether the updates were concurrent (causing a conflict). - In addition, it doesn't matter how many of those nodes were already - removed from the cluster. There's no way to compact the state yet. + In addition, it doesn't matter how many of those nodes were already removed from the cluster. There's no way to compact the state yet. ## CRDT types versus conflicts handling -As tables can contain both CRDT and non-CRDT columns (most -columns are expected to be non-CRDT), you need to do both the regular -conflict resolution and CRDT merge. +As tables can contain both CRDT and non-CRDT columns (most columns are expected to be non-CRDT), you need to do both the regular conflict resolution and CRDT merge. -The conflict resolution happens first and is responsible for deciding -the tuple to keep (applytuple) and the one to discard. The merge -phase happens next, merging data for CRDT columns from the discarded +The conflict resolution happens first and is responsible for deciding the tuple to keep (applytuple) and the one to discard. The merge phase happens next, merging data for CRDT columns from the discarded tuple into the applytuple. !!! Note - This handling makes CRDT types somewhat more expensive compared to plain - conflict resolution because the merge needs to happen every time. This is the case even - when the conflict resolution can use one of the fast-paths (such as those modified - in the current transaction). + This handling makes CRDT types somewhat more expensive compared to plain conflict resolution because the merge needs to happen every time. This is the case even when the conflict resolution can use one of the fast paths (such as those modified in the current transaction). ## CRDT types versus conflict reporting -By default, detected conflicts are individually reported. Without -CRDT types, this makes sense because the conflict resolution -essentially throws away one half of the available information (local or -remote row, depending on configuration). This presents a data loss. +By default, detected conflicts are individually reported. Without CRDT types, this makes sense because the conflict resolution essentially throws away half of the available information (local or remote row, depending on configuration). This presents a data loss. -CRDT types allow both parts of the information to be combined -without throwing anything away, eliminating the data loss issue. This makes -the conflict reporting unnecessary. +CRDT types allow both parts of the information to be combined without throwing anything away, eliminating the data loss issue. This approach makes the conflict reporting unnecessary. -For this reason, conflict reporting is skipped when the conflict can be -fully resolved by CRDT merge, that is, if each column meets at least one -of these two conditions: +For this reason, conflict reporting is skipped when the conflict can be fully resolved by CRDT merge. Each column must meet at least one of these two conditions: - The values in local and remote tuple are the same (NULL or equal). - It uses a CRDT data type and so can be merged. !!! Note - This means that the conflict reporting is also skipped when there are no - CRDT columns but all values in local/remote tuples are equal. + Conflict reporting is also skipped when there are no CRDT columns but all values in local/remote tuples are equal. ## Resetting CRDT values -Resetting CRDT values is possible but requires special handling. -The asynchronous nature of the -cluster means that different nodes might see the reset operation at different -places in the change stream no matter how it's implemented. -Different nodes might also initiate a reset concurrently, that is, before +Resetting CRDT values is possible but requires special handling. The asynchronous nature of the +cluster means that different nodes might see the reset operation at different places in the change stream no matter how it's implemented. Different nodes might also initiate a reset concurrently, that is, before observing the reset from the other node. -In other words, to make the reset operation behave correctly, it needs to -be commutative with respect to the regular operations. Many naive ways -to reset a value that might work well on a single-node fail +In other words, to make the reset operation behave correctly, it needs to be commutative with respect to the regular operations. Many naive ways to reset a value that might work well on a single-node fail for this reason. For example, the simplest approach to resetting a value might be: @@ -334,26 +241,14 @@ For example, the simplest approach to resetting a value might be: UPDATE crdt_table SET cnt = 0 WHERE id = 1; ``` -With state-based CRDTs this doesn't work. It throws away the state for the -other nodes but only locally. It's added back by merge functions -on remote nodes, causing diverging values and eventually receiving it +With state-based CRDTs this doesn't work. It throws away the state for the other nodes but only locally. It's added back by merge functions on remote nodes, causing diverging values and eventually receiving it back due to changes on the other nodes. -With operation-based CRDTs, this might seem to work because the -update is interpreted as a subtraction of `-cnt`. But it works only in the -absence of concurrent resets. Once two nodes attempt to do a reset at -the same time, the delta is applied twice, getting a negative -value (which isn't expected from a reset). +With operation-based CRDTs, this might seem to work because the update is interpreted as a subtraction of `-cnt`. But it works only in the absence of concurrent resets. Once two nodes attempt to do a reset at the same time, the delta is applied twice, getting a negative value (which isn't expected from a reset). -It might also seem that you can use `DELETE + INSERT` as a reset, but this approach -has a couple of weaknesses, too. If the row is reinserted with the same -key, it's not guaranteed that all nodes see it at the same position in -the stream of operations with respect to changes from other nodes. -BDR specifically discourages reusing the same primary key value since -it can lead to data anomalies in concurrent cases. +It might also seem that you can use `DELETE + INSERT` as a reset, but this approach has a couple of weaknesses, too. If the row is reinserted with the same key, it's not guaranteed that all nodes see it at the same position in the stream of operations with respect to changes from other nodes. PGD specifically discourages reusing the same primary key value since it can lead to data anomalies in concurrent cases. -State-based CRDT types can reliably handle resets -using a special `!` operator like this: +State-based CRDT types can reliably handle resets using a special `!` operator like this: ``` UPDATE tab SET counter = !counter WHERE ...; @@ -361,27 +256,22 @@ UPDATE tab SET counter = !counter WHERE ...; "Reliably" means the values don't have the two issues of multiple concurrent resets and divergence. -Operation-based CRDT types can be reset reliably only using -[Eager Replication](eager), since this avoids multiple concurrent resets. -You can also use Eager Replication to set either kind of CRDT to a specific +Operation-based CRDT types can be reset reliably only using [eager replication](eager), since this avoids multiple concurrent resets. You can also use eager replication to set either kind of CRDT to a specific value. ## Implemented CRDT data types -Currently, there are six CRDT data types implemented: +Currently, six CRDT data types are implemented: - Grow-only counter and sum - Positive-negative counter and sum - Delta counter and sum -The counters and sums behave mostly the same, except that the counter types -are integer-based (`bigint`), while the sum types are decimal-based -(`numeric`). +The counters and sums behave mostly the same, except that the counter types are integer based (`bigint`), while the sum types are decimal-based (`numeric`). Additional CRDT types, described at [1], might be implemented later. -You can list the currently implemented CRDT data types with the -following query: +You can list the currently implemented CRDT data types with the following query: ```sql SELECT n.nspname, t.typname @@ -392,18 +282,13 @@ JOIN (pg_type t JOIN pg_namespace n ON t.typnamespace = n.oid) ### grow-only counter (`crdt_gcounter`) -- Supports only increments with nonnegative values (`value + int` - and `counter + bigint` operators). +- Supports only increments with nonnegative values (`value + int` and `counter + bigint` operators). -- You can obtain the current value of the counter either using `#` operator - or by casting it to `bigint`. +- You can obtain the current value of the counter either using `#` operator or by casting it to `bigint`. -- Isn't compatible with simple assignments like `counter = value` - (which is common pattern when the new value is computed somewhere in - the application). +- Isn't compatible with simple assignments like `counter = value` (which is common pattern when the new value is computed somewhere in the application). -- Allows simple reset of the counter using the `!` operator - ( `counter = !counter` ). +- Allows simple reset of the counter using the `!` operator ( `counter = !counter` ). - You can inspect the internal state using `crdt_gcounter_to_text`. @@ -445,12 +330,9 @@ SELECT id, bdr.crdt_gcounter_to_text(cnt) FROM crdt_test; - Supports only increments with nonnegative values (`sum + numeric`). -- You can obtain the current value of the sum either by using the `#` operator - or by casting it to `numeric`. +- You can obtain the current value of the sum either by using the `#` operator or by casting it to `numeric`. -- Isn't compatible with simple assignments like `sum = value` - (which is the common pattern when the new value is computed somewhere in - the application). +- Isn't compatible with simple assignments like `sum = value`, which is the common pattern when the new value is computed somewhere in the application. - Allows simple reset of the sum using the `!` operator (`sum = !sum`). @@ -492,18 +374,13 @@ SELECT id, bdr.crdt_gsum_to_text(gsum) FROM crdt_test; ### positive-negative counter (`crdt_pncounter`) -- Supports increments with both positive and negative values (through - `counter + int` and `counter + bigint` operators). +- Supports increments with both positive and negative values (through `counter + int` and `counter + bigint` operators). -- You can obtain the current value of the counter either by using the `#` operator - or by casting to `bigint`. +- You can obtain the current value of the counter either by using the `#` operator or by casting to `bigint`. -- Isn't compatible with simple assignments like `counter = value` - (which is the common pattern when the new value is computed somewhere in - the application). +- Isn't compatible with simple assignments like `counter = value`, which is the common pattern when the new value is computed somewhere in the application. -- Allows simple reset of the counter using the `!` operator - (`counter = !counter`). +- Allows simple reset of the counter using the `!` operator (`counter = !counter`). - You can inspect the internal state using `crdt_pncounter_to_text`. @@ -546,15 +423,11 @@ SELECT id, cnt::bigint, cnt FROM crdt_test; ### positive-negative sum (`crdt_pnsum`) -- Supports increments with both positive and negative values (through - `sum + numeric`). +- Supports increments with both positive and negative values through `sum + numeric`. -- You can obtain the current value of the sum either by using then `#` operator - or by casting to `numeric`. +- You can obtain the current value of the sum either by using then `#` operator or by casting to `numeric`. -- Isn't compatible with simple assignments like `sum = value` - (which is the common pattern when the new value is computed somewhere in - the application). +- Isn't compatible with simple assignments like `sum = value`, which is the common pattern when the new value is computed somewhere in the application. - Allows simple reset of the sum using the `!` operator (`sum = !sum`). @@ -603,8 +476,7 @@ SELECT id, pnsum::numeric, pnsum FROM crdt_test; - Supports increments with both positive and negative values. -- Is compatible with simple assignments like `counter = value` - (common when the new value is computed somewhere in the application). +- Is compatible with simple assignments like `counter = value`, which is common when the new value is computed somewhere in the application. - There's no simple way to reset the value reliably. @@ -642,8 +514,7 @@ SELECT id, cnt FROM crdt_test; - Supports increments with both positive and negative values. -- Is compatible with simple assignments like `sum = value` - (common when the new value is computed somewhere in the application). +- Is compatible with simple assignments like `sum = value`, which is common when the new value is computed somewhere in the application. - There's no simple way to reset the value reliably. diff --git a/product_docs/docs/pgd/5/consistency/eager.mdx b/product_docs/docs/pgd/5/consistency/eager.mdx index dfd7169cded..88e0530b6aa 100644 --- a/product_docs/docs/pgd/5/consistency/eager.mdx +++ b/product_docs/docs/pgd/5/consistency/eager.mdx @@ -4,19 +4,13 @@ redirects: - /pgd/latest/bdr/eager/ --- -Eager conflict resolution (also known as Eager Replication) prevents conflicts -by aborting transactions that conflict with each other with serializable error -during the COMMIT decision process. +Eager conflict resolution (also known as eager replication) prevents conflicts by aborting transactions that conflict with each other with serializable errors during the COMMIT decision process. -It is configured using [Commit Scopes](../durability/commit-scopes) -as one of the conflict resolution options for -[Group Commit](../durability/group-commit). +You configure it using [commit scopes](../durability/commit-scopes) as one of the conflict resolution options for [group commit](../durability/group-commit). ## Usage -To enable Eager conflict resolution, the client needs to switch to -a Commit Scope which uses it at session level or for individual transactions -as shown here: +To enable eager conflict resolution, the client needs to switch to a commit scope, which uses it at session level or for individual transactions as shown here: ```sql BEGIN; @@ -26,14 +20,13 @@ SET LOCAL bdr.commit_scope = 'eager_scope'; ... other commands possible... ``` -The client can continue to issue a `COMMIT` at the end of the -transaction and let BDR manage the two phases: +The client can continue to issue a `COMMIT` at the end of the transaction and let PGD manage the two phases: ```sql COMMIT; ``` -In this case the `eager_scope` commit scope would be defined something like this: +In this case, the `eager_scope` commit scope is defined something like this: ```sql SELECT bdr.add_commit_scope( @@ -45,48 +38,25 @@ SELECT bdr.add_commit_scope( ``` !!! Upgrade note - The old `global` commit scope does not exist anymore and the above command - creates scope that is same as the old `global` scope with - `bdr.global_commit_timeout` set to `60s`. + The old `global` commit scope doesn't exist anymore. The above command creates a scope that's the same as the old `global` scope with `bdr.global_commit_timeout` set to `60s`. ## Error handling -Given that BDR manages the transaction, the client needs to check only the -result of the `COMMIT`. (This is advisable in any case, including single-node -Postgres.) +Given that PGD manages the transaction, the client needs to check only the result of the `COMMIT`. This is advisable in any case, including single-node Postgres. -In case of an origin node failure, the remaining nodes eventually -(after at least `ABORT ON timeout`) decide to roll back the -globally prepared transaction. Raft prevents inconsistent commit versus -rollback decisions. However, this requires a majority of connected -nodes. Disconnected nodes keep the transactions prepared -to eventually commit them (or roll back) as needed to reconcile with the -majority of nodes that might have decided and made further progress. +In case of an origin node failure, the remaining nodes eventually (after at least `ABORT ON timeout`) decide to roll back the globally prepared transaction. Raft prevents inconsistent commit versus rollback decisions. However, this requires a majority of connected nodes. Disconnected nodes keep the transactions prepared to eventually commit them (or roll back) as needed to reconcile with the majority of nodes that might have decided and made further progress. -## Effects of Eager Replication in general +## Effects of eager replication in general #### Increased commit latency -Adding a synchronization step means additional communication between -the nodes, resulting in additional latency at commit time. Eager All-Node -Replication adds roughly two network roundtrips (to the furthest -peer node in the worst case). Logical standby nodes and nodes still -in the process of joining or catching up aren't included but -eventually receive changes. +Adding a synchronization step means more communication between the nodes, resulting in more latency at commit time. Eager all-node replication adds roughly two network roundtrips (to the furthest peer node in the worst case). Logical standby nodes and nodes still in the process of joining or catching up aren't included but eventually receive changes. -Before a peer node can confirm its local preparation of the -transaction, it also needs to apply it locally. This further adds to -the commit latency, depending on the size of the transaction. -This is independent of the `synchronous_commit` setting. +Before a peer node can confirm its local preparation of the transaction, it also needs to apply it locally. This further adds to the commit latency, depending on the size of the transaction. This setting is independent of the `synchronous_commit` setting. #### Increased abort rate -With single-node Postgres, or even with BDR in its default asynchronous -replication mode, errors at `COMMIT` time are rare. The additional -synchronization step adds a source of errors, so applications need to -be prepared to properly handle such errors (usually by applying a -retry loop). +With single-node Postgres, or even with PGD in its default asynchronous replication mode, errors at `COMMIT` time are rare. The added synchronization step adds a source of errors, so applications need to +be prepared to properly handle such errors (usually by applying a retry loop). -The rate of aborts depends solely on the workload. Large transactions -changing many rows are much more likely to conflict with other -concurrent transactions. +The rate of aborts depends solely on the workload. Large transactions changing many rows are much more likely to conflict with other concurrent transactions. diff --git a/product_docs/docs/pgd/5/consistency/index.mdx b/product_docs/docs/pgd/5/consistency/index.mdx index 81d2b3b713f..66c4d1547a4 100644 --- a/product_docs/docs/pgd/5/consistency/index.mdx +++ b/product_docs/docs/pgd/5/consistency/index.mdx @@ -9,26 +9,14 @@ navigation: --- -EDB Postgres Distributed is an active/active or multi-master DBMS. If used -asynchronously, writes to the same or related rows from multiple different -nodes can result in data [conflicts](conflicts) when using standard data types. +EDB Postgres Distributed is an active/active or multi-master DBMS. If used asynchronously, writes to the same or related rows from multiple different nodes can result in data [conflicts](conflicts) when using standard data types. -Conflicts aren't errors. In most cases, they are events that PGD can detect -and resolve as they occur. Resolution depends on the -nature of the application and the meaning of the data, so it's important that -PGD provides the application a range of choices as to how to resolve -[conflicts](conflicts). +Conflicts aren't errors. In most cases, they're events that PGD can detect and resolve as they occur. Resolution depends on the nature of the application and the meaning of the data, so it's important that +PGD provides the application a range of choices as to how to resolve them. -By default, conflicts are resolved at the row level. When changes from two -nodes conflict, either the local or remote tuple is picked and the other -is discarded. For example, the commit timestamps might be compared for the two conflicting -changes and the newer one kept. This approach ensures that all nodes converge to the -same result and establishes commit-order-like semantics on the whole cluster. +By default, conflicts are resolved at the row level. When changes from two nodes conflict, either the local or remote tuple is picked and the other is discarded. For example, the commit timestamps might be compared for the two conflicting changes and the newer one kept. This approach ensures that all nodes converge to the same result and establishes commit-order-like semantics on the whole cluster. -Column-level conflict detection and resolution is available with PGD, -described in [CLCD](column-level-conflicts). +Column-level conflict detection and resolution is available with PGD, described in [CLCD](column-level-conflicts). -If you want to avoid conflicts, you can use -[Group Commit](/pgd/latest/durability/group-commit) with -[Eager Conflict Resolution](eager) or Conflict-free data types (CRDTs), -described in [CRDT](crdt) +If you want to avoid conflicts, you can use [group commit](/pgd/latest/durability/group-commit) with +[eager conflict resolution](eager) or conflict-free data types (CRDTs), described in [CRDT](crdt). diff --git a/product_docs/docs/pgd/5/ddl.mdx b/product_docs/docs/pgd/5/ddl.mdx index f26c001943a..9808bcb8840 100644 --- a/product_docs/docs/pgd/5/ddl.mdx +++ b/product_docs/docs/pgd/5/ddl.mdx @@ -8,7 +8,7 @@ redirects: DDL stands for data definition language, the subset of the SQL language that creates, alters, and drops database objects. -For operational convenience and correctness, BDR replicates most DDL +For operational convenience and correctness, PGD replicates most DDL actions, with these exceptions: - Temporary or unlogged relations @@ -27,9 +27,9 @@ In the default replication set, DDL is replicated to all nodes by default. To replicate DDL, you must add a DDL replication filter to the replication set. See [DDL replication filtering](repsets/#ddl-replication-filtering). -BDR is significantly different from standalone PostgreSQL when it +PGD is significantly different from standalone PostgreSQL when it comes to DDL replication. Treating it the same is the most -common issue with BDR. +common issue with PGD. The main difference from table replication is that DDL replication doesn't replicate the result of the DDL but the statement itself. This works @@ -71,32 +71,32 @@ parameters. SET bdr.ddl_replication = off; ``` -When set, it makes BDR skip both the global locking and the replication +When set, it makes PGD skip both the global locking and the replication of executed DDL commands. You must then run the DDL manually on all nodes. !!! Warning Executing DDL manually on each node without global locking can - cause the whole BDR group to stop replicating if conflicting DDL or DML + cause the whole PGD group to stop replicating if conflicting DDL or DML executes concurrently. The `bdr.ddl_replication` parameter can be set only by the bdr_superuser, by superuser, or in the `config` file. -## Executing DDL on BDR systems +## Executing DDL on PGD systems -A BDR group isn't the same as a standalone PostgreSQL server. It's +A PGD group isn't the same as a standalone PostgreSQL server. It's based on asynchronous multi-master replication without central locking and without a transaction coordinator. This has important implications when executing DDL. -DDL that executes in parallel continues to do so with BDR. DDL execution +DDL that executes in parallel continues to do so with PGD. DDL execution respects the parameters that affect parallel operation on each node as it executes, so you might notice differences in the settings between nodes. Prevent the execution of conflicting DDL, otherwise DDL replication causes errors and the replication stops. -BDR offers three levels of protection against those problems: +PGD offers three levels of protection against those problems: `ddl_locking = 'dml'` is the best option for operations, usable when you execute DDL from only one node at a time. This isn't the default, but we recommend @@ -120,19 +120,19 @@ function. ## DDL locking details -Two kinds of locks enforce correctness of replicated DDL with BDR. +Two kinds of locks enforce correctness of replicated DDL with PGD. The first kind is known as a global DDL lock and is used only when `ddl_locking = on`. A global DDL lock prevents any other DDL from executing on the cluster while each DDL statement runs. This ensures full correctness in the general case but -is too strict for many simple cases. BDR acquires a global lock on +is too strict for many simple cases. PGD acquires a global lock on DDL operations the first time in a transaction where schema changes are made. This effectively serializes the DDL-executing transactions in the cluster. In other words, while DDL is running, no other connection on any node can run another DDL command, even if it affects different tables. -To acquire a lock on DDL operations, the BDR node executing DDL contacts the -other nodes in a BDR group and asks them to grant it the exclusive right to +To acquire a lock on DDL operations, the PGD node executing DDL contacts the +other nodes in a PGD group and asks them to grant it the exclusive right to execute DDL. The lock request is sent by the regular replication stream, and the nodes respond by the replication stream as well. So it's important that nodes (or at least a majority of the nodes) run without much replication @@ -158,8 +158,8 @@ Relation DML locks affect only one relation at a time. Relation DML locks ensure that no DDL executes while there are changes in the queue that might cause replication to halt with an error. -To acquire the global DML lock on a table, the BDR node executing the DDL -contacts all other nodes in a BDR group, asking them to lock the table +To acquire the global DML lock on a table, the PGD node executing the DDL +contacts all other nodes in a PGD group, asking them to lock the table against writes and waiting while all pending changes to that table are drained. Once all nodes are fully caught up, the originator of the DML lock is free to perform schema changes to the table and replicate them to the other nodes. @@ -180,13 +180,13 @@ down node from the configuration. If a DDL statement isn't replicated, no global locks are acquired. Locking behavior is specified by the `bdr.ddl_locking` parameter, as -explained in [Executing DDL on BDR systems](#executing-ddl-on-bdr-systems): +explained in [Executing DDL on PGD systems](#executing-ddl-on-pgd-systems): - `ddl_locking = on` takes global DDL lock and, if needed, takes relation DML lock. - `ddl_locking = dml` skips global DDL lock and, if needed, takes relation DML lock. - `ddl_locking = off` skips both global DDL lock and relation DML lock. -Some BDR functions make DDL changes. For those functions, +Some PGD functions make DDL changes. For those functions, DDL locking behavior applies. This is noted in the docs for each function. Thus, `ddl_locking = dml` is safe only when you can guarantee that @@ -204,10 +204,10 @@ If these serialization failures occur, the DDL might reexecute. DDL replication isn't active on logical standby nodes until they are promoted. -Some BDR management functions act like DDL, meaning that they +Some PGD management functions act like DDL, meaning that they attempt to take global locks, and their actions are replicated if DDL replication is active. The full list of replicated functions is listed in -[BDR functions that behave like DDL](#bdr-functions-that-behave-like-ddl). +[PGD functions that behave like DDL](#pgd-functions-that-behave-like-ddl). DDL executed on temporary tables never need global locks. @@ -220,7 +220,7 @@ Monitoring of global DDL locks and global DML locks is shown in ## Minimizing the impact of DDL Good operational advice for any database, these points become even more -important with BDR: +important with PGD: - To minimize the impact of DDL, make transactions performing DDL short, don't combine them with lots of row changes, and avoid long @@ -251,7 +251,7 @@ INDEX CONCURRENTLY`, noting that DDL replication must be disabled for the whole session because `CREATE INDEX CONCURRENTLY` is a multi-transaction command. Avoid `CREATE INDEX` on production systems since it prevents writes while it executes. -`REINDEX` is replicated in versions up to 3.6 but not with BDR 3.7 or later. +`REINDEX` is replicated in versions up to 3.6 but not with PGD 3.7 or later. Avoid using `REINDEX` because of the AccessExclusiveLocks it holds. Instead, use `REINDEX CONCURRENTLY` (or `reindexdb --concurrently`), @@ -284,7 +284,7 @@ holding any global locks. You can disable all of these timeouts by setting their values to zero. Once the DDL operation has committed on the originating node, you can't cancel or abort it. -The BDR group must wait for it to apply successfully on +The PGD group must wait for it to apply successfully on other nodes that confirmed the global lock and for them to acknowledge replay. For this reason, keep DDL transactions short and fast. @@ -297,7 +297,7 @@ In case the node comes back up, it releases all the global locks that it holds. If it stays down for a long time (or indefinitely), -remove the node from the BDR group to release the global locks. This +remove the node from the PGD group to release the global locks. This is one reason for executing emergency DDL using the `SET` command as the bdr_superuser to update the `bdr.ddl_locking` value. @@ -319,12 +319,12 @@ Not all commands can be replicated automatically. Such commands are generally disallowed, unless DDL replication is turned off by turning `bdr.ddl_replication` off. -BDR prevents some DDL statements from running when it's active on a +PGD prevents some DDL statements from running when it's active on a database. This protects the consistency of the system by disallowing statements that can't be replicated correctly or for which replication isn't yet supported. -If a statement isn't permitted under BDR, you can often find +If a statement isn't permitted under PGD, you can often find another way to do the same thing. For example, you can't do an `ALTER TABLE`, which adds a column with a volatile default value. But generally you can rephrase that as a series of independent `ALTER TABLE` and `UPDATE` statements @@ -334,10 +334,10 @@ Generally unsupported statements are prevented from being executed, raising a `feature_not_supported` (SQLSTATE `0A000`) error. Any DDL that references or relies on a temporary object can't -be replicated by BDR and throws an error if executed with DDL replication +be replicated by PGD and throws an error if executed with DDL replication enabled. -## BDR DDL command handling matrix +## PGD DDL command handling matrix The following table describes the utility or DDL commands that are allowed, the ones that are replicated, and the type of global lock they take when they're replicated. @@ -579,7 +579,7 @@ subcommands aren't supported. #### ALTER TABLE disallowed commands -Some variants of `ALTER TABLE` currently aren't allowed on a BDR node: +Some variants of `ALTER TABLE` currently aren't allowed on a PGD node: - `ADD COLUMN ... DEFAULT (non-immutable expression)` — This is not allowed because it currently results in different data on different nodes. See @@ -619,7 +619,7 @@ ALTER TABLE foo ADD expiry_date timestamptz DEFAULT timestamp '2100-01-01 00:00:00' NOT NULL; ``` -Starting in BDR 3.7.4, you can add certain types of constraints, such as `CHECK` and +Starting in PGD 3.7.4, you can add certain types of constraints, such as `CHECK` and `FOREIGN KEY` constraints, without taking a DML lock. But this requires a two-step process of first creating a `NOT VALID` constraint and then validating the constraint in a separate transaction with the `ALTER TABLE ... VALIDATE CONSTRAINT` @@ -699,7 +699,7 @@ restricted. ```sql ALTER TABLE sample ALTER COLUMN col2 TYPE VARCHAR(64); -ERROR: ALTER TABLE ... ALTER COLUMN TYPE that rewrites table data may not affect replicated tables on a BDR node +ERROR: ALTER TABLE ... ALTER COLUMN TYPE that rewrites table data may not affect replicated tables on a PGD node ``` To give an example with nontext types, consider col3 above with type @@ -708,7 +708,7 @@ fails in a similar manner as above. ```sql ALTER TABLE sample ALTER COLUMN col3 TYPE bigint; -ERROR: ALTER TABLE ... ALTER COLUMN TYPE that rewrites table data may not affect replicated tables on a BDR node +ERROR: ALTER TABLE ... ALTER COLUMN TYPE that rewrites table data may not affect replicated tables on a PGD node ``` In both of these failing cases, there's an automatic assignment @@ -769,7 +769,7 @@ SET bdr.ddl_replication TO FALSE; ALTER TABLE sample ALTER COLUMN col3 TYPE TEXT; -- conversion from TEXT back to BIGINT fails ALTER TABLE sample ALTER COLUMN col3 TYPE BIGINT; -ERROR: ALTER TABLE ... ALTER COLUMN TYPE which cannot be automatically cast to new type may not affect replicated tables on a BDR node +ERROR: ALTER TABLE ... ALTER COLUMN TYPE which cannot be automatically cast to new type may not affect replicated tables on a PGD node RESET bdr.ddl_replication; ``` @@ -839,7 +839,7 @@ sequences, some options have no effect. ### CREATE TABLE Generally `CREATE TABLE` is supported, but `CREATE TABLE WITH OIDS` isn't -allowed on a BDR node. +allowed on a PGD node.
@@ -907,15 +907,15 @@ the global DML lock when `bdr.truncate_locking` is set to `on`. ### Role manipulation statements Users are global objects in a PostgreSQL instance, which means they span -multiple databases while BDR operates on an individual database level. This means +multiple databases while PGD operates on an individual database level. This means that role manipulation statement handling needs extra thought. -BDR requires that any roles that are referenced by any replicated DDL must +PGD requires that any roles that are referenced by any replicated DDL must exist on all nodes. The roles don't have to have the same grants, password, and so on, but they must exist. -BDR replicates role manipulation statements if `bdr.role_replication` is -enabled (default) and role manipulation statements are run in a BDR-enabled +PGD replicates role manipulation statements if `bdr.role_replication` is +enabled (default) and role manipulation statements are run in a PGD-enabled database. The role manipulation statements include the following: @@ -938,7 +938,7 @@ In general, either: tools like Ansible, Puppet, and Chef or explicitly replicated by `bdr.replicate_ddl_command(...)`. -- Configure the system so that exactly one BDR-enabled database +- Configure the system so that exactly one PGD-enabled database on the PostgreSQL instance has `bdr.role_replication = on` and run all role management DDL on that database. @@ -946,19 +946,19 @@ We recommended that you run all role management commands in one database. If role replication is turned off, then the administrator must ensure that -any roles used by DDL on one node also exist on the other nodes. Otherwise BDR apply +any roles used by DDL on one node also exist on the other nodes. Otherwise PGD apply stalls with an error until the role is created on the other nodes. !!! Note - BDR doesn't capture and replicate role management statements when they - run on a non-BDR-enabled database in a BDR-enabled PostgreSQL instance. + PGD doesn't capture and replicate role management statements when they + run on a non-PGD-enabled database in a PGD-enabled PostgreSQL instance. For example, if you have DBs 'bdrdb' (bdr group member) and 'postgres' (bare db), and `bdr.role_replication = on`, then a `CREATE USER` run in `bdrdb` is replicated, but a `CREATE USER` run in `postgres` isn't. ### Restricted DDL workarounds -Some of the limitations of BDR DDL operation handling can be worked around. +Some of the limitations of PGD DDL operation handling can be worked around. Often splitting up the operation into smaller changes can produce the desired result that either isn't allowed as a single statement or requires excessive locking. @@ -973,7 +973,7 @@ This involves a two-step process. Execute these steps in two different transactions. Both these steps take DDL lock only on the table and hence can be run even when one -or more nodes are down. But to validate a constraint, BDR must +or more nodes are down. But to validate a constraint, PGD must ensure that: - All nodes in the cluster see the `ADD CONSTRAINT` command. - The node validating the constraint applied replication changes from all other nodes prior to @@ -982,7 +982,7 @@ ensure that: So even though the new mechanism doesn't need all nodes to be up while validating the constraint, it still requires that all nodes applied the `ALTER TABLE .. ADD CONSTRAINT ... NOT VALID` -command and made enough progress. BDR waits for a consistent +command and made enough progress. PGD waits for a consistent state to be reached before validating the constraint. The new facility requires the cluster to run with Raft protocol @@ -1006,8 +1006,8 @@ separate transactions: ``` This approach splits schema changes and row changes into separate transactions that -BDR can execute and results in consistent data across all nodes in a -BDR group. +PGD can execute and results in consistent data across all nodes in a +PGD group. For best results, batch the update into chunks so that you don't update more than a few tens or hundreds of thousands of rows at once. You can do this using @@ -1095,9 +1095,9 @@ ALTER TYPE contact_method ADD VALUE 'email'; SELECT bdr.wait_slot_confirm_lsn(NULL, NULL); ``` -### BDR functions that behave like DDL +### PGD functions that behave like DDL -The following BDR management functions act like DDL. This means that, if DDL +The following PGD management functions act like DDL. This means that, if DDL replication is active and DDL filter settings allow it, they attempt to take global locks and their actions are replicate. For detailed information, see the documentation for the individual functions. diff --git a/product_docs/docs/pgd/5/deployments.mdx b/product_docs/docs/pgd/5/deployments.mdx index b2c0f0c0cec..2274f169498 100644 --- a/product_docs/docs/pgd/5/deployments.mdx +++ b/product_docs/docs/pgd/5/deployments.mdx @@ -8,9 +8,9 @@ You can deploy and install EDB Postgres Distributed products using the following - [Trusted Postgres Architect](/tpa/latest) is an orchestration tool that uses Ansible to build Postgres clusters using a set of reference architectures that document how to set up and operate Postgres in various scenarios. Trusted Postgres Architect (TPA) represents the best practices followed by EDB, and its recommendations are as applicable to quick testbed setups as to production environments. See [Deploying with TPA](tpa) for more information. -- BigAnimal is a fully managed database-as-a-service with built-in Oracle compatibility, running in your cloud account and operated by the Postgres experts. BigAnimal makes it easy to set up, manage, and scale your databases. The addition of extreme high availability support through EDB Postres Distributed allows single-region Always On Gold clusters: two BDR groups in different availability zones in a single cloud region, with a witness node in a third availability zone. See the [Extreme high availability](/biganimal/latest/overview/02_high_availability/#extreme-high-availability-beta) topic in the [BigAnimal documentation](/biganimal/latest) for more information. +- BigAnimal is a fully managed database-as-a-service with built-in Oracle compatibility, running in your cloud account and operated by the Postgres experts. BigAnimal makes it easy to set up, manage, and scale your databases. The addition of extreme high availability support through EDB Postres Distributed allows single-region Always On Gold clusters: two PGD groups in different availability zones in a single cloud region, with a witness node in a third availability zone. See the [Extreme high availability](/biganimal/latest/overview/02_high_availability/#extreme-high-availability-beta) topic in the [BigAnimal documentation](/biganimal/latest) for more information. Coming soon: -- EDB Postgres Distributed for Kubernetes will be a Kubernetes operator is designed, developed, and supported by EDB that covers the full lifecycle of a highly available Postgres database clusters with a multi-master architecture, using BDR replication. It is based on the open source CloudNativePG operator, and provides additional value such as compatibility with Oracle using EDB Postgres Advanced Server and additional supported platforms such as IBM Power and OpenShift. +- EDB Postgres Distributed for Kubernetes will be a Kubernetes operator is designed, developed, and supported by EDB that covers the full lifecycle of a highly available Postgres database clusters with a multi-master architecture, using PGD replication. It is based on the open source CloudNativePG operator, and provides additional value such as compatibility with Oracle using EDB Postgres Advanced Server and additional supported platforms such as IBM Power and OpenShift. diff --git a/product_docs/docs/pgd/5/durability/camo.mdx b/product_docs/docs/pgd/5/durability/camo.mdx index aecb6d8be93..9971bfdfb43 100644 --- a/product_docs/docs/pgd/5/durability/camo.mdx +++ b/product_docs/docs/pgd/5/durability/camo.mdx @@ -5,157 +5,72 @@ redirects: - /pgd/latest/bdr/camo/ --- -The objective of the Commit At Most Once (CAMO) feature is to prevent -the application from committing more than once. +The objective of the Commit At Most Once (CAMO) feature is to prevent the application from committing more than once. -Without CAMO, when a client loses connection after a COMMIT is -submitted, the application might not receive a reply from the server -and is therefore unsure whether the transaction committed. +Without CAMO, when a client loses connection after a `COMMIT` is submitted, the application might not receive a reply from the server and is therefore unsure whether the transaction committed. The application can't easily decide between the two options of: -* Retrying the transaction with the same data, since this can in some cases - cause the data to be entered twice +- Retrying the transaction with the same data, since this can in some cases cause the data to be entered twice -* Not retrying the transaction and risk that the data doesn't get - processed at all +- Not retrying the transaction and risk that the data doesn't get processed at all Either of those is a critical error with high-value data. -One way to avoid this situation is to make sure that the transaction -includes at least one `INSERT` into a table with a unique index, but -that depends on the application design and requires application- -specific error-handling logic, so it isn't effective in all cases. - -The CAMO feature in PGD offers a more general solution and doesn't require -an `INSERT`. When activated by `bdr.commit_scope`, the application -receives a message containing the transaction identifier, if already -assigned. Otherwise, the first write statement in a transaction -sends that information to the client. - -If the application sends an explicit COMMIT, the protocol ensures that the -application receives the notification of the transaction identifier before the -COMMIT is sent. If the server doesn't reply to the COMMIT, the application can -handle this error by using the transaction identifier to request -the final status of the transaction from another PGD node. -If the prior transaction status is known, then the application can safely -decide whether to retry the transaction. - -CAMO works by creating a pair of partner nodes that are two PGD nodes -from the same PGD group. In this operation mode, each node in the pair knows -the outcome of any recent transaction executed on the other peer and especially -(for our need) knows the outcome of any transaction disconnected during COMMIT. -The node that receives the transactions from the application might be referred -to as "origin" and the node that confirms these transactions as "partner." -However, there's no difference in the CAMO configuration for the nodes in the -CAMO pair. The pair is symmetric. +One way to avoid this situation is to make sure that the transaction includes at least one `INSERT` into a table with a unique index. However, that depends on the application design and requires application-specific error-handling logic, so it isn't effective in all cases. + +The CAMO feature in PGD offers a more general solution and doesn't require an `INSERT`. When activated by `bdr.commit_scope`, the application receives a message containing the transaction identifier, if already assigned. Otherwise, the first write statement in a transaction sends that information to the client. + +If the application sends an explicit `COMMIT`, the protocol ensures that the application receives the notification of the transaction identifier before the `COMMIT` is sent. If the server doesn't reply to the `COMMIT`, the application can handle this error by using the transaction identifier to request the final status of the transaction from another PGD node. If the prior transaction status is known, then the application can safely decide whether to retry the transaction. + +CAMO works by creating a pair of partner nodes that are two PGD nodes from the same PGD group. In this operation mode, each node in the pair knows the outcome of any recent transaction executed on the other peer and especially (for our need) knows the outcome of any transaction disconnected during `COMMIT`. The node that receives the transactions from the application might be referred to as "origin" and the node that confirms these transactions as "partner." However, there's no difference in the CAMO configuration for the nodes in the CAMO pair. The pair is symmetric. !!! Warning - CAMO requires changes to the user's application to take advantage of the - advanced error handling. Enabling a parameter isn't enough to gain - protection. Reference client implementations are provided to customers - on request. + CAMO requires changes to the user's application to take advantage of the advanced error handling. Enabling a parameter isn't enough to gain protection. Reference client implementations are provided to customers on request. ## Requirements -To use CAMO, an application must issue an explicit COMMIT message -as a separate request (not as part of a multi-statement request). -CAMO can't provide status for transactions issued from procedures -or from single-statement transactions that use implicit commits. +To use CAMO, an application must issue an explicit `COMMIT` message as a separate request, not as part of a multi-statement request. CAMO can't provide status for transactions issued from procedures or from single-statement transactions that use implicit commits. ## Configuration -Configuration of CAMO happens through [Commit Scopes](commit-scopes). +Configuration of CAMO happens through [commit scopes](commit-scopes). ## Failure scenarios -Different failure scenarios occur in different -configurations. +Different failure scenarios occur in different configurations. ### Data persistence at receiver side -By default, a PGL writer operates in -`bdr.synchronous_commit = off` mode when applying transactions -from remote nodes. This holds true for CAMO as well, meaning that -transactions are confirmed to the origin node possibly before reaching -the disk of the CAMO partner. In case of a crash or hardware failure, -it is possible for a confirmed transaction to be unrecoverable on the -CAMO partner by itself. This isn't an issue as long as the CAMO -origin node remains operational, as it redistributes the -transaction once the CAMO partner node recovers. - -This in turn means CAMO can protect against a single-node failure, -which is correct for local mode as well as or even in combination -with remote write. - -To cover an outage of both nodes of a CAMO pair, you can use -`bdr.synchronous_commit = local` to enforce a flush prior to the -pre-commit confirmation. This doesn't work with -either remote write or local mode and has a performance -impact due to I/O requirements on the CAMO partner in the -latency sensitive commit path. +By default, a PGL writer operates in `bdr.synchronous_commit = off` mode when applying transactions from remote nodes. This holds true for CAMO as well, meaning that transactions are confirmed to the origin node possibly before reaching the disk of the CAMO partner. In case of a crash or hardware failure, a confirmed transaction might be unrecoverable on the CAMO partner by itself. This isn't an issue as long as the CAMO origin node remains operational, as it redistributes the transaction once the CAMO partner node recovers. + +This in turn means CAMO can protect against a single-node failure, which is correct for local mode as well as or even in combination with remote write. + +To cover an outage of both nodes of a CAMO pair, you can use `bdr.synchronous_commit = local` to enforce a flush prior to the pre-commit confirmation. This doesn't work with either remote write or local mode and has a performance impact due to I/O requirements on the CAMO partner in the latency sensitive commit path. ### Asynchronous mode -When `DEGRADE ON ... TO ASYNC` clause is used in the commit scope -a node detects whether its CAMO partner is ready. If not, it temporarily -switches to asynchronous (local) mode. When in this mode, a node commits -transactions locally until switching back to CAMO mode. - -This doesn't allow COMMIT status to be retrieved, but it does -let you choose availability over consistency. This mode -can tolerate a single-node failure. In case both nodes of a CAMO pair -fail, they might choose incongruent commit decisions to maintain -availability, leading to data inconsistencies. - -For a CAMO partner to switch to ready, it needs to be connected, and -the estimated catchup interval needs to drop below -the `timeout` value of `TO ASYNC`. The current readiness status of a CAMO -partner can be checked with `bdr.is_camo_partner_ready`, while -`bdr.node_replication_rates` provides the current estimate of the catchup -time. - -The switch from CAMO protected to asynchronous mode is only ever triggered by -an actual CAMO transaction either because the commit exceeds the -`timeout` value of `TO ASYNC` or, in case the CAMO partner is already -known, disconnected at the time of commit. This switch is independent -of the estimated catchup interval. If the CAMO pair is configured to -require the current node to be the write lead of a group as configured -through `enable_proxy_routing` node group option. See -[Commit Scopes](commit-scopes) syntax. -This can prevent a split brain situation due to an isolated node from -switching to asynchronous mode. If `enable_proxy_routing` isn't set for the -CAMO group, the origin node switches to asynchronous mode immediately. - -The switch from asynchronous mode to CAMO mode depends on the CAMO partner -node, which initiates the connection. The CAMO partner tries to -reconnect at least every 30 seconds. After connectivity is -reestablished, it might therefore take up to 30 seconds until the CAMO -partner connects back to its origin node. Any lag that accumulated on -the CAMO partner further delays the switch back to CAMO protected -mode. - -Unlike during normal CAMO operation, in asynchronous mode there's no -additional commit overhead. This can be problematic, as it allows the -node to continuously process more transactions than the CAMO -pair can normally process. Even if the CAMO partner eventually -reconnects and applies transactions, its lag only ever increases -in such a situation, preventing reestablishing the CAMO protection. -To artificially throttle transactional throughput, PGD provides the -`bdr.camo_local_mode_delay` setting, which allows you to delay a COMMIT in -local mode by an arbitrary amount of time. We recommend measuring -commit times in normal CAMO mode during expected workloads and -configuring this delay accordingly. The default is 5 ms, which reflects -a asynchronous network and a relatively quick CAMO partner response. - -Consider the choice of whether to allow asynchronous mode in view of -the architecture and the availability requirements. The following examples -provide some detail. +When the `DEGRADE ON ... TO ASYNC` clause is used in the commit scope, a node detects whether its CAMO partner is ready. If not, it temporarily switches to asynchronous (local) mode. When in this mode, a node commits transactions locally until switching back to CAMO mode. + +This doesn't allow COMMIT status to be retrieved, but it does let you choose availability over consistency. This mode can tolerate a single-node failure. In case both nodes of a CAMO pair fail, they might choose incongruent commit decisions to maintain availability, leading to data inconsistencies. + +For a CAMO partner to switch to ready, it needs to be connected, and the estimated catchup interval needs to drop below the `timeout` value of `TO ASYNC`. You can check the current readiness status of a CAMO partner with `bdr.is_camo_partner_ready`, while `bdr.node_replication_rates` provides the current estimate of the catchup time. + + +The switch from CAMO protected to asynchronous mode is only ever triggered by an actual CAMO transaction either because the commit exceeds the `timeout` value of `TO ASYNC` or, in case the CAMO partner is already +known, disconnected at the time of commit. This switch is independent of the estimated catchup interval. If the CAMO pair is configured to require the current node to be the write lead of a group as configured through `enable_proxy_routing` node group option. See [Commit scopes](commit-scopes) for syntax. This can prevent a split brain situation due to an isolated node from switching to asynchronous mode. If `enable_proxy_routing` isn't set for the CAMO group, the origin node switches to asynchronous mode immediately. + +The switch from asynchronous mode to CAMO mode depends on the CAMO partner node, which initiates the connection. The CAMO partner tries to reconnect at least every 30 seconds. After connectivity is reestablished, it might therefore take up to 30 seconds until the CAMO partner connects back to its origin node. Any lag that accumulated on +the CAMO partner further delays the switch back to CAMO protected mode. + +Unlike during normal CAMO operation, in asynchronous mode there's no added commit overhead. This can be problematic, as it allows the node to continuously process more transactions than the CAMO pair can normally process. Even if the CAMO partner eventually reconnects and applies transactions, its lag only ever increases +in such a situation, preventing reestablishing the CAMO protection. To artificially throttle transactional throughput, PGD provides the `bdr.camo_local_mode_delay` setting, which allows you to delay a `COMMIT` in local mode by an arbitrary amount of time. We recommend measuring commit times in normal CAMO mode during expected workloads and configuring this delay accordingly. The default is 5 ms, which reflects a asynchronous network and a relatively quick CAMO partner response. + +Consider the choice of whether to allow asynchronous mode in view of the architecture and the availability requirements. The following examples provide some detail. ### Example -This example considers a setup with two PGD nodes that are the -CAMO partner of each other. +This example considers a setup with two PGD nodes that are the CAMO partner of each other. ```sql -- create a CAMO commit scope for a group over @@ -166,61 +81,38 @@ SELECT bdr.add_commit_scope( rule := 'ALL (left_dc) CAMO DEGRADE ON (timeout=500ms) TO ASYNC' ); ``` -For this CAMO commit scope to be legal, the number of nodes in the group -must equal exactly 2. Using ALL or ANY 2 on a group consisting of several -nodes is an error because the unquantified group expression does not resolve +For this CAMO commit scope to be legal, the number of nodes in the group must equal exactly 2. Using ALL or ANY 2 on a group consisting of several nodes is an error because the unquantified group expression doesn't resolve to a definite pair of nodes. #### With asynchronous mode -If asynchronous mode is allowed, there's no single point of failure. When one -node fails: +If asynchronous mode is allowed, there's no single point of failure. When one node fails: -* The other node can determine the status of all transactions that - were disconnected during COMMIT on the failed node. -* New write transactions are allowed: - * If the second node also fails, then the outcome of those - transactions that were being committed at that time is - unknown. +- The other node can determine the status of all transactions that were disconnected during `COMMIT` on the failed node. +- New write transactions are allowed. If the second node also fails, then the outcome of those transactions that were being committed at that time is unknown. #### Without asynchronous mode -If asynchronous mode isn't allowed, then each node requires the other node -for committing transactions, that is, each node is a single point of -failure. When one node fails: +If asynchronous mode isn't allowed, then each node requires the other node for committing transactions, that is, each node is a single point of failure. When one node fails: -* The other node can determine the status of all transactions that - were disconnected during COMMIT on the failed node. -* New write transactions are prevented until the node recovers. +- The other node can determine the status of all transactions that were disconnected during `COMMIT` on the failed node. +- New write transactions are prevented until the node recovers. ## Application use ### Overview and requirements -CAMO relies on a retry loop and specific error handling -on the client side. There are three aspects to it: +CAMO relies on a retry loop and specific error handling on the client side. There are three aspects to it: -* The result of a transaction's COMMIT needs to be checked and, in - case of a temporary error, the client must retry the transaction. -* Prior to COMMIT, the client must retrieve a global - identifier for the transaction, consisting of a node id and a - transaction id (both 32-bit integers). -* If the current server fails while attempting a COMMIT of a transaction, - the application must connect to its CAMO partner, retrieve the status - of that transaction, and retry depending on the response. +- The result of a transaction's `COMMIT` needs to be checked and, in case of a temporary error, the client must retry the transaction. +- Prior to `COMMIT`, the client must retrieve a global identifier for the transaction, consisting of a node id and a transaction id (both 32-bit integers). +- If the current server fails while attempting a `COMMIT` of a transaction, the application must connect to its CAMO partner, retrieve the status of that transaction, and retry depending on the response. -The application must store the global transaction -identifier only for the purpose of verifying the transaction status in -case of disconnection during COMMIT. In particular, the application -doesn't need an additional persistence layer. If the application -fails, it needs only the information in the database to restart. +The application must store the global transaction identifier only for the purpose of verifying the transaction status in case of disconnection during `COMMIT`. In particular, the application doesn't need another persistence layer. If the application fails, it needs only the information in the database to restart. ### CAMO partner connection status -The function `bdr.is_camo_partner_connected` allows checking the -connection status of a CAMO partner node configured in pair mode. -There currently is no equivalent for CAMO used with -Eager Replication. +The function `bdr.is_camo_partner_connected` allows checking the connection status of a CAMO partner node configured in pair mode. There currently is no equivalent for CAMO used with eager replication. #### Synopsis @@ -230,15 +122,11 @@ bdr.is_camo_partner_connected() #### Return value -A Boolean value indicating whether the CAMO partner is currently -connected to a WAL sender process on the local node and therefore can -receive transactional data and send back confirmations. +A Boolean value indicating whether the CAMO partner is currently connected to a WAL sender process on the local node and therefore can receive transactional data and send back confirmations. ### CAMO partner readiness -The function `bdr.is_camo_partner_ready` allows checking the readiness -status of a CAMO partner node configured in pair mode. Underneath, -this triggers the switch to and from local mode. +The function `bdr.is_camo_partner_ready` allows checking the readiness status of a CAMO partner node configured in pair mode. Underneath, this triggers the switch to and from local mode. #### Synopsis @@ -248,19 +136,14 @@ bdr.is_camo_partner_ready() #### Return value -A Boolean value indicating whether the CAMO partner can reasonably be -expected to confirm transactions originating from the local node in a -timely manner (before `timeout` for `TO ASYNC` expires). +A Boolean value indicating whether the CAMO partner can reasonably be expected to confirm transactions originating from the local node in a timely manner, that is, before `timeout` for `TO ASYNC` expires. !!! Note - This function queries the past or current state. A - positive return value doesn't indicate whether the CAMO partner can - confirm future transactions. + This function queries the past or current state. A positive return value doesn't indicate whether the CAMO partner can confirm future transactions. ### Fetch the CAMO partner -This function shows the local node's CAMO partner (configured by pair -mode). +This function shows the local node's CAMO partner (configured by pair mode). ```sql bdr.get_configured_camo_partner() @@ -268,9 +151,7 @@ bdr.get_configured_camo_partner() ### Wait for consumption of the apply queue from the CAMO partner -The function `bdr.wait_for_camo_partner_queue` is a wrapper of -`bdr.wait_for_apply_queue` defaulting to query the CAMO partner node. -It yields an error if the local node isn't part of a CAMO pair. +The function `bdr.wait_for_camo_partner_queue` is a wrapper of `bdr.wait_for_apply_queue` defaulting to query the CAMO partner node. It returns an error if the local node isn't part of a CAMO pair. #### Synopsis @@ -288,35 +169,23 @@ bdr.camo_transactions_resolved() ### Transaction status query function -To check the status of a transaction that was being committed when the node -failed, the application must use this function: +To check the status of a transaction that was being committed when the node failed, the application must use this function: ```sql bdr.logical_transaction_status(node_id OID, xid OID, require_camo_partner boolean) ``` -With CAMO used in pair mode, use this function only on -a node that's part of a CAMO pair. Along with Eager +With CAMO used in pair mode, use this function only on a node that's part of a CAMO pair. Along with eager replication, you can use it on all nodes. -In both cases, you must call the function within 15 minutes after -the commit was issued. The CAMO partner must regularly purge -such meta-information and therefore can't provide correct answers for -older transactions. +In both cases, you must call the function within 15 minutes after the commit was issued. The CAMO partner must regularly purge such meta-information and therefore can't provide correct answers for older transactions. -Before querying the status of a transaction, this function waits for -the receive queue to be consumed and fully applied. This prevents -early negative answers for transactions that were -received but not yet applied. +Before querying the status of a transaction, this function waits for the receive queue to be consumed and fully applied. This mechanism prevents early negative answers for transactions that were received but not yet applied. -Despite its name, it's not always a read-only operation. -If the status is unknown, the CAMO partner decides whether to -commit or abort the transaction, storing that decision locally to -ensure consistency going forward. +Despite its name, it's not always a read-only operation. If the status is unknown, the CAMO partner decides whether to commit or abort the transaction, storing that decision locally to ensure consistency going forward. -The client must not call this function before -attempting to commit on the origin. Otherwise the transaction might be +The client must not call this function before attempting to commit on the origin. Otherwise the transaction might be forced to roll back. #### Synopsis @@ -328,83 +197,40 @@ bdr.logical_transaction_status(node_id OID, xid OID, #### Parameters -- `node_id` — The node id of the PGD node the transaction originates - from, usually retrieved by the client before COMMIT from the PQ - parameter `bdr.local_node_id`. -- `xid` — The transaction id on the origin node, usually retrieved by - the client before COMMIT from the PQ parameter `transaction_id` -- `require_camo_partner` — Defaults to true and enables configuration - checks. Set to false to disable these checks and query the - status of a transaction that was not a CAMO transaction. +- `node_id` — The node id of the PGD node the transaction originates from, usually retrieved by the client before `COMMIT` from the PQ parameter `bdr.local_node_id`. +- `xid` — The transaction id on the origin node, usually retrieved by the client before `COMMIT` from the PQ parameter `transaction_id`. +- `require_camo_partner` — Defaults to true and enables configuration checks. Set to false to disable these checks and query the status of a transaction that was not a CAMO transaction. #### Return value The function returns one of these results: -- `'committed'::TEXT` — The transaction was committed, is visible - on both nodes of the CAMO pair, and will eventually be replicated to - all other PGD nodes. No need for the client to retry it. - -- `'aborted'::TEXT` — The transaction was aborted and will not be - replicated to any other PGD node. The client needs to either - retry it or escalate the failure to commit the transaction. - -- `'in progress'::TEXT` — The transaction is still in progress on this - local node and wasn't committed or aborted yet. The transaction might be in the COMMIT phase, waiting for - the CAMO partner to confirm or deny the commit. The recommended - client reaction is to disconnect from the origin node and reconnect - to the CAMO partner to query that instead. With a load balancer or proxy - in between, where the client lacks control over which node gets - queried, the client can only poll repeatedly until the status - switches to either `'committed'` or `'aborted'`. - - For Eager All-Node Replication, peer nodes yield this result for - transactions that aren't yet committed or aborted. This means that - even transactions not yet replicated (or not even started on the - origin node) might yield an `in progress` result on a peer PGD node in - this case. However, the client must not query the transaction +- `'committed'::TEXT` — The transaction was committed, is visible on both nodes of the CAMO pair, and is eventually replicated to all other PGD nodes. No need for the client to retry it. + +- `'aborted'::TEXT` — The transaction was aborted and isn't replicated to any other PGD node. The client needs to either retry it or escalate the failure to commit the transaction. + +- `'in progress'::TEXT` — The transaction is still in progress on this local node and wasn't committed or aborted yet. The transaction might be in the COMMIT phase, waiting for the CAMO partner to confirm or deny the commit. The recommended client reaction is to disconnect from the origin node and reconnect to the CAMO partner to query that instead. With a load balancer or proxy in between, where the client lacks control over which node gets queried, the client can only poll repeatedly until the status switches to either `'committed'` or `'aborted'`. + + For eager all-node replication, peer nodes yield this result for transactions that aren't yet committed or aborted. Even transactions not yet replicated (or not even started on the origin node) might yield an `in progress` result on a peer PGD node in this case. However, the client must not query the transaction status prior to attempting to commit on the origin. -- `'unknown'::TEXT` — The transaction specified is unknown, either - because it's in the future, not replicated to that specific node - yet, or too far in the past. The status of such a transaction is - not yet or no longer known. This return value is a sign of improper - use by the client. +- `'unknown'::TEXT` — The transaction specified is unknown, because either it's in the future, not replicated to that specific node yet, or too far in the past. The status of such a transaction isn't yet or is no longer known. This return value is a sign of improper use by the client. The client must be prepared to retry the function call on error. ### Connection pools and proxies -The effect of connection pools and proxies needs to be considered when -designing a CAMO cluster. A proxy may freely distribute transactions -to all nodes in the commit group (i.e. to both nodes of a CAMO pair or -to all PGD nodes in case of Eager All Node Replication). - -Care needs to be taken to ensure that the application fetches -the proper node id: when using session pooling, the client remains -connected to the same node, so the node id remains constant for the -lifetime of the client session. However, with finer-grained transaction -pooling, the client needs to fetch the node id for every transaction (as -in the example given below). - -A client that is not directly connected to the PGD nodes might not even -notice a failover or switchover, but can always use the -`bdr.local_node_id` parameter to determine which node it is currently -connected to. In the crucial situation of a disconnect during COMMIT, -the proxy must properly forward that disconnect as an error to the -client applying the CAMO protocol. - -For CAMO in `received` mode, a proxy that potentially switches -between the CAMO pairs must use the `bdr.wait_for_camo_partner_queue` -function to prevent stale reads. +Consider the effect of connection pools and proxies when designing a CAMO cluster. A proxy might freely distribute transactions to all nodes in the commit group, that is, to both nodes of a CAMO pair or to all PGD nodes in case of eager all node replication). + +Take care to ensure that the application fetches the proper node id. When using session pooling, the client remains connected to the same node, so the node id remains constant for the lifetime of the client session. However, with finer-grained transaction pooling, the client needs to fetch the node id for every transaction (as in the example that follows. + +A client that isn't directly connected to the PGD nodes might not even notice a failover or switchover. But it can always use the `bdr.local_node_id` parameter to determine which node it's currently connected to. In the crucial situation of a disconnect during COMMIT, the proxy must properly forward that disconnect as an error to the client applying the CAMO protocol. + +For CAMO in `received` mode, a proxy that potentially switches between the CAMO pairs must use the `bdr.wait_for_camo_partner_queue` function to prevent stale reads. ### Example -The following example demonstrates what a retry loop of a CAMO aware -client application should look like in C-like pseudo-code. It expects -two DSNs `origin_dsn` and `partner_dsn` providing connection information. -These usually are the same DSNs as used for the initial call to -`bdr.create_node`, and can be looked up in `bdr.node_summary`, column +This example shows what a retry loop of a CAMO-aware client application looks like in C-like pseudo-code. It expects two DSNs `origin_dsn` and `partner_dsn` providing connection information. These usually are the same DSNs as used for the initial call to `bdr.create_node` and can be looked up in `bdr.node_summary`, column `interface_connstr`. ```shell @@ -462,37 +288,21 @@ loop { } ``` -This example needs to be extended with proper logic for connecting, including -retries and error handling. If using a load balancer -(e.g. PgBouncer), re-connecting can be implemented by simply using -`PQreset`. Ensure that the load balancer only -ever redirects a client to a CAMO partner and not any other PGD node. +This example needs to be extended with proper logic for connecting, including retries and error handling. If using a load balancer like PgBouncer, you can implement reconnecting by using `PQreset`. Ensure that the load balancer only ever redirects a client to a CAMO partner and not any other PGD node. -In practice, an upper limit of retries is recommended. Depending on the -actions performed in the transaction, other temporary errors may be -possible and need to be handled by retrying the transaction depending -on the error code, similarly to the best practices on deadlocks or on -serialization failures while in `SERIALIZABLE` isolation mode. +In practice, we recommend an upper limit of retries. Depending on the actions performed in the transaction, other temporary errors might be possible. They need to be handled by retrying the transaction depending on the error code, similarly to the best practices on deadlocks or on serialization failures while in `SERIALIZABLE` isolation mode. ## Interaction with DDL and global locks -Transactions protected by CAMO can contain DDL operations. However, DDL uses global locks, which already provide some -synchronization among nodes. See -[DDL locking details](../ddl#ddl-locking-details) for more -information. +Transactions protected by CAMO can contain DDL operations. However, DDL uses global locks, which already provide some synchronization among nodes. See [DDL locking details](../ddl#ddl-locking-details) for more information. -Combining CAMO with DDL imposes a higher latency and also -increases the chance of global deadlocks. We therefore recommend using a -relatively low `bdr.global_lock_timeout`, which aborts the DDL and -therefore resolves a deadlock in a reasonable amount of time. +Combining CAMO with DDL imposes a higher latency and also increases the chance of global deadlocks. We therefore recommend using a relatively low `bdr.global_lock_timeout`, which aborts the DDL and therefore resolves a deadlock in a reasonable amount of time. ### Nontransactional DDL -The following DDL operations aren't allowed in a transaction -block and therefore can't benefit from CAMO protection. For -these, CAMO is automatically disabled internally: +The following DDL operations aren't allowed in a transaction block and therefore can't benefit from CAMO protection. For these, CAMO is automatically disabled internally: -* all concurrent index operations (`CREATE`, `DROP`, and `REINDEX`) +* All concurrent index operations (`CREATE`, `DROP`, and `REINDEX`) * `REINDEX DATABASE`, `REINDEX SCHEMA`, and `REINDEX SYSTEM` * `VACUUM` * `CLUSTER` without any parameter @@ -505,55 +315,25 @@ these, CAMO is automatically disabled internally: ## CAMO limitations -- CAMO is designed to query the results of a recently failed COMMIT on -the origin node, so in case of disconnection, code the application -to immediately request the transaction status from the CAMO partner. -Have as little delay as possible after the failure before -requesting the status. Applications must not rely on CAMO decisions -being stored for longer than 15 minutes. - -- If the application forgets the global identifier assigned, for example -as a result of a restart, there's no easy way to recover -it. Therefore, we recommend that applications wait for outstanding -transactions to end before shutting down. - -- For the client to apply proper checks, a transaction protected by CAMO -can't be a single statement with implicit transaction control. You also can't -use CAMO with a transaction-controlling procedure or -in a `DO` block that tries to start or end transactions. - -- CAMO resolves commit status but doesn't yet resolve pending -notifications on commit. CAMO and Eager replication options don't -allow the `NOTIFY` SQL command or the `pg_notify()` function. -They also don't allow `LISTEN` or `UNLISTEN`. - -- When replaying changes, CAMO transactions may detect conflicts just -the same as other transactions. If timestamp conflict detection is used, -the CAMO transaction uses the timestamp of the prepare on the origin -node, which is before the transaction becomes visible on the origin -node itself. - -- CAMO is not currently compatible with transaction streaming. Please -ensure to disable transaction streaming when planning to use -CAMO. This can be configured globally or in the PGD node group, see -[Transaction Streaming Configuration](../transaction-streaming#configuration). +- CAMO is designed to query the results of a recently failed `COMMIT` on the origin node, so in case of disconnection, code the application to immediately request the transaction status from the CAMO partner. Have as little delay as possible after the failure before requesting the status. Applications must not rely on CAMO decisions being stored for longer than 15 minutes. + +- If the application forgets the global identifier assigned, for example as a result of a restart, there's no easy way to recover it. Therefore, we recommend that applications wait for outstanding transactions to end before shutting down. + +- For the client to apply proper checks, a transaction protected by CAMO can't be a single statement with implicit transaction control. You also can't use CAMO with a transaction-controlling procedure or in a `DO` block that tries to start or end transactions. + +- CAMO resolves commit status but doesn't yet resolve pending notifications on commit. CAMO and eager replication options don't allow the `NOTIFY` SQL command or the `pg_notify()` function. They also don't allow `LISTEN` or `UNLISTEN`. + +- When replaying changes, CAMO transactions can detect conflicts just the same as other transactions. If timestamp conflict detection is used, the CAMO transaction uses the timestamp of the prepare on the origin node, which is before the transaction becomes visible on the origin node itself. + +- CAMO isn't currently compatible with transaction streaming. Be sure to disable transaction streaming when planning to use CAMO. YOu can configure this globally or in the PGD node group. See [Transaction streaming configuration](../transaction-streaming#configuration). ## Performance implications -CAMO extends the Postgres replication protocol by adding a -message roundtrip at commit. Applications have a higher -commit latency than with asynchronous replication, mostly determined -by the roundtrip time between involved nodes. Increasing the number -of concurrent sessions can help to increase parallelism to -obtain reasonable transaction throughput. +CAMO extends the Postgres replication protocol by adding a message roundtrip at commit. Applications have a higher +commit latency than with asynchronous replication, mostly determined by the roundtrip time between involved nodes. Increasing the number of concurrent sessions can help to increase parallelism to obtain reasonable transaction throughput. -The CAMO partner confirming transactions must store transaction -states. Compared to non-CAMO operation, this might require an -additional seek for each transaction applied from the origin. +The CAMO partner confirming transactions must store transaction states. Compared to non-CAMO operation, this might require an added seek for each transaction applied from the origin. ## Client application testing -Proper use of CAMO on the client side isn't trivial. We strongly -recommend testing the application behavior with the PGD -cluster against failure scenarios such as node crashes or network -outages. +Proper use of CAMO on the client side isn't trivial. We strongly recommend testing the application behavior with the PGD cluster against failure scenarios such as node crashes or network outages. diff --git a/product_docs/docs/pgd/5/durability/commit-scopes.mdx b/product_docs/docs/pgd/5/durability/commit-scopes.mdx index a04df998fe6..6ca5ac30258 100644 --- a/product_docs/docs/pgd/5/durability/commit-scopes.mdx +++ b/product_docs/docs/pgd/5/durability/commit-scopes.mdx @@ -1,21 +1,14 @@ --- -title: Commit Scopes +title: Commit scopes --- -Commit Scopes give applications granular control about durability and -consistency of EDB Postgres Distributed. +Commit scopes give applications granular control about durability and consistency of EDB Postgres Distributed. -A Commit Scope is a named rule that describes behavior of COMMIT replication. -The actual behavior depends on whether a Commit Scope uses -[Group Commit](group-commit), [Commit At Most Once](camo), -[Lag Control](lag-control) or combination of these. +A commit scope is a named rule that describes behavior of COMMIT replication. The actual behavior depends on whether a commit scope uses [group commit](group-commit), [Commit At Most Once](camo), [lag control](lag-control), or combination of these. ## Configuration -To use Group Commit, first define a commit scope. This -determines the BDR nodes involved in the commit of a transaction. -Once a scope is established, you can configure a transaction to use -Group Commit as follows: +To use group commit, first define a commit scope, which determines the PGD nodes involved in the commit of a transaction. Once a scope is established, you can configure a transaction to use group commit as follows: ```sql BEGIN; @@ -24,7 +17,7 @@ SET LOCAL bdr.commit_scope = 'example_scope'; COMMIT; ``` -The commit scope must be set before the transaction has written any data. +You must set the commit scope before the transaction writes any data. For this example, you might previously have defined the commit scope as: @@ -37,29 +30,14 @@ SELECT bdr.add_commit_scope( ); ``` -This assumes a *node group* named `example_bdr_group` exists and -includes at least two BDR nodes as members, either directly or in -subgroups. Any transaction committed in the `example_scope` -requires one extra confirmation from a BDR node in the group. -Together with the origin node, this accounts for "ANY 2" nodes out of -the group, on which the transaction is guaranteed to be visible and -durable after the commit. +This example assumes a *node group* named `example_bdr_group` exists and includes at least two PGD nodes as members, either directly or in subgroups. Any transaction committed in the `example_scope` requires one extra confirmation from a PGD node in the group. Together with the origin node, this accounts for "ANY 2" nodes out of the group, on which the transaction is guaranteed to be visible and durable after the commit. ### Origin groups -Rules for commit scopes can depend on the node the transaction is -committed on, that is, the node that acts as the origin for the transaction. -To make this transparent for the application, BDR allows a commit -scope to define different rules depending on where the transaction -originates from. +Rules for commit scopes can depend on the node the transaction is committed on, that is, the node that acts as the origin for the transaction. To make this transparent for the application, PGD allows a commit scope to define different rules depending on where the transaction originates from. -For example, consider a EDB Postgres Distributed cluster with nodes -spread across two data centers: a left and a right one. -Assume the top-level BDR node group -is called `top_group`. You can use the following commands to set up -subgroups and create a commit scope requiring all nodes in the local -data center to confirm the transaction but only one node from the -remote one. +For example, consider an EDB Postgres Distributed cluster with nodes spread across two data centers: a left and a right one. Assume the top-level PGD node group is called `top_group`. You can use the following commands to set up +subgroups and create a commit scope requiring all nodes in the local data center to confirm the transaction but only one node from the remote one: ```sql -- create sub-groups @@ -90,16 +68,11 @@ SELECT bdr.add_commit_scope( ); ``` -Now using the `example_scope` on any node that's part of `left_dc` will use the -first scope, while using same scope on node that's part of `right_dc` will -use the second scope. This is effective way of creating inverted scope without -having to juggle scope names in application. +Now, using the `example_scope` on any node that's part of `left_dc` uses the first scope. Using the same scope on a node that's part of `right_dc` uses the second scope. This is effective way of creating inverted scope without having to juggle scope names in application. -In addition to this, each group can also have default commit scope specified using -`bdr.alter_node_group_option` admin interface. +Each group can also have a default commit scope specified using the `bdr.alter_node_group_option` admin interface. -So making the above scopes the default ones for all transactions originatin on -nodes withing those groups would look like this. +Making the above scopes the default ones for all transactions originating on nodes in those groups looks like this: ```sql SELECT bdr.alter_node_group_option( @@ -116,32 +89,24 @@ SELECT bdr.alter_node_group_option( ### Confirmation levels -BDR nodes can send confirmations for a transaction at different points -in time. In increasing levels of protection, from the perspective of the -confirming node, these are: +PGD nodes can send confirmations for a transaction at different times. In increasing levels of protection, from the perspective of the confirming node, these are: -* `received` — A remote BDR node confirms the transaction immediately - after receiving it, prior to starting the local application. -* `replicated` — Confirm after applying changes of the transaction - but before flushing them to disk. -* `durable` — Confirm the transaction after all of its changes are - flushed to disk. -* `visible` (default) — Confirm the transaction after all of its - changes are flushed to disk and it's visible to - concurrent transactions. +- `received` — A remote PGD node confirms the transaction immediately after receiving it, prior to starting the local application. +- `replicated` — Confirms after applying changes of the transaction but before flushing them to disk. +- `durable` — Confirms the transaction after all of its changes are flushed to disk. +- `visible` (default) — Confirms the transaction after all of its changes are flushed to disk and it's visible to concurrent transactions. -In rules for commit scopes, you can append these confirmation levels -to the node group definition in parenthesis with `ON` as follows: +In rules for commit scopes, you can append these confirmation levels to the node group definition in parentheses with `ON` as follows: -* `ANY 2 (right_dc) ON replicated` -* `ALL (left_dc) ON visible` (default and may as well be omitted) -* `ALL (left_dc) ON received AND ANY 1 (right_dc) ON durable` +- `ANY 2 (right_dc) ON replicated` +- `ALL (left_dc) ON visible` (default) +- `ALL (left_dc) ON received AND ANY 1 (right_dc) ON durable` ## Reference ### Commit scope grammar -For reference, the grammar for commit scopes is composed as follows: +The grammar for commit scopes is composed as follows: ``` commit_scope: @@ -163,63 +128,32 @@ commit_scope_kind: #### Parameters -* `node_group` - name of a node group -* `( group_commit_parameter = value )` - options for Group Commit - * `transaction_tracking` (boolean) - specifies whether status of - transaction should be tracked - * `conflict_resolution` (enum) - how to handle conflicts, possible values - are either `async` meaning conflicts should be resolved asynchronously - after during replication using the conflict resolution policy or `eager` - meaning that conflicts are resolved eagerly during COMMIT by aborting - one of the conflicting transactions - * `commit_decision` (enum) - how is COMMIT decision made, it can be either - `group` meaning the `commit_scope_group` specification also affects the - COMMIT decision, not just durability, it can also be `partner` which means - partner node decides whether transaction can be committed (this is only - allowed on 2 data node groups) or it can be `raft` which means COMMIT - decision is done using Raft consensus independently of `commit_scope_group` - consensus. -* `ABORT ON ( abort_on_parameter = value )` - allows automatic transaction - abort on timeout - * `timeout` (interval) - timeout in milliseconds (accepts other units) -* `DEGRADE ON ( degrade_on_parameter = value )` - allows degrading to asynchronous - operation on timeout - * `timeout` (interval) - timeout in milliseconds (accepts other units) after - which operation becomes asynchronous - * `require_write_lead` (boolean) - whether the node has to be a write lead to - to be able to switch to asynchronous mode -* `( lag_control_parameter = value )` - options for Lag Control - * `max_lag_size` (int) - maximum allowed lag based on WAL bytes - * `max_lag_time` (interval) - maximum allowed lag based on wall clock sampling - * `max_commit_delay` (interval) - maximum delay that can be injected to - commit in order to try to keep within the lag limits +* `node_group` — Name of a node group. +* `( group_commit_parameter = value )` — Options for group commit. + * `transaction_tracking` (Boolean) — Specifies whether to track status of transaction. + * `conflict_resolution` (enum) — Specifies how to handle conflicts. Possible values are `async`, meaning to resolve conflicts asynchronously during replication using the conflict resolution policy, or `eager` meaning that conflicts are resolved eagerly during COMMIT by aborting one of the conflicting transactions. + * `commit_decision` (enum) — Specifies how the COMMIT decision is made. The value `group` means the `commit_scope_group` specification also affects the COMMIT decision, not just durability. The value `partner` means the partner node decides whether transactions can be committed. This value is allowed only on 2 data node groups. The value `raft` means the COMMIT decision is done using Raft consensus independent of `commit_scope_group` consensus. +* `ABORT ON ( abort_on_parameter = value )` — Allows automatic transaction abort on timeout. + * `timeout` (interval) — Timeout in milliseconds (accepts other units). +* `DEGRADE ON ( degrade_on_parameter = value )` — Allows degrading to asynchronous operation on timeout + * `timeout` (interval) — Timeout in milliseconds (accepts other units) after which operation becomes asynchronous. + * `require_write_lead` (Boolean) — Specifies whether the node must be a write lead to be able to switch to asynchronous mode. +* `( lag_control_parameter = value )` — Options for lag control: + * `max_lag_size` (int) — Maximum allowed lag based on WAL bytes. + * `max_lag_time` (interval) — Maximum allowed lag based on wall clock sampling. + * `max_commit_delay` (interval) — Maximum delay that can be injected to commit to try to keep within the lag limits. !!! Note - `CAMO` commit scope kind is mostly syntax sugar for - `GROUP COMMIT (transaction_tracking = true, commit_decision = partner)` with - additional `DEGRADE ON` clause. It's expected that `GROUP COMMIT` will - eventually gain `DEGRADE ON` clause as well, making `CAMO` syntax deprecated. + `CAMO` commit scope kind is mostly syntactic sugar for `GROUP COMMIT (transaction_tracking = true, commit_decision = partner)` with additional `DEGRADE ON` clause. It's expected that `GROUP COMMIT` will eventually gain the `DEGRADE ON` clause as well, making `CAMO` syntax deprecated. !!! Note - While the grammar for `synchronous_standby_names` and Commit - Scopes can loo very similar, it is important to note that the former - does not account for the origin node, but the latter does. - Therefore, for example `synchronous_standby_names = 'ANY 1 (..)'` - is equivalent to a Commit Scope of `ANY 2 (...)`. This choice - makes reasoning about majority easier and reflects that the origin - node also contributes to the durability and visibility of the - transaction. + While the grammar for `synchronous_standby_names` and commit scopes can look similar, the former doesn't account for the origin node, but the latter does. Therefore, for example `synchronous_standby_names = 'ANY 1 (..)'` is equivalent to a commit scope of `ANY 2 (...)`. This choice makes reasoning about majority easier and reflects that the origin node also contributes to the durability and visibility of the transaction. ### Adding a commit scope rule -The function `bdr.add_commit_scope` creates a rule for the given -commit scope name and origin node group. If the rule is the same for -all nodes in the EDB Postgres Distributed cluster, invoking this function once for the -top-level node group is enough to fully define the commit scope. +The function `bdr.add_commit_scope` creates a rule for the given commit scope name and origin node group. If the rule is the same for all nodes in the EDB Postgres Distributed cluster, invoking this function once for the top-level node group is enough to fully define the commit scope. -Alternatively, you can invoke it multiple times with the same -`commit_scope_name` but different origin node groups and rules for -commit scopes that vary depending on the origin of the transaction. +Alternatively, you can invoke it multiple times with the same `commit_scope_name` but different origin node groups and rules for commit scopes that vary depending on the origin of the transaction. #### Synopsis @@ -233,8 +167,7 @@ bdr.add_commit_scope( ### Changing a commit scope rule -To change a specific rule for a single origin node group in a -commit scope, you can use the function `bdr.alter_commit_scope`. +To change a specific rule for a single origin node group in a commit scope, you can use the function `bdr.alter_commit_scope`. #### Synopsis @@ -247,10 +180,7 @@ bdr.alter_commit_scope( ### Removing a commit scope rule -You can use `bdr.remove_commit_scope` to drop a single rule in -a commit scope. If you define multiple rules for the commit scope, you must invoke -this function once per rule to fully remove the entire -commit scope. +You can use `bdr.remove_commit_scope` to drop a single rule in a commit scope. If you define multiple rules for the commit scope, you must invoke this function once per rule to fully remove the entire commit scope. #### Synopsis @@ -261,6 +191,4 @@ bdr.remove_commit_scope( ``` !!! Note - Removing a commit scope that is still used as default by a node - group is not allowed - + Removing a commit scope that's still used as default by a node group isn't allowed. diff --git a/product_docs/docs/pgd/5/durability/group-commit.mdx b/product_docs/docs/pgd/5/durability/group-commit.mdx index feaaa72e989..c2b7e2efc8f 100644 --- a/product_docs/docs/pgd/5/durability/group-commit.mdx +++ b/product_docs/docs/pgd/5/durability/group-commit.mdx @@ -1,41 +1,41 @@ --- -title: Group Commit +title: Group commit redirects: - /pgd/latest/bdr/group-commit/ --- -The goal of Group Commit is to protect against data loss +The goal of group commit is to protect against data loss in case of single node failures or temporary outages. You achieve this -by requiring more than one BDR node to successfully receive and +by requiring more than one PGD node to successfully receive and confirm a transaction at COMMIT time. ## Requirements -During normal operation, Group Commit is completely transparent to the -application. Transactions which were in progress during failover need the +During normal operation, group commit is transparent to the +application. Transactions that were in progress during failover need the reconciliation phase triggered or consolidated by either the application or a -proxy in between. This currently happens only when either the origin node -recovers or when it is parted from the cluster. This is the same as with -Postgres legacy builtin synchronous replication. +proxy in between. This activity currently happens only when either the origin node +recovers or when it's parted from the cluster. This behavior is the same as with +Postgres legacy built-in synchronous replication. -Transactions using committed with Group Commit use two-phase commit underneath. +Transactions committed with group commit use two-phase commit underneath. Therefore, configure `max_prepared_transactions` high enough to handle all such transactions originating per node. ## Configuration -To use Group Commit, first define a [Commit Scope](commit-scopes). This -determines the BDR nodes involved in the commit of a transaction. +To use group commit, first define a [commit scope](commit-scopes). The commit scope +determines the PGD nodes involved in the commit of a transaction. ## Behavior -The behavior of Group Commit depends on the configuration applied by the Commit -Scope. +The behavior of group commit depends on the configuration applied by the commit +scope. ### Commit decisions -Group Commit can be configured to decide commits in 3 different ways, `group`, -`partner` and `raft`. +You can configure group commit to decide commits in three different ways: `group`, +`partner`, and `raft`. Group commit decision is done through the consensus specified using the same commit scope group settings used for the durability purposes. The difference @@ -43,66 +43,62 @@ is that the commit decision is made based on PREPARE replication while the durability checks COMMIT (PREPARED) replication. The partner decision is what [Commit At Most Once](camo) uses. This approach -only works when there are 2 data nodes in the node group. These two nodes are +works only when there are two data nodes in the node group. These two nodes are partners of each other, and the replica rather than origin decides whether -to commit something or not. This approach requires application changes to use -the CAMO transaction protocol to work correctly as application is in some way -part of the consensus. More on this approach in the [CAMO](camo) chapter. +to commit something. This approach requires application changes to use +the CAMO transaction protocol to work correctly, as the application is in some way +part of the consensus. For more on this approach, see [CAMO](camo). -Last option is raft, which uses the builtin Raft consensus to decide whether -commit can happen. Currently the global Raft is used so for this to work majority -of nodes across whole cluster must work. +The raft option uses the built-in Raft consensus to decide whether +commit can happen. Currently, the global Raft is used. For this to work, the majority +of nodes across the whole cluster must work. ### Conflict resolution -Conflict resolution can be either `async` or `eager`. +Conflict resolution can be `async` or `eager`. -Async means that PGD does optimistic conflict resolution during replication -(regardless of whether the origin transaction committed or or is still in progress) -using the row level resolution as configured for given node. See -[Conflicts](../consistency/conflicts) chapter for detailed description -of how the asynchronous conflict resolution works. +Async means that PGD does optimistic conflict resolution during replication using the row-level resolution as configured for given node. This happens regardless of whether the origin transaction committed or is still in progress. See +[Conflicts](../consistency/conflicts) for details about +how the asynchronous conflict resolution works. -Eager means that conflicts are resolved eagerly (as part of agreement on COMMIT) -and conflicting transactions get aborted with serialization error. This approach +Eager means that conflicts are resolved eagerly (as part of agreement on COMMIT), +and conflicting transactions get aborted with a serialization error. This approach provides greater isolation than the asynchronous resolution at the price of -performance. For the details of how Eager conflict resolution works, see +performance. For the details about how eager conflict resolution works, see [Eager conflict resolution](../consistency/eager). ### Aborts -To prevent transaction which cannot get consensus on the COMMIT from hanging -forever, the `ABORT ON` clause allows specifying timeout after which the -transaction abort is requested. Note that in case the transaction is already +To prevent a transaction that can't get consensus on the COMMIT from hanging +forever, the `ABORT ON` clause allows specifying timeout. After the timeout, the +transaction abort is requested. If the transaction is already decided to be committed at the time the abort request is sent, the transaction -will eventually COMMIT even though client might receive abort message. +does eventually COMMIT even though the client might receive an abort message. ## Limitations -Group Commit transactions can't yet execute DDL, -nor do they support explicit two-phase commit. These might be allowed in -later releases. However, the `TRUNCATE` command is allowed. +Group commit transactions can't yet execute DDL, +and they don't support explicit two-phase commit. Future releases might allow them. +However, the `TRUNCATE` command is allowed. -Only CAMO transactions can combined with `DEGRADE TO` clause for switching -to asynchronous operation on case of lowered availability yet. +You can combine only CAMO transactions with the `DEGRADE TO` clause for switching +to asynchronous operation in case of lowered availability. -Neither Eager or CAMO transactions are not currently supported in combination -with the Decoding Worker feature nor with transaction streaming. -Installations using Eager must keep `enable_wal_decoder` and `streaming_mode` -disabled for the BDR node group. +Eager and CAMO transactions aren't currently supported in combination +with the Decoding Worker feature or with transaction streaming. +Installations using eager must keep `enable_wal_decoder` and `streaming_mode` +disabled for the PGD node group. Synchronous replication uses a mechanism for transaction confirmation -different from Group Commit. The two aren't compatible, and you must not use -them together. Therefore, whenever Group Commit transactions, -make sure none of the BDR nodes are configured in +different from group commit. The two aren't compatible, and you must not use +them together. Therefore, whenever you group commit transactions, +make sure none of the PGD nodes are configured in `synchronous_standby_names`. -Currently, Raft commit decisions are extremely slow producing very low TPS and -are only recommended to be used along with the `eager` conflict resolution setting -to get the Eager All-Node Replication behavior of PGD 4 and older. +Currently, Raft commit decisions are extremely slow, producing very low TPS. We recommended +using them only with the `eager` conflict resolution setting +to get the eager all-node replication behavior of PGD 4 and older. -Combining different commit decision options in the same transaction is not -supported. - -Combining different conflict resolution options in the same transaction is not +Combining different commit decision options in the same transaction isn't +supported. Combining different conflict resolution options in the same transaction also isn't supported. diff --git a/product_docs/docs/pgd/5/durability/index.mdx b/product_docs/docs/pgd/5/durability/index.mdx index 0a311edefbb..5decde315f8 100644 --- a/product_docs/docs/pgd/5/durability/index.mdx +++ b/product_docs/docs/pgd/5/durability/index.mdx @@ -16,79 +16,79 @@ redirects: EDB Postgres Distributed allows you to choose from several replication configurations based on your durability, consistency, availability, and -performance needs using *Commit Scopes*. +performance needs using *commit scopes*. -In it's basic configuration, EDB Postgres Distributed will use asynchronous -replication, however commit scopes can change both the default and the per -transaction behavior. It's also possible to configure the legacy Postgres -synchronous replication using standard `synchronous_standby_names` in a same -way as the built-in physical or logical replication. Commit scopes however +In its basic configuration, EDB Postgres Distributed uses asynchronous +replication. However, commit scopes can change both the default and the +per-transaction behavior. It's also possible to configure the legacy Postgres +synchronous replication using standard `synchronous_standby_names` in the same +way as the built-in physical or logical replication. However, commit scopes provide much more flexibility and control over the replication behavior. The different synchronization settings affect three properties of interest to applications that are related but can all be implemented individually: -- *Durability*: Writing to multiple nodes increases crash resilience +- Durability: Writing to multiple nodes increases crash resilience and allows you to recover the data after a crash and restart. -- *Visibility*: With the commit confirmation to the client, the database +- Visibility: With the commit confirmation to the client, the database guarantees immediate visibility of the committed transaction on some sets of nodes. -- *Conflict handling*: Conflicts can be handled either optimistically - post-commit, with conflicts being resolved when the transaction is replicated - based on commit timestamps. Or they can be handled pessimistically - pre-commit, where the client can rely on the transaction to eventually be - applied on all nodes without further conflicts or get an abort directly +- Conflict handling: Conflicts can be handled optimistically + postcommit, with conflicts resolved when the transaction is replicated + based on commit timestamps. Or, they can be handled pessimistically + precommit. The client can rely on the transaction to eventually be + applied on all nodes without further conflicts or get an abort, directly informing the client of an error. -Commit Scopes allow two ways of controlling durability of the transaction: +Commit scopes allow two ways of controlling durability of the transaction: -- [Group Commit](group-commit). This option controls which and how many nodes - have to reach a consensus before we consider transaction to be committable - and at what stage of replication we can consider it committed. This also - allows controlling the visibility ordering of the transaction. -- [CAMO](camo). Variant of Group Commit where the client is part of the +- [Group commit](group-commit). This option controls which and how many nodes + have to reach a consensus before the transaction is considered to be committable + and at what stage of replication it can be considered committed. This option also + allows you to control the visibility ordering of the transaction. +- [CAMO](camo). This option is a variant of group commit in which the client is part of the consensus. -- [Lag Control](lag-control). This option controls how far behind can nodes +- [Lag control](lag-control). This option controls how far behind nodes can be in terms of replication before allowing commit to proceed. -Postgres provides [Physical Streaming Replication](https://www.postgresql.org/docs/current/warm-standby.html#STREAMING-REPLICATION) +Postgres provides [physical streaming replication](https://www.postgresql.org/docs/current/warm-standby.html#STREAMING-REPLICATION) (PSR), which is unidirectional but offers a [synchronous variant](https://www.postgresql.org/docs/current/warm-standby.html#SYNCHRONOUS-REPLICATION). -For backward compatibility, BDR still supports configuring synchronous +For backward compatibility, PGD still supports configuring synchronous replication with `synchronous_commit` and `synchronous_standby_names`. See -[Legacy synchronous replication](#legacy-synchronous-replication-using-bdr), -but consider using [Group Commit](group-commit) instead. +[Legacy synchronous replication](#legacy-synchronous-replication-using-pgd), +but consider using [group commit](group-commit) instead. ## Terms and definitions -BDR nodes take different roles during the replication of a transaction. +PGD nodes take different roles during the replication of a transaction. These are implicitly assigned per transaction and are unrelated even for concurrent transactions. * The *origin* is the node that receives the transaction from the client or application. It's the node processing the transaction - first, initiating replication to other BDR nodes, and responding back + first, initiating replication to other PGD nodes and responding back to the client with a confirmation or an error. -* A *partner* node is a BDR node expected to confirm transactions - either according to Group Commit requirements. +* A *partner* node is a PGD node expected to confirm transactions + according to group commit requirements. -* A *commit group* is the group of all BDR nodes involved in the +* A *commit group* is the group of all PGD nodes involved in the commit, that is, the origin and all of its partner nodes, which can be just a few or all peer nodes. ## Comparison Most options for synchronous replication available to -BDR allow for different levels of synchronization, offering different +PGD allow for different levels of synchronization, offering different tradeoffs between performance and protection against node or network outages. The following table summarizes what a client can expect from a peer -node replicated to after having received a COMMIT confirmation from +node replicated to after receiving a COMMIT confirmation from the origin node the transaction was issued to. The Mode column takes on different meaning depending on the variant. For PSR and legacy -synchronous replication with BDR, it refers to the -`synchronous_commit` setting. And for Commit Scopes, it refers to the +synchronous replication with PGD, it refers to the +`synchronous_commit` setting. For commit scopes, it refers to the confirmation requirements of the [commit scope configuration](commit-scopes#configuration). @@ -120,7 +120,7 @@ Postgres crashes.* *(2) Unless switched to local mode (if allowed) by setting `synchronous_replication_availability` to `async'`, otherwise the -values for the asynchronous BDR default apply.* +values for the asynchronous PGD default apply.* *(3) Consider using Group Commit instead.* @@ -140,7 +140,7 @@ results of the transaction and experience stale reads. Durability relates to the peer node's storage and provides protection against loss of data after a crash and recovery of the peer node. This can either relate to the reception of the data (as with physical -streaming replication) or to visibility (as with Group Commit). +streaming replication) or to visibility (as with group commit). The former eliminates the need for retransmissions after a crash, while the latter ensures visibility is maintained across restarts. @@ -148,7 +148,7 @@ restarts. ## Internal timing of operations For a better understanding of how the different modes work, it's -helpful to realize PSR and BDR apply transactions +helpful to realize PSR and PGD apply transactions differently. With physical streaming replication, the order of operations is: @@ -167,7 +167,7 @@ With PGD, the order of operations is different: - Peer applies changes, making the transaction visible locally. - Peer persists the transaction by flushing to disk. -For Group Commit, CAMO, and Eager, the origin node waits for +For group commit, CAMO, and eager, the origin node waits for a certain number of confirmations prior to making the transaction visible locally. The order of operations is: @@ -189,11 +189,11 @@ The following table summarizes the differences. ## Configuration -Configuring Commit Scopes, is done through SQL function just like other administration +You configure commit scopes using an SQL function just like other administration operations in PGD. -For example you might define basic Commit Scope which does Group Commit on majority -of nodes in the example_group BDR group: +For example, you might define a basic commit scope that does group commit on a majority +of nodes in the example_group PGD group: ```sql SELECT bdr.add_commit_scope( @@ -204,8 +204,8 @@ SELECT bdr.add_commit_scope( ); ``` -You can then use the commit scope either by setting configuration variable (GUC) -`bdr.commit_scope` either per transaction or globally to that commit scope. +You can then use the commit scope either by setting the configuration variable (GUC) +`bdr.commit_scope` either per transaction or globally to that commit scope: ```sql BEGIN; @@ -214,7 +214,7 @@ SET LOCAL bdr.commit_scope = 'example_scope'; COMMIT; ``` -You can also set the default commit scope for given BDR group. +You can also set the default commit scope for a given PGD group: ```sql SELECT bdr.alter_node_group_option( @@ -224,18 +224,19 @@ SELECT bdr.alter_node_group_option( ); ``` -Note that the `default_commit_scope` is checked in the group tree the given origin -node belongs to from bottom to up. The `default_commit_scope` cannot be set to -the special value `local` which means no commit scope this way, for that use +The `default_commit_scope` is checked in the group tree that the given origin +node belongs to from bottom to top. The `default_commit_scope` can't be set to +the special value `local`, which means there's no way for the commit scope to use the `bdr.commit_scope` configuration parameter. + -Full details of the Commit Scope language with all the options are described -in the [Commit Scopes](commit-scopes) chapter. +For full details of the commit scope language with all the options described, +see [Commit scopes](commit-scopes). ### Postgres configuration parameters The following table provides an overview of the configuration -settings that are required to be set to a non-default value (req) or +settings that you must set to a non-default value (req) and those that are optional (opt) but affecting a specific variant. | Setting (GUC) | Group Commit | Lag Control | PSR (1) | Legacy Sync | @@ -247,7 +248,7 @@ optional (opt) but affecting a specific variant. ## Planned shutdown and restarts -When using Group Commit with receive confirmations, take care +When using group commit with receive confirmations, take care with planned shutdown or restart. By default, the apply queue is consumed prior to shutting down. However, in the `immediate` shutdown mode, the queue is discarded at shutdown, leading to the stopped node "forgetting" @@ -258,43 +259,43 @@ To ensure the apply queue gets flushed to disk, use either `smart` or `fast` shutdown for maintenance tasks. This approach maintains the required synchronization level and prevents loss of data. -## Legacy synchronous replication using BDR +## Legacy synchronous replication using PGD !!! Note - Consider using [Group Commit](group-commit) instead. + Consider using [group commit](group-commit) instead. ### Usage -To enable synchronous replication using BDR, you need to add the application -name of the relevant BDR peer nodes to -`synchronous_standby_names`. The use of `FIRST x` or `ANY x` offers a +To enable synchronous replication using PGD, you need to add the application +name of the relevant PGD peer nodes to +`synchronous_standby_names`. The use of `FIRST x` or `ANY x` offers some flexibility if this doesn't conflict with the requirements of -non-BDR standby nodes. +non-PGD standby nodes. Once you've added it, you can configure the level of synchronization per transaction using `synchronous_commit`, which defaults to `on`. This setting means that -adding to `synchronous_standby_names` already enables synchronous +adding the application name to to `synchronous_standby_names` already enables synchronous replication. Setting `synchronous_commit` to `local` or `off` turns off synchronous replication. -Due to BDR applying the transaction before persisting it, the -values `on` and `remote_apply` are equivalent (for logical -replication). +Due to PGD applying the transaction before persisting it, the +values `on` and `remote_apply` are equivalent for logical +replication. -### Migration to Commit Scopes +### Migration to commit scopes -The Group Commit feature of BDR is configured independent of +You configure the group commit feature of PGD independent of `synchronous_commit` and `synchronous_standby_names`. Instead, the `bdr.commit_scope` GUC allows you to select the scope per transaction. And -instead of `synchronous_standby_names` configured on each node -individually, Group Commit uses globally synchronized Commit Scopes. +instead of configuring `synchronous_standby_names` on each node +individually, group commit uses globally synchronized commit scopes. !!! Note - While the grammar for `synchronous_standby_names` and Commit - Scopes looks similar, the former + While the grammar for `synchronous_standby_names` and commit + scopes looks similar, the former doesn't account for the origin node, but the latter does. Therefore, for example, `synchronous_standby_names = 'ANY 1 (..)'` - is equivalent to a Commit Scope of `ANY 2 (...)`. This choice + is equivalent to a commit scope of `ANY 2 (...)`. This choice makes reasoning about majority easier and reflects that the origin node also contributes to the durability and visibility of the transaction. diff --git a/product_docs/docs/pgd/5/durability/lag-control.mdx b/product_docs/docs/pgd/5/durability/lag-control.mdx index b0eb0f0d2dc..5642fd48695 100644 --- a/product_docs/docs/pgd/5/durability/lag-control.mdx +++ b/product_docs/docs/pgd/5/durability/lag-control.mdx @@ -4,8 +4,8 @@ redirects: - /pgd/latest/bdr/lag-control/ --- -Data throughput of database applications on a BDR origin node can -exceed the rate at which committed data can be safely replicated to +Data throughput of database applications on a PGD origin node can +exceed the rate at which committed data can safely replicate to downstream peer nodes. If this disparity persists beyond a period of time or chronically in high availability applications, then organizational objectives related to disaster recovery or business @@ -13,12 +13,12 @@ continuity plans might not be satisfied. The replication lag control (RLC) feature is designed to regulate this imbalance using a dynamic rate-limiting device so that data flow between -BDR group nodes complies with these organizational objectives. It does so -by controlling the extent of replication lag between BDR nodes. +PGD group nodes complies with these organizational objectives. It does so +by controlling the extent of replication lag between PGD nodes. Some of these objectives include the following: -- Recovery point objective (RPO) specifies the maximum tolerated +- Recovery point objective (RPO) specifies the maximum-tolerated amount of data that can be lost due to unplanned events, usually expressed as an amount of time. In non-replicated systems, RPO is used to set backup intervals to limit the risk of lost committed @@ -34,7 +34,7 @@ Some of these objectives include the following: - Group elasticity objective (GEO) ensures that any node isn't originating new data at a clip that can't be acceptably saved to - its peer nodes. When that is the case then the detection of that + its peer nodes. When that's the case, then the detection of that condition can be used as one metric in the decision to expand the number of database nodes. Similarly, when that condition abates then it might influence the decision to contract the number of database nodes. @@ -43,23 +43,23 @@ Lag control manages replication lag by controlling the rate at which client connections can commit READ WRITE transactions. Replication lag is measured either as lag time or lag size, depending on the objectives to meet. Transaction commit rate is regulated using a configured -BDR commit-delay time. +PGD commit-delay time. ## Requirements To get started using lag control: -- Determine the maximum acceptable commit delay time `max_commit_delay` that can be tolerated for all database applications. +- Determine the maximum acceptable commit delay time `max_commit_delay` that all database applications can tolerate. - Decide on the lag measure to use. Choose either lag size `max_lag_size` or lag time `max_lag_time`. -- Decide on the groups or subgroups involved and the minimum number of nodes in each collection required to satisfy confirmation. This will form the basis for the definition of a commit scope rule. +- Decide on the groups or subgroups involved and the minimum number of nodes in each collection required to satisfy confirmation. This information forms the basis for the definition of a commit scope rule. ## Configuration -Lag control is specified within a commit scope, which allows consistent and coordinated parameter settings across the nodes spanned by the commmit scope rule. A Lag control specification can be included in the default commit scope of a top group or part of an Origin group commit scope. +You specify lag control in a commit scope, which allows consistent and coordinated parameter settings across the nodes spanned by the commmit scope rule. You can include a lag control specification in the default commit scope of a top group or as part of an origin group commit scope. -Using the sample node groups from the [Commit Scope](commit-scopes) chapter, this example shows lag control rules for two datacenters. +Using the sample node groups from [Commit scope](commit-scopes), this example shows lag control rules for two data centers: ```sql -- create a Lag Control commit scope with individual rules @@ -78,95 +78,95 @@ SELECT bdr.add_commit_scope( ); ``` -Note the parameter values admit unit specification that is compatible with GUC parameter conventions. +The parameter values admit unit specification that's compatible with GUC parameter conventions. -A Lag control commit scope rule can be added to existings commit scope rules that also include Group Commit and CAMO rule specifications. +You can add a lag control commit scope rule to existing commit scope rules that also include group commit and CAMO rule specifications. -`max_commit_delay` parameter permits and encourages a specification of milliseconds with a fractional part, including a sub-millisecond setting if appropriate. +The `max_commit_delay` parameter permits and encourages a specification of milliseconds with a fractional part, including a submillisecond setting, if appropriate. ## Overview -Lag control is a dynamic TPS rate-limiting mechanism that operates at the client +Lag control is a dynamic TPS, rate-limiting mechanism that operates at the client connection level. It's designed to be as unobtrusive as possible while satisfying configured lag-control constraints. This means that if enough -BDR nodes can replicate changes fast enough to remain below configured -lag measure thresholds, then the BDR runtime commit delay stays fixed +PGD nodes can replicate changes fast enough to remain below configured +lag measure thresholds, then the PGD runtime commit delay stays fixed at 0 milliseconds. If this isn't the case, minimally -adjust the BDR runtime commit delay as high as needed, but no higher, until the number of +adjust the PGD runtime commit delay as high as needed, but no higher, until the number of conforming nodes returns to the minimum threshold. Even after the minimum node threshold is reached, lag control continues to attempt -to drive the BDR runtime commit delay back to zero. The BDR commit delay +to drive the PGD runtime commit delay back to zero. The PGD commit delay might rise and fall around an equilibrium level most of the time, but if -data throughput or lag-apply rates improve then the commit delay +data throughput or lag-apply rates improve, then the commit delay decreases over time. -The BDR commit delay is a post-commit delay. It occurs after the transaction +The PGD commit delay is a post-commit delay. It occurs after the transaction has committed and after all Postgres resources locked or acquired by the transaction are released. Therefore, the delay doesn't prevent concurrent active transactions from observing or modifying its values or acquiring its resources. The same guarantee can't be made for external resources managed by Postgres extensions. Regardless of extension -dependencies, the same guarantee can be made if the BDR extension is listed +dependencies, the same guarantee can be made if the PGD extension is listed before extension-based resource managers in `postgresql.conf`. -Strictly speaking, the BDR commit delay is not a per-transaction delay. -It is the mean value of commit delays over a stream of transactions for a +Strictly speaking, the PGD commit delay isn't a per-transaction delay. +It's the mean value of commit delays over a stream of transactions for a particular client connection. This technique allows the commit delay and fine-grained adjustments of the value to escape the coarse granularity of OS schedulers, clock interrupts, and variation due to system load. It also -allows the BDR runtime commit delay to settle within microseconds of the +allows the PGD runtime commit delay to settle within microseconds of the lowest duration possible to maintain a lag measure threshold. !!! Note - Don't conflate the BDR commit delay with the Postgres + Don't conflate the PGD commit delay with the Postgres commit delay. They are unrelated and perform different functions. Don't substitute one for the other. ## Transaction application -The BDR commit delay is applied to all READ WRITE transactions that -modify data for user applications. This implies that any transaction +The PGD commit delay is applied to all READ WRITE transactions that +modify data for user applications. This behavior implies that any transaction that doesn't modify data, including declared READ WRITE transactions, is exempt from the commit delay. -Asynchronous transaction commit also executes a BDR commit delay. This +Asynchronous transaction commit also executes a PGD commit delay. This might appear counterintuitive, but asynchronous commit, by virtue of its performance, can be one of the greatest sources of replication lag. -Postgres and BDR auxillary processes don't delay at transaction commit. -Most notably, BDR writers don't execute a commit delay when applying -remote transactions on the local node. This is by design as BDR writers +Postgres and PGD auxillary processes don't delay at transaction commit. +Most notably, PGD writers don't execute a commit delay when applying +remote transactions on the local node. This is by design, as PGD writers contribute nothing to outgoing replication lag and can reduce incoming replication lag the most by not having their transaction commits throttled by a delay. ## Limitations -The maximum commit delay is a ceiling value representing a hard limit. -This means that a commit delay never exceeds the configured value. +The maximum commit delay is a ceiling value representing a hard limit, +which means that a commit delay never exceeds the configured value. Conversely, the maximum lag measures both by size and time and are soft limits that can be exceeded. When the maximum commit delay is reached, there's no additional back pressure on the lag measures to prevent their continued increase. -There's no way to exempt origin transactions that don't modify BDR +There's no way to exempt origin transactions that don't modify PGD replication sets from the commit delay. For these transactions, it can be useful to SET LOCAL the maximum transaction delay to 0. ## Caveats Application TPS is one of many factors that can affect replication lag. -Other factors include the average size of transactions for which BDR commit +Other factors include the average size of transactions for which PGD commit delay can be less effective. In particular, bulk load operations can cause replication lag to rise, which can trigger a concomitant rise in -the BDR runtime commit delay beyond the level reasonably expected by normal +the PGD runtime commit delay beyond the level reasonably expected by normal applications, although still under the maximum allowed delay. Similarly, an application with a very high OLTP requirement and modest -data changes can be unduly restrained by the acceptable BDR commit delay +data changes can be unduly restrained by the acceptable PGD commit delay setting. In these cases, it can be useful to use the `SET [SESSION|LOCAL]` command to @@ -175,7 +175,7 @@ those applications. For example, bulk load operations are sometimes split into multiple, smaller transactions to limit transaction snapshot duration and WAL retention size or establish a restart point if the bulk load fails. In deference to lag control, those transaction commits can also schedule very -long BDR commit delays to allow digestion of the lag contributed by the +long PGD commit delays to allow digestion of the lag contributed by the prior partial bulk load. ## Meeting organizational objectives @@ -184,10 +184,10 @@ In the example objectives list earlier: - RPO can be met by setting an appropriate maximum lag time. - RCO can be met by setting an appropriate maximum lag size. -- GEO can be met by monitoring the BDR runtime commit delay - and the BDR runtime lag measures, +- GEO can be met by monitoring the PGD runtime commit delay + and the PGD runtime lag measures, -As mentioned, when the maximum BDR runtime commit delay is -pegged at the BDR configured commit-delay limit and the lag -measures consistently exceed their BDR-configured maximum -levels, this scenario can be a marker for BDR group expansion. +As mentioned, when the maximum PGD runtime commit delay is +pegged at the PGD configured commit-delay limit, and the lag +measures consistently exceed their PGD-configured maximum +levels, this scenario can be a marker for PGD group expansion. diff --git a/product_docs/docs/pgd/5/functions.mdx b/product_docs/docs/pgd/5/functions.mdx index 9fdd678dba2..3b5caeab17b 100644 --- a/product_docs/docs/pgd/5/functions.mdx +++ b/product_docs/docs/pgd/5/functions.mdx @@ -5,8 +5,8 @@ redirects: - ../bdr/functions --- -Perform BDR management primarily by using functions you call from SQL. -All functions in BDR are exposed in the `bdr` schema. Schema qualify any calls to these +Perform PGD management primarily by using functions you call from SQL. +All functions in PGD are exposed in the `bdr` schema. Schema qualify any calls to these functions instead of putting `bdr` in the `search_path`. @@ -14,12 +14,12 @@ functions instead of putting `bdr` in the ### bdr.bdr_version -This function retrieves the textual representation of the BDR version -currently in use. +This function retrieves the textual representation of the version +of the BDR extension currently in use. ### bdr.bdr_version_num -This function retrieves the BDR version number that is +This function retrieves the version number of the BDR extension that is currently in use. Version numbers are monotonically increasing, allowing this value to be used for less-than and greater-than comparisons. @@ -43,7 +43,7 @@ Returns the current subscription statistics. ## System and progress information parameters -BDR exposes some parameters that you can query using `SHOW` in `psql` +PGD exposes some parameters that you can query using `SHOW` in `psql` or using `PQparameterStatus` (or equivalent) from a client application. @@ -98,7 +98,7 @@ Disables the consensus worker on the local node until server restart or until it's reenabled using `bdr.consensus_enable` (whichever happens first). !!! Warning - Disabling consensus disables some features of BDR and + Disabling consensus disables some features of PGD and affects availability of the EDB Postgres Distributed cluster if left disabled for a long time. Use this function only when working with Technical Support. @@ -111,7 +111,7 @@ Reenabled disabled consensus worker on local node. Returns currently used consensus protocol version by the local node. -Needed by the BDR group reconfiguration internal mechanisms. +Needed by the PGD group reconfiguration internal mechanisms. ### bdr.consensus_snapshot_export @@ -121,7 +121,7 @@ Needed by the BDR group reconfiguration internal mechanisms. bdr.consensus_snapshot_export(version integer DEFAULT NULL) ``` -Generate a new BDR consensus snapshot from the currently committed-and-applied +Generate a new PGD consensus snapshot from the currently committed-and-applied state of the local node and return it as bytea. By default, a snapshot for the highest supported Raft version is @@ -136,10 +136,10 @@ The new snapshot isn't automatically stored to the local node's `bdr.local_consensus_snapshot` table. It's only returned to the caller. The generated snapshot might be passed to `bdr.consensus_snapshot_import()` on -any other nodes in the same BDR node group that's behind the exporting node's +any other nodes in the same PGD node group that's behind the exporting node's Raft log position. -The local BDR consensus worker must be disabled for this function to work. +The local PGD consensus worker must be disabled for this function to work. Typical usage is: ``` @@ -148,7 +148,7 @@ Typical usage is: SELECT bdr.bdr_consensus_enable(); ``` -While the BDR consensus worker is disabled: +While the PGD consensus worker is disabled: - DDL locking attempts on the node fail or time out. - galloc sequences don't get new values. - Eager and CAMO transactions pause or error. @@ -168,13 +168,13 @@ bdr.consensus_snapshot_import(IN snapshot bytea) ``` Import a consensus snapshot that was exported by -`bdr.consensus_snapshot_export()`, usually from another node in the same BDR +`bdr.consensus_snapshot_export()`, usually from another node in the same PGD node group. It's also possible to use a snapshot extracted directly from the `snapshot` field of the `bdr.local_consensus_snapshot` table on another node. -This function is useful for resetting a BDR node's catalog state to a known good +This function is useful for resetting a PGD node's catalog state to a known good state in case of corruption or user error. You can import the snapshot if the importing node's `apply_index` is less than @@ -185,7 +185,7 @@ and makes no changes. The imported snapshot doesn't have to be completely up to date, as once the snapshot is imported the node fetches the remaining changes from the current leader. -The BDR consensus worker must be disabled on the importing node for this +The PGD consensus worker must be disabled on the importing node for this function to work. See notes on `bdr.consensus_snapshot_export()` for details. It's possible to use this function to force the local node to generate a new Raft @@ -233,9 +233,9 @@ bdr.raft_leadership_transfer(IN node_name text, IN wait_for_completion boolean) ``` Request the node identified by `node_name` to be the Raft leader. The -request can be initiated from any of the BDR nodes and is +request can be initiated from any of the PGD nodes and is internally forwarded to the current leader to transfer the leadership to -the designated node. The designated node must be an ACTIVE BDR node +the designated node. The designated node must be an ACTIVE PGD node with full voting rights. If `wait_for_completion` is false, the request is served on @@ -261,7 +261,7 @@ to one or all nodes. Waits until a slot passes a certain LSN. If no position is supplied, the current write position is used on the local node. -If no slot name is passed, it waits until all BDR slots pass the LSN. +If no slot name is passed, it waits until all PGD slots pass the LSN. The function polls every 1000 ms for changes from other nodes. @@ -277,19 +277,19 @@ bdr.wait_slot_confirm_lsn(slot_name text DEFAULT NULL, target_lsn pg_lsn DEFAULT #### Parameters -- `slot_name` — Name of replication slot or, if NULL, all BDR slots (only). +- `slot_name` — Name of replication slot or, if NULL, all PGD slots (only). - `target_lsn` — LSN to wait for or, if NULL, use the current write LSN on the local node. ### bdr.wait_for_apply_queue -The function `bdr.wait_for_apply_queue` allows a BDR node to wait for +The function `bdr.wait_for_apply_queue` allows a PGD node to wait for the local application of certain transactions originating from a given -BDR node. It returns only after all transactions from that peer +PGD node. It returns only after all transactions from that peer node are applied locally. An application or a proxy can use this function to prevent stale reads. -For convenience, BDR provides a variant of this function for +For convenience, PGD provides a variant of this function for CAMO and the CAMO partner node. See [bdr.wait_for_camo_partner_queue](durability/camo#wait-for-consumption-of-the-apply-queue-from-the-camo-partner). @@ -617,9 +617,9 @@ bdrdb=# SELECT bdr.node_group_type('bdrgroup'); ## Global advisory locks -BDR supports global advisory locks. These locks are similar to +PGD supports global advisory locks. These locks are similar to the advisory locks available in PostgreSQL except that the -advisory locks supported by BDR are global. They follow semantics +advisory locks supported by PGD are global. They follow semantics similar to DDL locks. So an advisory lock is obtained by majority consensus and can be used even if one or more nodes are down or lagging behind, as long as a majority of all nodes can work together. @@ -695,7 +695,7 @@ bdr.global_advisory_unlock(key1 integer, key2 integer) ### bdr.monitor_group_versions To provide a cluster-wide version check, this function uses -BDR version information returned from the view +PGD version information returned from the view `bdr.group_version_details`. #### Synopsis @@ -707,14 +707,14 @@ bdr.monitor_group_versions() #### Notes This function returns a record with fields `status` and `message`, -as explained in [Monitoring](../monitoring/sql/#monitoring-bdr-versions). +as explained in [Monitoring](../monitoring/sql/#monitoring-pgd-versions). This function calls `bdr.run_on_all_nodes()`. ### bdr.monitor_group_raft To provide a cluster-wide Raft check, this function uses -BDR Raft information returned from the view +PGD Raft information returned from the view `bdr.group_raft_details`. #### Synopsis @@ -739,7 +739,7 @@ This function calls `bdr.run_on_all_nodes()`. This function uses replication slot status information returned from the view `pg_replication_slots` (slot active or inactive) to provide a -local check considering all replication slots except the BDR group +local check considering all replication slots except the PGD group slots. #### Synopsis @@ -843,7 +843,7 @@ bdr.lag_control() ## Internal functions -### BDR message payload functions +### PGD message payload functions `bdr.decode_message_response_payload` and `bdr.decode_message_payload` @@ -865,20 +865,20 @@ replication slot. Used internally to implement the `bdr.node_slots` view. -### BDR internal function replication functions +### PGD internal function replication functions `bdr.internal_alter_sequence_set_kind`, `internal_replication_set_add_table`, `internal_replication_set_remove_table` Functions used internally for replication of the various function calls. -No longer used by the current version of BDR. Exists only for backward +No longer used by the current version of PGD. Exists only for backward compatibility during rolling upgrades. ### bdr.internal_submit_join_request Submits a consensus request for joining a new node. -Needed by the BDR group reconfiguration internal mechanisms. +Needed by the PGD group reconfiguration internal mechanisms. ### bdr.isolation_test_session_is_blocked @@ -890,7 +890,7 @@ Used for isolation/concurrency tests. ### bdr.local_node_info -This function displays information for the local node, needed by the BDR group +This function displays information for the local node, needed by the PGD group reconfiguration internal mechanisms. The view `bdr.local_node_summary` provides similar information useful for @@ -922,11 +922,11 @@ consensus mechanism is working. Internal implementation of sequence increments. Use this function instead of standard `nextval` in queries that -interact with [BDR global sequences](sequences/#bdr-global-sequences). +interact with [PGD global sequences](sequences/#pgd-global-sequences). #### Notes -The following are also internal BDR sequence manipulation functions. +The following are also internal PGD sequence manipulation functions. `bdr.seq_currval` and `bdr.sql_lastval` are used automatically. ### bdr.show_subscription_status @@ -1275,7 +1275,7 @@ Taskmgr workers are always running in the background, even before the ### Alter node kind -BDR5 introduced a concept of Task Manager Leader node. The node is selected +PGD5 introduced a concept of Task Manager Leader node. The node is selected automatically by PGD, but for upgraded clusters, its important to set the `node_kind` properly for all nodes in the cluster. The user is expected to do this manually after upgrading to the latest PGD version by calling @@ -1307,7 +1307,7 @@ bdr.node_catchup_state_name(catchup_state oid); - `catchup_state` — Oid code of the catchup state. -### Modify the BDR node group routing configuration +### Modify the PGD node group routing configuration #### Synopsis @@ -1324,7 +1324,7 @@ bdr.alter_node_group_option(node_group_name text, - `config_value` — New value to be set for the given key. -### Modify the BDR node routing configuration +### Modify the PGD node routing configuration #### Synopsis diff --git a/product_docs/docs/pgd/5/known_issues.mdx b/product_docs/docs/pgd/5/known_issues.mdx index 9ae33626d07..4b040cae19f 100644 --- a/product_docs/docs/pgd/5/known_issues.mdx +++ b/product_docs/docs/pgd/5/known_issues.mdx @@ -2,21 +2,49 @@ title: 'Known issues' --- -This section discusses currently known issues in EDB Postgres Distributed 5. These issues are tracked in EDB's ticketing system and are expected to be resolved in a future release. - -- If the resolver for the `update_origin_change` conflict is set to `skip`, `synchronous_commit=remote_apply` is used, and concurrent updates of the same row are repeatedly applied on two different nodes, then one of the update statements might hang due to a deadlock with the BDR writer. As mentioned in the [Conflicts](consistency/conflicts/) chapter, `skip` is not the default resolver for the `update_origin_change` conflict, and this combination isn't intended to be used in production. It discards one of the two conflicting updates based on the order of arrival on that node, which is likely to cause a divergent cluster. In the rare situation that you do choose to use the `skip` conflict resolver, note the issue with the use of the `remote_apply` mode. +This section discusses currently known issues in EDB Postgres Distributed 5. +These known issues are tracked in PGD's +ticketing system and are expected to be resolved in a future +release. + +- If the resolver for the `update_origin_change` conflict + is set to `skip`, `synchronous_commit=remote_apply` is used, and + concurrent updates of the same row are repeatedly applied on two + different nodes, then one of the update statements might hang due + to a deadlock with the PGD writer. As mentioned in the + [Conflicts](consistency/conflicts/) chapter, `skip` is not the default + resolver for the `update_origin_change` conflict, and this + combination isn't intended to be used in production. It discards + one of the two conflicting updates based on the order of arrival + on that node, which is likely to cause a divergent cluster. + In the rare situation that you do choose to use the `skip` + conflict resolver, note the issue with the use of the + `remote_apply` mode. - The Decoding Worker feature doesn't work with CAMO/EAGER/Group Commit. Installations using CAMO/Eager/Group Commit must keep `enable_wal_decoder` disabled. -- Lag control doesn't adjust commit delay in any way on a fully isolated node, that is, in case all other nodes are unreachable or not operational. As soon as at least one node is connected, replication lag control picks up its work and adjusts the BDR commit delay again. +- Lag control doesn't adjust commit delay in any way on a fully + isolated node, that is, in case all other nodes are unreachable or not + operational. As soon as at least one node is connected, replication + lag control picks up its work and adjusts the PGD commit delay + again. -- For time-based lag control, BDR currently uses the lag time (measured by commit timestamps) rather than the estimated catchup time that's based on historic apply rate. +- For time-based lag control, PGD currently uses the lag time (measured + by commit timestamps) rather than the estimated catchup time that's + based on historic apply rate. -- Changing the CAMO partners in a CAMO pair isn't currently possible. It's possible only to add or remove a pair. Adding or removing a pair doesn't need a restart of Postgres or even a reload of the configuration. +- Changing the CAMO partners in a CAMO pair isn't currently possible. + It's possible only to add or remove a pair. + Adding or removing a pair doesn't need a restart of Postgres or even a + reload of the configuration. -- Group Commit cannot be combined with [CAMO](durability/camo/) or [Eager All Node replication](consistency/eager/). Eager Replication currently only works by using the "global" BDR commit scope. +- Group Commit cannot be combined with [CAMO](durability/camo/) or [Eager All Node + replication](consistency/eager/). Eager Replication currently only works by using the + "global" PGD commit scope. -- Transactions using Eager Replication can't yet execute DDL, nor do they support explicit two-phase commit. The TRUNCATE command is allowed. +- Transactions using Eager Replication can't yet execute DDL, + nor do they support explicit two-phase commit. + The TRUNCATE command is allowed. - Not all DDL can be run when either CAMO or Group Commit is used. @@ -25,4 +53,3 @@ This section discusses currently known issues in EDB Postgres Distributed 5. The - There currently is no protection against altering or removing a commit scope. Running transactions in a commit scope that is concurrently being altered or removed can lead to the transaction blocking or replication stalling completely due to an error on the downstream node attempting to apply the transaction. Ensure that any transactions using a specific commit scope have finished before altering or removing it. Details of other design or implementation [limitations](limitations) are also available. - diff --git a/product_docs/docs/pgd/5/monitoring/index.mdx b/product_docs/docs/pgd/5/monitoring/index.mdx index b9dbe5cab66..5c21ff26d52 100644 --- a/product_docs/docs/pgd/5/monitoring/index.mdx +++ b/product_docs/docs/pgd/5/monitoring/index.mdx @@ -4,19 +4,22 @@ originalFilePath: monitoring.md --- -Monitoring replication setups is important to ensure that your system performs optimally -and does not run out of disk space or encounter other faults that may halt operations. +Monitoring replication setups is important to ensure that your system: -It is important to have automated monitoring in place to ensure that if, for example, -replication slots start falling badly behind, the administrator is alerted and can -take proactive action. +- Performs optimally +- Doesn't run out of disk space +- Doesn't encounter other faults that might halt operations -EDB provides Postgres Enterprise Manager (PEM), which supports BDR from version 8.1. See [Monitoring EDB Postgres Distributed](/pem/latest/monitoring_BDR_nodes/) for more information. +It's important to have automated monitoring in place to ensure that the administrator is alerted and can +take proactive action when issues occur. For example, the administrator can be alerted if +replication slots start falling badly behind, + +EDB provides Postgres Enterprise Manager (PEM), which supports PGD starting with version 8.1. See [Monitoring EDB Postgres Distributed](/pem/latest/monitoring_BDR_nodes/) for more information. Alternatively, tools or users can make their own calls into information views and functions provided by the BDR extension. See [Monitoring through SQL](sql) for -detailed description. +details. EDB Postgres Distributed also integrates with OpenTelemetry, allowing you to -use existing reporting setup to follow the state of the EDB Postgres Distributed -cluster. See the [OpenTelemetry integration](otel) chapter for details. +use an existing reporting setup to follow the state of the EDB Postgres Distributed +cluster. See [OpenTelemetry integration](otel) for details. diff --git a/product_docs/docs/pgd/5/monitoring/otel.mdx b/product_docs/docs/pgd/5/monitoring/otel.mdx index d234c2be093..ec6a206ad5a 100644 --- a/product_docs/docs/pgd/5/monitoring/otel.mdx +++ b/product_docs/docs/pgd/5/monitoring/otel.mdx @@ -1,24 +1,24 @@ --- -title: OpenTelemetry Integration +title: OpenTelemetry integration --- -EDB Postgres Distributed can be configured to report monitoring information +You can configure EDB Postgres Distributed to report monitoring information as well as traces to the OpenTelemetry collector. -Several resource attributes are filled by EDB Postgres Distributed OTEL collector. +EDB Postgres Distributed OTEL collector fills several resource attributes. These are attached to all metrics and traces: - - The `service.name` is configurable via `bdr.otel_service_name` configuration setting. + - The `service.name` is configurable with the `bdr.otel_service_name` configuration setting. - The `service.namespace` is always set to `edb_postgres_distributed`. - - The `service.instance.id` is always set to system identifier of the Postgres instance. - - The `service.version` is set to current version of the BDR extension loaded in the Postgresql instance. + - The `service.instance.id` is always set to the system identifier of the Postgres instance. + - The `service.version` is set to the current version of the BDR extension loaded in the Postgresql instance. ## Metrics collection -The metric collection is enable automatically when configuration option -`bdr.metrics_otel_http_url` is set to non-empty URL. +Setting the configuration option +`bdr.metrics_otel_http_url` to a non-empty URL enables the metric collection. -Different kinds of metrics are being collected as seen bellow. +Different kinds of metrics are collected as shown in the tables that follow. ### Generic metrics @@ -60,16 +60,16 @@ Different kinds of metrics are being collected as seen bellow. ## Tracing -Tracing collection to OpenTelemetry requires `bdr.trace_otel_http_url` to be -configured and tracing itself to be enabled using `bdr.trace_enable`. +Tracing collection to OpenTelemetry requires configuring `bdr.trace_otel_http_url` +and enabling tracing using `bdr.trace_enable`. The tracing is limited to only some subsystems at the moment, primarily to the -cluster management functionality. The following spans can be seen in traces: +cluster management functionality. The following spans can be seen in traces. | Span name | Description | | --------- | ----------- | | create_node_group | Group creation -| alter_node_group_config | Change of group config option(s) +| alter_node_group_config | Change of group config options | alter_node_config | Change of node config option | join_node_group | Node joining a group | join_send_remote_request | Join source sending the join request on behalf of the joining node @@ -93,7 +93,7 @@ cluster management functionality. The following spans can be seen in traces: ## TLS support -The metrics and tracing endpoints can be either HTTP or HTTPS. It's possible -to configure paths to the CA bundle, client key, and client certificate using +The metrics and tracing endpoints can be HTTP or HTTPS. You can +configure paths to the CA bundle, client key, and client certificate using `bdr.otel_https_ca_path`, `bdr.otel_https_key_path`, and `bdr.otel_https_cert_path` configuration options. diff --git a/product_docs/docs/pgd/5/monitoring/sql.mdx b/product_docs/docs/pgd/5/monitoring/sql.mdx index f305b1145bc..f2fc9172ea4 100644 --- a/product_docs/docs/pgd/5/monitoring/sql.mdx +++ b/product_docs/docs/pgd/5/monitoring/sql.mdx @@ -6,49 +6,49 @@ EDB Postgres Distributed provides several monitoring and statistics views that are specific to its distributed nature. The standard Postgres monitoring is also useful for monitoring EDB Postgres Distributed. -## Monitoring Overview +## Monitoring overview -A BDR Group consists of multiple servers, often referred to as nodes. All of the -nodes need to be monitored to ensure the health of the whole group. +A PGD group consists of multiple servers, often referred to as nodes. Monitor all of the +nodes to ensure the health of the whole group. -The bdr_monitor role may execute the `bdr.monitor` functions to provide an -assessment of BDR health using one of three levels: +The bdr_monitor role can execute the `bdr.monitor` functions to provide an +assessment of PGD health using one of three levels: -- `OK` - often shown as Green -- `WARNING` - often shown as Yellow -- `CRITICAL` - often shown as Red -- as well as `UNKNOWN` - for unrecognized situations, often shown as Red +- `OK` — Often shown as green. +- `WARNING` — Often shown as yellow. +- `CRITICAL` — Often shown as red. +- `UNKNOWN` — For unrecognized situations, often shown as red. -BDR also provides dynamic catalog views that show the instantaneous state of various -internal metrics and also BDR metadata catalogs that store the configuration -defaults and/or configuration changes requested by the user. Some of those views +PGD also provides dynamic catalog views that show the instantaneous state of various +internal metrics. It also provides metadata catalogs that store the configuration +defaults and configuration changes the user requests. Some of those views and tables are accessible by bdr_monitor or bdr_read_all_stats, but some contain user or internal information that has higher security requirements. -BDR allows you to monitor each of the nodes individually, or to monitor the -whole group by access to a single node. If you wish to monitor each node individually, -simply connect to each node and issue monitoring requests. If you wish to monitor -the group from a single node then use the views starting with `bdr.group` since these +PGD allows you to monitor each of the nodes individually or to monitor the +whole group by access to a single node. If you want to monitor each node individually, +connect to each node and issue monitoring requests. If you want to monitor +the group from a single node, then use the views starting with `bdr.group` since these requests make calls to other nodes to assemble a group-level information set. -If you have been granted access to the `bdr.run_on_all_nodes()` function by -bdr_superuser then you may make your own calls to all nodes. +If you were granted access to the `bdr.run_on_all_nodes()` function by +bdr_superuser, then you can make your own calls to all nodes. -## Monitoring Node Join and Removal +## Monitoring node join and removal By default, the node management functions wait for the join or part -operation to complete. This can be turned off using the respective -`wait_for_completion` function argument. If waiting is turned off, +operation to complete. You can turn waiting off using the respective +`wait_for_completion` function argument. If waiting is turned off, then to see when a join or part operation finishes, -check the node state indirectly via `bdr.node_summary` and +check the node state indirectly using `bdr.node_summary` and `bdr.event_summary`. -When called, the helper function `bdr.wait_for_join_completion()` will cause +When called, the helper function `bdr.wait_for_join_completion()` causes a PostgreSQL session to pause until all outstanding node join operations -complete. +area complete. -Here is an example output of a `SELECT` query from `bdr.node_summary` that -indicates that two nodes are active and another one is joining: +This example shows the output of a `SELECT` query from `bdr.node_summary`. It +indicates that two nodes are active and another one is joining. ``` # SELECT node_name, interface_connstr, peer_state_name, @@ -74,11 +74,11 @@ node_seq_id | 3 node_local_dbname | postgres ``` -Also, the table [`bdr.node_catchup_info`](../catalogs/#bdrnode_catchup_info) will give information +Also, the table [`bdr.node_catchup_info`](../catalogs/#bdrnode_catchup_info) gives information on the catch-up state, which can be relevant to joining nodes or parting nodes. -When a node is parted, it could be that some nodes in the cluster did not receive -all the data from that parting node. So it will create a temporary slot from +When a node is parted, some nodes in the cluster might not receive +all the data from that parting node. So parting a node creates a temporary slot from a node that already received that data and can forward it. The `catchup_state` can be one of the following: @@ -92,24 +92,24 @@ The `catchup_state` can be one of the following: ## Monitoring Replication Peers -There are two main views used for monitoring of replication activity: +You use two main views for monitoring of replication activity: - [`bdr.node_slots`](../catalogs/#bdrnode_slots) for monitoring outgoing replication - [`bdr.subscription_summary`](../catalogs/#bdrsubscription_summary) for monitoring incoming replication -Most of the information provided by `bdr.node_slots` can be also obtained by querying +You can also obtain most of the information provided by `bdr.node_slots` by querying the standard PostgreSQL replication monitoring views [`pg_catalog.pg_stat_replication`](https://www.postgresql.org/docs/current/static/monitoring-stats.html#PG-STAT-REPLICATION-VIEW) and [`pg_catalog.pg_replication_slots`](https://www.postgresql.org/docs/current/view-pg-replication-slots.html). -Each node has one BDR group slot which should never have a connection to it -and will very rarely be marked as active. This is normal, and does not imply -something is down or disconnected. See [`Replication Slots created by BDR`](../nodes/#replication-slots-created-by-bdr). +Each node has one PGD group slot that must never have a connection to it +and is very rarely be marked as active. This is normal and doesn't imply +something is down or disconnected. See [Replication slots created by PGD`](../nodes/#replication-slots-created-by-pgd). -### Monitoring Outgoing Replication +### Monitoring outgoing replication -There is an additional view used for monitoring of outgoing replication activity: +You can use another view for monitoring of outgoing replication activity: - [`bdr.node_replication_rates`](../catalogs/#bdrnode_replication_rates) for monitoring outgoing replication @@ -141,21 +141,22 @@ apply_rate | 853 catchup_interval | 00:00:00 ``` -The `apply_rate` above refers to the rate in bytes per second. It is the rate +The `apply_rate` refers to the rate in bytes per second. It's the rate at which the peer is consuming data from the local node. The `replay_lag` when -a node reconnects to the cluster is immediately set to zero. We are working on -fixing this information; as a workaround, we suggest you use the `catchup_interval` +a node reconnects to the cluster is immediately set to zero. This information will be +fixed in a future release. As a workaround, we recommend using the `catchup_interval` column that refers to the time required for the peer node to catch up to the -local node data. The other fields are also available via the `bdr.node_slots` -view, as explained below. +local node data. The other fields are also available from the `bdr.node_slots` +view. + !!! Note - This catalog is only present when bdr-enteprise extension is installed. + This catalog is present only when the bdr-enteprise extension is installed. -Administrators may query `bdr.node_slots` for outgoing replication from the +Administrators can query `bdr.node_slots` for outgoing replication from the local node. It shows information about replication status of all other nodes -in the group that are known to the current node, as well as any additional -replication slots created by BDR on the current node. +in the group that are known to the current node as well as any additional +replication slots created by PGD on the current node. ``` # SELECT node_group_name, target_dbname, target_name, slot_name, active_pid, @@ -190,60 +191,66 @@ replay_lag_bytes| 84211 replay_lag_size | 82 kB ``` -Note that because BDR is a mesh network, to get full view of lag in the -cluster, this query has to be executed on all nodes participating. +Because PGD is a mesh network, to get the full view of lag in the +cluster, you must execute this query on all nodes participating. `replay_lag_bytes` reports the difference in WAL positions between the local server's current WAL write position and `replay_lsn`, the last position -confirmed replayed by the peer node. `replay_lag_size` is just a human-readable -form of the same. It is important to understand that WAL usually contains a lot -of writes that are not replicated but still count in `replay_lag_bytes`, -including `VACUUM` activity, index changes, writes associated with other -databases on the same node, writes for tables that are not part of a -replication set, etc. So the lag in bytes reported here is not the amount of +confirmed replayed by the peer node. `replay_lag_size` is a human-readable +form of the same. It's important to understand that WAL usually contains a lot +of writes that aren't replicated but still count in `replay_lag_bytes`, +including, for example: + +- `VACUUM` activity +- Index changes +- Writes associated with other databases on the same node +- Writes for tables that are not part of a replication set + +So the lag in bytes reported here isn't the amount of data that must be replicated on the wire to bring the peer node up to date, only the amount of server-side WAL that must be processed. -Similarly, `replay_lag` is not a measure of how long the peer node will take to -catch up, or how long it will take to replay from its current position to the +Similarly, `replay_lag` isn't a measure of how long the peer node takes to +catch up or how long it takes to replay from its current position to the write position at the time `bdr.node_slots` was queried. It measures the delay between when the peer confirmed the most recent commit and the current wall-clock time. We suggest that you monitor `replay_lag_bytes` and `replay_lag_size` or `catchup_interval` in `bdr.node_replication_rates`, as this column is set to zero immediately after the node reconnects. -The lag in both bytes and time does not advance while logical replication is -streaming a transaction. It only changes when a commit is replicated. So the lag -will tend to "sawtooth", rising as a transaction is streamed, then falling again +The lag in both bytes and time doesn't advance while logical replication is +streaming a transaction. It changes only when a commit is replicated. So the lag +tends to "sawtooth," rising as a transaction is streamed and then falling again as the peer node commits it, flushes it, and sends confirmation. The reported -LSN positions will "stair-step" instead of advancing smoothly, for similar +LSN positions "stair-step" instead of advancing smoothly, for similar reasons. When replication is disconnected (`active` = `'f'`), the `active_pid` column -will be `NULL`, as will `client_addr` and other fields that only make sense -with an active connection. The `state` field will be `'disconnected'`. The -`_lsn` fields will be the same as the `confirmed_flush_lsn`, since that is the +is `NULL`, as is `client_addr` and the other fields that make sense only +with an active connection. The `state` field is `'disconnected'`. The +`_lsn` fields are the same as the `confirmed_flush_lsn`, since that's the last position that the client is known for certain to have replayed to and saved. -The `_lag` fields will show the elapsed time between the most recent confirmed -flush on the client and the current time, and the `_lag_size` and `_lag_bytes` -fields will report the distance between `confirmed_flush_lsn` and the local +The `_lag` fields show the elapsed time between the most recent confirmed +flush on the client and the current time. The `_lag_size` and `_lag_bytes` +fields report the distance between `confirmed_flush_lsn` and the local server's current WAL insert position. -Note: It is normal for `restart_lsn` to be behind the other `lsn` columns; -this does not indicate a problem with replication or a peer node lagging. The -`restart_lsn` is the position that PostgreSQL's internal logical decoding must -be reading WAL at if interrupted, and generally reflects the position of the -oldest transaction that is not yet replicated and flushed. A very old -`restart_lsn` can make replication slow to restart after disconnection and -force retention of more WAL than is desirable, but will otherwise be harmless. -If you are concerned, look for very long running transactions and forgotten -prepared transactions. - -### Monitoring Incoming Replication - -Incoming replication (also called subscription) can be monitored by querying -the `bdr.subscription_summary` view. This shows the list of known subscriptions -to other nodes in the EDB Postgres Distributed cluster and the state of the replication worker, e.g.: +!!! Note + It's normal for `restart_lsn` to be behind the other `lsn` columns. + This doesn't indicate a problem with replication or a peer node lagging. The + `restart_lsn` is the position that PostgreSQL's internal logical decoding must + be reading WAL at if interrupted. It generally reflects the position of the + oldest transaction that's not yet replicated and flushed. A very old + `restart_lsn` can make replication slow to restart after disconnection and + force retention of more WAL than is desirable, but it's otherwise harmless. + If you're concerned, look for very long-running transactions and forgotten + prepared transactions. + +### Monitoring incoming replication + +You can monitor incoming replication (also called subscriptions) by querying +the `bdr.subscription_summary` view. This query shows the list of known subscriptions +to other nodes in the EDB Postgres Distributed cluster and the state of the replication worker: ``` # SELECT node_group_name, origin_name, sub_enabled, sub_slot_name, @@ -265,10 +272,9 @@ subscription_status | replicating ### Monitoring WAL senders using LCR -If the [Decoding Worker](../nodes#decoding-worker) is enabled, information about the -current LCR (`Logical Change Record`) file for each WAL sender can be monitored -via the function [bdr.wal_sender_stats](../functions#bdrwal_sender_stats), -e.g.: +If the [decoding worker](../nodes#decoding-worker) is enabled, you can monitor information about the +current logical change record (LCR) file for each WAL sender +using the function [bdr.wal_sender_stats](../functions#bdrwal_sender_stats). For example: ``` postgres=# SELECT * FROM bdr.wal_sender_stats(); @@ -280,12 +286,12 @@ postgres=# SELECT * FROM bdr.wal_sender_stats(); (3 rows) ``` -If `is_using_lcr` is `FALSE`, `decoder_slot_name`/`lcr_file_name` will be `NULL`. -This will be the case if the Decoding Worker is not enabled, or the WAL sender is +If `is_using_lcr` is `FALSE`, `decoder_slot_name`/`lcr_file_name` is `NULL`. +This is the case if the decoding worker isn't enabled or the WAL sender is serving a [logical standby](../nodes#logical-standby-nodes). -Additionally, information about the Decoding Worker can be monitored via the function -[bdr.get_decoding_worker_stat](../functions#bdrget_decoding_worker_stat), e.g.: +Also, you can monitor information about the decoding worker using the function +[bdr.get_decoding_worker_stat](../functions#bdrget_decoding_worker_stat). For example: ``` postgres=# SELECT * FROM bdr.get_decoding_worker_stat(); @@ -295,73 +301,72 @@ postgres=# SELECT * FROM bdr.get_decoding_worker_stat(); (1 row) ``` -## Monitoring BDR Replication Workers +## Monitoring PGD replication workers -All BDR workers show up in the system view `bdr.stat_activity`, +All PGD workers show up in the system view `bdr.stat_activity`, which has the same columns and information content as [pg_stat_activity](https://www.postgresql.org/docs/current/monitoring-stats.html#PG-STAT-ACTIVITY-VIEW). -So this view offers these insights into the state of a BDR system: +So this view offers these insights into the state of a PGD system: - The wait_event column has enhanced information, if - the reason for waiting is related to BDR. -- The `query` column will be blank in BDR workers, except - when a writer process is executing DDL + the reason for waiting is related to PGD. +- The `query` column is blank in PGD workers, except + when a writer process is executing DDL. -The `bdr.workers` view shows BDR worker specific details, that are not +The `bdr.workers` view shows PGD worker-specific details that aren't available from `bdr.stat_activity`. -The view `bdr.event_summary` shows last error (if any) reported by any worker -which has a problem continuing the work. This is persistent information, so -it's important to note the time of the error not just the existence of one, -because most errors are transient in their nature and BDR workers will retry +The view `bdr.event_summary` shows the last error (if any) reported by any worker +that has a problem continuing the work. This information is persistent, so +it's important to note the time of the error and not just its existence. +Most errors are transient, and PGD workers will retry the failed operation. -## Monitoring BDR Writers +## Monitoring PGD writers -There is another system view `bdr.writers` to monitor writer activities. -This views shows the current status of only writer workers. It includes: +Another system view, `bdr.writers`, monitors writer activities. +This view shows only the current status of writer workers. It includes: -- `sub_name` to identify the subscription which the writer belongs to +- `sub_name` to identify the subscription that the writer belongs to - `pid` of the writer process -- `streaming_allowed` to know if the writer supports application of +- `streaming_allowed` to know if the writer supports applying in-progress streaming transactions - `is_streaming` to know if the writer is currently applying a streaming transaction - `commit_queue_position` to check the position of the writer in the - commit queue. + commit queue -BDR honours commit ordering by following the same commit order as +PGD honors commit ordering by following the same commit order as happened on the origin. In case of parallel writers, multiple writers -could be applying different transactions at the same time. The -`commit_queue_position` shows in which order they will commit. Value `0` +might apply different transactions at the same time. The +`commit_queue_position` shows the order in which they will commit. Value `0` means that the writer is the first one to commit. Value `-1` means that -the commit position is not yet known. This can happen for a streaming -transaction or when the writer is not applying any transaction at the -moment. +the commit position isn't yet known, which can happen for a streaming +transaction or when the writer isn't currently applying any transaction. -## Monitoring Global Locks +## Monitoring global locks -The global lock, which is currently only used for DDL replication, is a heavyweight -lock that exists across the whole BDR group. +The global lock, which is currently used only for DDL replication, is a heavyweight +lock that exists across the whole PGD group. There are currently two types of global locks: - DDL lock, used for serializing all DDL operations on permanent - (not temporary) objects (i.e. tables) in the database + (not temporary) objects (that is, tables) in the database - DML relation lock, used for locking out writes to relations during DDL operations that change the relation definition -Either or both entry types may be created for the same transaction, depending on +You can create either or both entry types for the same transaction, depending on the type of DDL operation and the value of the `bdr.ddl_locking` setting. -Global locks held on the local node are visible in [the `bdr.global_locks` -view](../catalogs#bdrglobal_locks). This view shows the type of the lock; for -relation locks it shows which relation is being locked, the PID holding the -lock (if local), and whether the lock has been globally granted or not. In case -of global advisory locks, `lock_type` column shows `GLOBAL_LOCK_ADVISORY` and -`relation` column shows the advisory key(s) on which the lock is acquired. +Global locks held on the local node are visible in the [`bdr.global_locks`](../catalogs#bdrglobal_locks) view. +This view shows the type of the lock. For +relation locks, it shows the relation that's being locked, the PID holding the +lock (if local), and whether the lock was globally granted. In case +of global advisory locks, `lock_type` column shows `GLOBAL_LOCK_ADVISORY`, and +`relation` column shows the advisory keys on which the lock is acquired. -The following is an example output of `bdr.global_locks` while running an +This example shows the output of `bdr.global_locks` while running an `ALTER TABLE` statement with `bdr.ddl_locking = on`: ``` @@ -376,26 +381,24 @@ relation | someschema.sometable pid | 15534 ``` -See the catalog documentation for details on all fields including lock +See [Catalogs](../catalogs) for details on all fields, including lock timing information. -## Monitoring Conflicts +## Monitoring conflicts Replication [conflicts](../consistency/conflicts) can arise when multiple nodes make changes that affect the same rows in ways that can interact with each other. -The BDR system should be monitored to ensure that conflicts are identified -and, where possible, application changes are made to eliminate them or make -them less frequent. +Monitor the PGD system to identify conflicts and, where possible, make application changes to eliminate the conflicts or make them less frequent. -By default, all conflicts are logged to `bdr.conflict_history`. Since this +By default, all conflicts are logged to `bdr.conflict_history`. Since this log contains full details of conflicting data, the rows are protected by -row-level security to ensure they are visible only by +row-level security to ensure they're visible only by owners of replicated tables. Owners should expect conflicts and analyze them -to see which, if any, might be considered as problems to be resolved. +to see which, if any, might be considered as problems to resolve. -For monitoring purposes use `bdr.conflict_history_summary`, which does -not contain user data. An example query to count the number of conflicts -seen within the current day using an efficient query plan is: +For monitoring purposes, use `bdr.conflict_history_summary`, which doesn't +contain user data. This example shows a query to count the number of conflicts +seen in the current day using an efficient query plan: ```sql SELECT count(*) @@ -404,9 +407,9 @@ WHERE local_time > date_trunc('day', current_timestamp) AND local_time < date_trunc('day', current_timestamp + '1 day'); ``` -## Apply Statistics +## Apply statistics -BDR collects statistics about replication apply, both for each subscription +PGD collects statistics about replication apply, both for each subscription and for each table. Two monitoring views exist: `bdr.stat_subscription` for subscription statistics @@ -419,21 +422,21 @@ and `bdr.stat_relation` for relation statistics. These views both provide: - Number of in-progress transactions streamed to writers - Number of in-progress streamed transactions committed/aborted -and for relations only, these statistics: +For relations only, `bdr.stat_relation` also includes: - Total time spent processing replication for the relation - Total lock wait time to acquire lock (if any) for the relation (only) -and for subscriptions only, these statistics: +For subscriptions only, `bdr.stat_subscription` includes: - Number of COMMITs/DDL replicated for the subscription - Number of times this subscription has connected upstream -Tracking of these statistics is controlled by the BDR GUCs -`bdr.track_subscription_apply` and `bdr.track_relation_apply` +Tracking of these statistics is controlled by the PGD GUCs +`bdr.track_subscription_apply` and `bdr.track_relation_apply`, respectively. -The example output from these would look like this: +The following shows the example output from these: ```sql # SELECT sub_name, nconnect, ninsert, ncommit, nupdate, ndelete, ntruncate, nddl @@ -449,19 +452,19 @@ ntruncate | 0 nddl | 2 ``` -In this case the subscription connected 3 times to the upstream, inserted -10 rows and did 2 DDL commands inside 5 transactions. +In this case, the subscription connected three times to the upstream, inserted +10 rows, and performed two DDL commands inside five transactions. -Stats counters for these views can be reset to zero using the functions +You can reset the stats counters for these views to zero using the functions `bdr.reset_subscription_stats` and `bdr.reset_relation_stats`. -## Standard PostgreSQL Statistics Views +## Standard PostgreSQL statistics views -Statistics on table and index usage are updated normally by the downstream +Statistics on table and index usage are normally updated by the downstream master. This is essential for the correct function of [autovacuum](https://www.postgresql.org/docs/current/static/routine-vacuuming.html). -If there are no local writes on the downstream master and statistics have not been -reset, these two views should show corresponding results between +If there are no local writes on the downstream master and statistics haven't been +reset, these two views show corresponding results between upstream and downstream: - `pg_stat_user_tables` @@ -469,17 +472,17 @@ upstream and downstream: !!! Note We don't necessarily expect the upstream table statistics to - be *similar* to the downstream ones; we only expect them to *change* + be *similar* to the downstream ones. We only expect them to *change* by the same amounts. Consider the example of a table whose statistics - show 1M inserts and 1M updates; when a new node joins the BDR group, - the statistics for the same table in the new node will show 1M inserts + show 1M inserts and 1M updates. When a new node joins the PGD group, + the statistics for the same table in the new node show 1M inserts and zero updates. However, from that moment, the upstream and - downstream table statistics will change by the same amounts, because - all changes on one side will be replicated to the other side. + downstream table statistics change by the same amounts because + all changes on one side are replicated to the other side. Since indexes are used to apply changes, the identifying indexes on the -downstream side may appear more heavily used with workloads that perform -`UPDATE`s and `DELETE`s than non-identifying indexes are. +downstream side might appear more heavily used with workloads that perform +`UPDATE` and `DELETE` than non-identifying indexes are. The built-in index monitoring views are: @@ -489,39 +492,39 @@ The built-in index monitoring views are: All these views are discussed in detail in the [PostgreSQL documentation on the statistics views](http://www.postgresql.org/docs/current/static/monitoring-stats.html#MONITORING-STATS-VIEWS-TABLE). -## Monitoring BDR Versions +## Monitoring PGD versions -BDR allows running different Postgres versions as well as different -BDR versions across the nodes in the same cluster. This is useful for +PGD allows running different Postgres versions as well as different +BDR extension versions across the nodes in the same cluster. This capability is useful for upgrading. The view `bdr.group_versions_details` uses the function -`bdr.run_on_all_nodes()` to retrieve Postgres and BDR versions from all nodes -at the same time. For example: +`bdr.run_on_all_nodes()` to retrieve Postgres and BDR extension versions from all +nodes at the same time. For example: ```sql bdrdb=# SELECT node_name, postgres_version, bdr_version FROM bdr.group_versions_details; node_name | postgres_version | bdr_version -----------+------------------+------------- - node1 | 14.1 | 4.0.0 - node2 | 14.1 | 4.0.0 + node1 | 15.2.0 | 5.0.0 + node2 | 15.2.0 | 5.0.0 ``` -The recommended setup is to try to have all nodes running the same -latest versions as soon as possible. It is recommended -that the cluster does not run different BDR versions for too long. +The recommended setup is to try to have all nodes running the same (and +latest) versions as soon as possible. We recommend +that the cluster doesn't run different versions of the BDR extension for too long. For monitoring purposes, we recommend the following alert levels: -- status=UNKNOWN, message=This node is not part of any BDR group -- status=OK, message=All nodes are running same BDR versions +- status=UNKNOWN, message=This node is not part of any PGD group +- status=OK, message=All nodes are running same PGD versions - status=WARNING, message=There is at least 1 node that is not accessible -- status=WARNING, message=There are node(s) running different BDR versions +- status=WARNING, message=There are node(s) running different PGD versions when compared to other nodes The described behavior is implemented in the function -`bdr.monitor_group_versions()`, which uses BDR version +`bdr.monitor_group_versions()`, which uses PGD version information returned from the view `bdr.group_version_details` to provide a cluster-wide version check. For example: @@ -532,25 +535,25 @@ bdrdb=# SELECT * FROM bdr.monitor_group_versions(); OK | All nodes are running same BDR versions ``` -## Monitoring Raft Consensus +## Monitoring Raft consensus -Raft Consensus should be working cluster-wide at all times. The impact -of running a EDB Postgres Distributed cluster without Raft Consensus working might be as +Raft consensus must be working cluster-wide at all times. The impact +of running a EDB Postgres Distributed cluster without Raft consensus working might be as follows: -- BDR data changes replication may still be working correctly -- Global DDL/DML locks will not work -- Galloc sequences will eventually run out of chunks -- Eager Replication will not work +- The replication of PGD data changes might still work correctly. +- Global DDL/DML locks doesn't work. +- Galloc sequences eventually run out of chunks. +- Eager replication doesn't work. - Cluster maintenance operations (join node, part node, promote standby) - are still allowed but they might not finish (simply hang) -- Node statuses might not be correctly synced among the BDR nodes -- BDR group replication slot does not advance LSN, thus keeps WAL files on - disk + are still allowed, but they might not finish (hanging instead). +- Node statuses might not be correctly synced among the PGD nodes. +- PGD group replication slot doesn't advance LSN and thus keeps WAL files on + disk. The view `bdr.group_raft_details` uses the functions `bdr.run_on_all_nodes()` and `bdr.get_raft_status()` to retrieve Raft -Consensus status from all nodes at the same time. For example: +consensus status from all nodes at the same time. For example: ```sql bdrdb=# SELECT node_id, node_name, state, leader_id @@ -561,48 +564,48 @@ FROM bdr.group_raft_details; 3367056606 | node2 | top_group | RAFT_FOLLOWER | 1148549230 ``` -We can say that Raft Consensus is working correctly if all below +Raft consensus is working correctly if all of these conditions are met: - A valid state (`RAFT_LEADER` or `RAFT_FOLLOWER`) is defined on all - nodes -- Only one of the nodes is the `RAFT_LEADER` + nodes. +- Only one of the nodes is the `RAFT_LEADER`. - The `leader_id` is the same on all rows and must match the `node_id` - of the row where `state = RAFT_LEADER` + of the row where `state = RAFT_LEADER`. -From time to time, Raft Consensus will start a new election to define a +From time to time, Raft consensus starts a new election to define a new `RAFT_LEADER`. During an election, there might be an intermediary -situation where there is no `RAFT_LEADER` and some of the nodes consider -themselves as `RAFT_CANDIDATE`. The whole election should not take longer -than `bdr.raft_election_timeout` (by default it is set to 6 seconds). If -the query above returns an in-election situation, then simply wait for -`bdr.raft_election_timeout` and run the query again. If after -`bdr.raft_election_timeout` has passed and some the conditions above are -still not met, then Raft Consensus is not working. - -Raft Consensus might not be working correctly on a single node only; -for example one of the nodes does not recognize the current leader and -considers itself as a `RAFT_CANDIDATE`. In this case, it is important to +situation where there's no `RAFT_LEADER`, and some of the nodes consider +themselves as `RAFT_CANDIDATE`. The whole election can't take longer +than `bdr.raft_election_timeout` (by default it's set to 6 seconds). If +the query above returns an in-election situation, then wait for +`bdr.raft_election_timeout`, and run the query again. If after +`bdr.raft_election_timeout` has passed and some the listed conditions are +still not met, then Raft consensus isn't working. + +Raft consensus might not be working correctly on only a single node. +For example, one of the nodes doesn't recognize the current leader and +considers itself as a `RAFT_CANDIDATE`. In this case, it's important to make sure that: -- All BDR nodes are accessible to each other through both regular and - replication connections (check file `pg_hba.conf`) -- BDR versions are the same on all nodes -- `bdr.raft_election_timeout` is the same on all nodes +- All PGD nodes are accessible to each other through both regular and + replication connections (check file `pg_hba.conf`). +- PGD versions are the same on all nodes. +- `bdr.raft_election_timeout` is the same on all nodes. In some cases, especially if nodes are geographically distant from each -other and/or network latency is high, the default value of +other or network latency is high, the default value of `bdr.raft_election_timeout` (6 seconds) might not be enough. If Raft -Consensus is still not working even after making sure everything is -correct, consider increasing `bdr.raft_election_timeout` to, say, 30 -seconds on all nodes. From BDR 3.6.11 onwards, setting +consensus is still not working even after making sure everything is +correct, consider increasing `bdr.raft_election_timeout` to 30 +seconds on all nodes. For PGD 3.6.11 and later, setting `bdr.raft_election_timeout` requires only a server reload. -Given how Raft Consensus affects cluster operational tasks, and also as -Raft Consensus is directly responsible for advancing the group slot, -we can define monitoring alert levels as follows: +Given how Raft consensus affects cluster operational tasks, and also as +Raft consensus is directly responsible for advancing the group slot, +monitoring alert levels are defined as follows: -- status=UNKNOWN, message=This node is not part of any BDR group +- status=UNKNOWN, message=This node is not part of any PGD group - status=OK, message=Raft Consensus is working correctly - status=WARNING, message=There is at least 1 node that is not accessible - status=WARNING, message=There are node(s) as RAFT_CANDIDATE, an @@ -616,7 +619,7 @@ we can define monitoring alert levels as follows: than the node set as RAFT_LEADER The described behavior is implemented in the function -`bdr.monitor_group_raft()`, which uses Raft Consensus status +`bdr.monitor_group_raft()`, which uses Raft consensus status information returned from the view `bdr.group_raft_details` to provide a cluster-wide Raft check. For example: @@ -627,11 +630,11 @@ node_group_name | status | message myroup | OK | Raft Consensus is working correctly ``` -## Monitoring Replication Slots +## Monitoring replication slots -Each BDR node keeps: +Each PGD node keeps: -- One replication slot per active BDR peer +- One replication slot per active PGD peer - One group replication slot For example: @@ -648,27 +651,27 @@ FROM pg_replication_slots ORDER BY slot_name; ``` Peer slot names follow the convention `bdr___`, -while the BDR group slot name follows the convention -`bdr__`, which can be accessed using the function +while the PGD group slot name follows the convention +`bdr__`. You can access the group slot using the function `bdr.local_group_slot_name()`. -Peer replication slots should be active on all nodes at all times. -If a peer replication slot is not active, then it might mean: +Peer replication slots must be active on all nodes at all times. +If a peer replication slot isn't active, then it might mean either: -- The corresponding peer is shutdown or not accessible; or -- BDR replication is broken. +- The corresponding peer is shut down or not accessible. +- PGD replication is broken. -Grep the log file for `ERROR` or `FATAL` and also check `bdr.event_summary` on -all nodes. The root cause might be, for example, an incompatible DDL was +Grep the log file for `ERROR` or `FATAL`, and also check `bdr.event_summary` on +all nodes. The root cause might be, for example, an incompatible DDL was executed with DDL replication disabled on one of the nodes. -The BDR group replication slot is however inactive most of the time. BDR -maintains this slot and advances its LSN when all other peers have already -consumed the corresponding transactions. Consequently it is not necessary to +The PGD group replication slot is, however, inactive most of the time. PGD +maintains this slot and advances its LSN when all other peers already +consumed the corresponding transactions. Consequently, it's not necessary to monitor the status of the group slot. The function `bdr.monitor_local_replslots()` provides a summary of whether all -BDR node replication slots are working as expected, e.g.: +PGD node replication slots are working as expected. For example: ```sql bdrdb=# SELECT * FROM bdr.monitor_local_replslots(); @@ -677,7 +680,7 @@ bdrdb=# SELECT * FROM bdr.monitor_local_replslots(); OK | All BDR replication slots are working correctly ``` -One of the following status summaries will be returned: +One of the following status summaries is returned: - `UNKNOWN`: `This node is not part of any BDR group` - `OK`: `All BDR replication slots are working correctly` @@ -685,17 +688,17 @@ One of the following status summaries will be returned: - `CRITICAL`: `There is at least 1 BDR replication slot which is inactive` - `CRITICAL`: `There is at least 1 BDR replication slot which is missing` -## Monitoring Transaction COMMITs +## Monitoring transaction COMMITs -By default, BDR transactions commit only on the local node. In that case, -transaction `COMMIT` will be processed quickly. +By default, PGD transactions commit only on the local node. In that case, +transaction `COMMIT` is processed quickly. -BDR can be used with standard PostgreSQL synchronous replication, while -BDR also provides two new transaction commit modes: CAMO and Eager -replication. Each of these modes provides additional robustness +You can use PGD with standard PostgreSQL synchronous replication. +PGD also provides two new transaction commit modes: CAMO and eager +replication. Each of these modes adds robustness features, though at the expense of additional latency at `COMMIT`. -The additional time at `COMMIT` can be monitored dynamically using the +You can monitor the additional time at `COMMIT` dynamically using the `bdr.stat_activity` catalog, where processes report different `wait_event` -states. A transaction in `COMMIT` waiting for confirmations from one or +states. A transaction in `COMMIT` waiting for confirmations from one or more synchronous standbys reports a `SyncRep` wait event, whereas the two new modes report `EagerRep`. diff --git a/product_docs/docs/pgd/5/nodes.mdx b/product_docs/docs/pgd/5/nodes.mdx index 1f0e37ad882..3b6dece53ef 100644 --- a/product_docs/docs/pgd/5/nodes.mdx +++ b/product_docs/docs/pgd/5/nodes.mdx @@ -5,34 +5,34 @@ redirects: --- -Each database that's member of a BDR group must be represented by its own -node. A node is a unique identifier of a database in a BDR group. +Each database that's member of a PGD group must be represented by its own +node. A node is a unique identifier of a database in a PGD group. At present, each node can be a member of just one node group. (This might be extended in later releases.) Each node can subscribe to one or more replication sets to give fine-grained control over replication. -A BDR group might also contain zero or more subgroups, allowing you to create a variety +A PGD group might also contain zero or more subgroups, allowing you to create a variety of different architectures. -## Creating and joining a BDR group +## Creating and joining a PGD group -For BDR, every node must connect to every other node. To make +For PGD, every node must connect to every other node. To make configuration easy, when a new node joins, it configures all existing nodes to connect to it. For this reason, every node, including -the first BDR node created, must know the [PostgreSQL connection string](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING), +the first PGD node created, must know the [PostgreSQL connection string](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING), sometimes referred to as a data source name (DSN), that other nodes can use to connect to it. Both formats of connection string are supported. So you can use either key-value format, like `host=myhost port=5432 dbname=mydb`, or URI format, like `postgresql://myhost:5432/mydb`. -The SQL function `bdr.create_node_group()` creates the BDR group -from the local node. Doing so activates BDR on that node and allows other -nodes to join the BDR group, which consists of only one node at that point. +The SQL function `bdr.create_node_group()` creates the PGD group +from the local node. Doing so activates PGD on that node and allows other +nodes to join the PGD group, which consists of only one node at that point. At the time of creation, you must specify the connection string for other nodes to use to connect to this node. -Once the node group is created, every further node can join the BDR +Once the node group is created, every further node can join the PGD group using the `bdr.join_node_group()` function. Alternatively, use the command line utility `bdr_init_physical` to @@ -44,7 +44,7 @@ completes faster and also uses less space because it excludes unwanted databases. If you specify only the target database, then the excluded databases get cleaned up and removed on the new node. -When a new BDR node is joined to an existing BDR group or a node subscribes +When a new PGD node is joined to an existing PGD group or a node subscribes to an upstream peer, before replication can begin the system must copy the existing data from the peer nodes to the local node. This copy must be carefully coordinated so that the local and remote data starts out @@ -53,13 +53,13 @@ extension provides built-in facilities for making this initial copy. During the join process, the BDR extension synchronizes existing data using the provided source node as the basis and creates all metadata -information needed for establishing itself in the mesh topology in the BDR +information needed for establishing itself in the mesh topology in the PGD group. If the connection between the source and the new node disconnects during this initial copy, restart the join process from the beginning. The node that is joining the cluster must not contain any schema or data -that already exists on databases in the BDR group. We recommend that the +that already exists on databases in the PGD group. We recommend that the newly joining database be empty except for the BDR extension. However, it's important that all required database users and roles are created. @@ -106,9 +106,9 @@ Retrying the join works in that case. ### Joining a heterogeneous cluster -BDR 4.0 node can join a EDB Postgres Distributed cluster running 3.7.x at a specific +PGD 4.0 node can join a EDB Postgres Distributed cluster running 3.7.x at a specific minimum maintenance release (such as 3.7.6) or a mix of 3.7 and 4.0 nodes. -This procedure is useful when you want to upgrade not just the BDR +This procedure is useful when you want to upgrade not just the PGD major version but also the underlying PostgreSQL major version. You can achieve this by joining a 3.7 node running on PostgreSQL 12 or 13 to a EDB Postgres Distributed cluster running 3.6.x on @@ -116,7 +116,7 @@ PostgreSQL 11. The new node can also run on the same PostgreSQL major release as all of the nodes in the existing cluster. -BDR ensures that the replication works correctly in all directions +PGD ensures that the replication works correctly in all directions even when some nodes are running 3.6 on one PostgreSQL major release and other nodes are running 3.7 on another PostgreSQL major release. But we recommend that you quickly bring the cluster into a @@ -161,7 +161,7 @@ addresses, so if the connection is made by address rather than name, it must match the CN field. The CN of the client certificate must be the name of the user making the -BDR connection. +PGD connection. This is usually the user postgres. Each node requires matching lines permitting the connection in the `pg_hba.conf` file. For example: @@ -195,12 +195,12 @@ an extra node to help break ties in the event of a network split (or network partition, as it is sometimes called). Rather than create an additional full-size node, you can create a micro node, -sometimes called a witness node. This is a normal BDR node that +sometimes called a witness node. This is a normal PGD node that is deliberately set up not to replicate any tables or data to it. ## Logical standby nodes -BDR allows you to create a *logical standby node*, also known as an offload +PGD allows you to create a *logical standby node*, also known as an offload node, a read-only node, receive-only node, or logical-read replicas. A master node can have zero, one, or more logical standby nodes. @@ -211,7 +211,7 @@ A master node can have zero, one, or more logical standby nodes. With a physical standby node, the node never comes up fully, forcing it to stay in continual recovery mode. -BDR allows something similar. `bdr.join_node_group` has the `pause_in_standby` +PGD allows something similar. `bdr.join_node_group` has the `pause_in_standby` option to make the node stay in half-way-joined as a logical standby node. Logical standby nodes receive changes but don't send changes made locally to other nodes. @@ -235,18 +235,18 @@ There are multiple options for high availability: so the effectiveness of this technique is limited to one logical standby. -In case a new standby is created from an existing BDR node, +In case a new standby is created from an existing PGD node, the needed replication slots for operation aren't synced to the new standby until at least 16 MB of LSN has elapsed since the group slot was last advanced. In extreme cases, this might require a full 16 MB before slots are synced or created on the streaming replica. If a failover or switchover occurs during this interval, the -streaming standby can't be promoted to replace its BDR node, as the +streaming standby can't be promoted to replace its PGD node, as the group slot and other dependent slots don't exist yet. The slot sync-up process on the standby solves this by invoking a function on the upstream. This function moves the group slot in the -entire EDB Postgres Distributed cluster by performing WAL switches and requesting all BDR +entire EDB Postgres Distributed cluster by performing WAL switches and requesting all PGD peer nodes to replay their progress updates. This causes the group slot to move ahead in a short time span. This reduces the time required by the standby for the initial slot's sync-up, allowing for @@ -263,12 +263,12 @@ SELECT true FROM pg_catalog.pg_replication_slots WHERE slot_type = 'logical' AND confirmed_flush_lsn IS NOT NULL; ``` -You can also nudge the slot sync-up process in the entire BDR -cluster by manually performing WAL switches and by requesting all BDR +You can also nudge the slot sync-up process in the entire PGD +cluster by manually performing WAL switches and by requesting all PGD peer nodes to replay their progress updates. This activity causes the group slot to move ahead in a short time and also hastens the slot sync-up activity on the standby. You can run the following queries -on any BDR peer node in the target database for this: +on any PGD peer node in the target database for this: ```sql SELECT bdr.run_on_all_nodes('SELECT pg_catalog.pg_switch_wal()'); @@ -294,7 +294,7 @@ are sent onwards. If you perform writes to a logical standby, take care to quiesce the database before promotion. You might make DDL changes to logical standby nodes but they aren't -replicated and they don't attempt to take global DDL locks. BDR functions +replicated and they don't attempt to take global DDL locks. PGD functions that act similarly to DDL also aren't replicated. See [DDL replication](ddl). If you made incompatible DDL changes to a logical standby, then the database is a *divergent node*. Promotion of a divergent @@ -305,17 +305,17 @@ ensure that divergent nodes are never promoted. ## Physical standby nodes -BDR also enables you to create traditional physical standby failover -nodes. These are commonly intended to directly replace a BDR +PGD also enables you to create traditional physical standby failover +nodes. These are commonly intended to directly replace a PGD node in the cluster after a short promotion procedure. As with any standard Postgres cluster, a node can have any number of these physical replicas. There are, however, some minimal prerequisites for this to work properly due to the use of replication slots and other functional requirements in -BDR: +PGD: -- The connection between BDR primary and standby uses streaming +- The connection between PGD primary and standby uses streaming replication through a physical replication slot. - The standby has: - `recovery.conf` (for PostgreSQL <12, for PostgreSQL 12+ these settings are in `postgres.conf`): @@ -330,25 +330,25 @@ BDR: - `bdr.standby_slot_names` specifies the physical replication slot used for the standby's `primary_slot_name`. -While this is enough to produce a working physical standby of a BDR +While this is enough to produce a working physical standby of a PGD node, you need to address some additional concerns. Once established, the standby requires enough time and WAL traffic -to trigger an initial copy of the primary's other BDR-related -replication slots, including the BDR group slot. At minimum, slots on a +to trigger an initial copy of the primary's other PGD-related +replication slots, including the PGD group slot. At minimum, slots on a standby are live and can survive a failover only if they report a nonzero `confirmed_flush_lsn` as reported by `pg_replication_slots`. -As a consequence, check physical standby nodes in newly initialized BDR +As a consequence, check physical standby nodes in newly initialized PGD clusters with low amounts of write activity before assuming a failover will work normally. Failing to take this precaution can result in the standby having an incomplete subset of required -replication slots needed to function as a BDR node, and thus an +replication slots needed to function as a PGD node, and thus an aborted failover. The protection mechanism that ensures physical standby nodes are up to date and can be promoted (as configured `bdr.standby_slot_names`) affects the -overall replication latency of the BDR group. This is because the group replication +overall replication latency of the PGD group. This is because the group replication happens only when the physical standby nodes are up to date. For these reasons, we generally recommend to use either logical standby nodes @@ -356,7 +356,7 @@ or a subscribe-only group instead of physical standby nodes. They both have better operational characteristics in comparison. You can can manually ensure the group slot is advanced on all nodes -(as much as possible), which helps hasten the creation of BDR-related +(as much as possible), which helps hasten the creation of PGD-related replication slots on a physical standby using the following SQL syntax: ```sql @@ -368,27 +368,27 @@ the primary: - Assume control of the same IP address or hostname as the primary. - Inform the EDB Postgres Distributed cluster of the change in address by executing the - [bdr.alter_node_interface](#bdralter_node_interface) function on all other BDR nodes. + [bdr.alter_node_interface](#bdralter_node_interface) function on all other PGD nodes. -Once this is done, the other BDR nodes reestablish communication +Once this is done, the other PGD nodes reestablish communication with the newly promoted standby -> primary node. Since replication slots are synchronized only periodically, this new primary might reflect -a lower LSN than expected by the existing BDR nodes. If this is the -case, BDR fast forwards each lagging slot to the last location -used by each BDR node. +a lower LSN than expected by the existing PGD nodes. If this is the +case, PGD fast forwards each lagging slot to the last location +used by each PGD node. Take special note of the `bdr.standby_slot_names` parameter as well. It's important to set it in a EDB Postgres Distributed cluster where there is a primary -> physical standby relationship or when using subscriber-only groups. -BDR maintains a group slot that always reflects the state of the +PGD maintains a group slot that always reflects the state of the cluster node showing the most lag for any outbound replication. With the addition of a physical -replica, BDR must be informed that there is a nonparticipating node +replica, PGD must be informed that there is a nonparticipating node member that, regardless, affects the state of the group slot. -Since the standby doesn't directly communicate with the other BDR -nodes, the `standby_slot_names` parameter informs BDR to consider named +Since the standby doesn't directly communicate with the other PGD +nodes, the `standby_slot_names` parameter informs PGD to consider named slots as needed constraints on the group slot as well. When set, the group slot is held if the standby shows lag, even if the group slot is normally advanced. @@ -402,12 +402,12 @@ configured as a synchronous replica. As a reminder, this requires: - Enabling `synchronous_commit` - Including the standby `application_name` in `synchronous_standby_names` -It's possible to mix physical standby and other BDR nodes in +It's possible to mix physical standby and other PGD nodes in `synchronous_standby_names`. CAMO and Eager All-Node Replication use different synchronization mechanisms and don't work with synchronous replication. Make sure `synchronous_standby_names` doesn't -include any BDR node if either CAMO or Eager All-Node Replication is used. -Instead use only non-BDR nodes, for example, a physical standby. +include any PGD node if either CAMO or Eager All-Node Replication is used. +Instead use only non-PGD nodes, for example, a physical standby. ## Subgroups @@ -427,7 +427,7 @@ in the cluster and hence aren't affected by unavailability or parting of any one node in the cluster. A `subscriber-only` node is a fully joined -BDR node and hence it receives all replicated DDLs and acts on those. It +PGD node and hence it receives all replicated DDLs and acts on those. It also uses Raft to consistently report its status to all nodes in the cluster. The `subscriber-only` node doesn't have Raft voting rights and hence can't become a Raft leader or participate in the leader @@ -435,7 +435,7 @@ election. Also, while it receives replicated DDLs, it doesn't participate in DDL or DML lock acquisition. In other words, a currently down `subscriber-only` node doesn't stop a DML lock from being acquired. -The `subscriber-only` node forms the building block for BDR Tree +The `subscriber-only` node forms the building block for PGD Tree topology. In this topology, a small number of fully active nodes are replicating changes in all directions. A large number of `subscriber-only` nodes receive only changes but never @@ -445,7 +445,7 @@ an extremely large number of `leaf` nodes that you can use to consume the data. To make use of `subscriber-only` nodes, first -create a BDR group of type `subscriber-only`. Make it a subgroup of +create a PGD group of type `subscriber-only`. Make it a subgroup of the group from which the member nodes receive the replication changes. Once you create the subgroup, all nodes that intend to become `subscriber-only` nodes must join the subgroup. You can create more than one @@ -471,9 +471,9 @@ causes inconsistency between the nodes. For now, you can solve this by setting `bdr.standby_slot_names` and `bdr.standby_slots_min_confirmed` so that there -is always a fully active BDR node that is ahead of the `subscriber-only` +is always a fully active PGD node that is ahead of the `subscriber-only` nodes. - + This might be improved in a future release. We might either allow `subscriber-only` nodes to be ahead in the replication and then use them as replication source for sync or simply provide ways to optionally @@ -482,24 +482,24 @@ another fully joined node is parted. ## Decoding worker -BDR4 provides an option to enable a decoding worker process that performs +PGD4 provides an option to enable a decoding worker process that performs decoding once, no matter how many nodes are sent data. This introduces a -new process, the WAL decoder, on each BDR node. One WAL sender process still +new process, the WAL decoder, on each PGD node. One WAL sender process still exists for each connection, but these processes now just perform the task of sending and receiving data. Taken together, these changes reduce the CPU -overhead of larger BDR groups and also allow higher replication throughput +overhead of larger PGD groups and also allow higher replication throughput since the WAL sender process now spends more time on communication. -`enable_wal_decoder` is an option for each BDR group, which is currently +`enable_wal_decoder` is an option for each PGD group, which is currently disabled by default. You can use `bdr.alter_node_group_config()` to enable or -disable the decoding worker for a BDR group. +disable the decoding worker for a PGD group. -When the decoding worker is enabled, BDR stores logical change record (LCR) +When the decoding worker is enabled, PGD stores logical change record (LCR) files to allow buffering of changes between decoding and when all subscribing nodes received data. LCR files are stored under the `pg_logical` directory in each local node's data directory. The number and size of the LCR files varies as replication lag increases, so this also -needs monitoring. The LCRs that aren't required by any of the BDR nodes are cleaned +needs monitoring. The LCRs that aren't required by any of the PGD nodes are cleaned periodically. The interval between two consecutive cleanups is controlled by `bdr.lcr_cleanup_interval`, which defaults to 3 minutes. The cleanup is disabled when `bdr.lcr_cleanup_interval` is zero. @@ -507,14 +507,14 @@ disabled when `bdr.lcr_cleanup_interval` is zero. When disabled, logical decoding is performed by the WAL sender process for each node subscribing to each node. In this case, no LCR files are written. -Even though the decoding worker is enabled for a BDR group, following +Even though the decoding worker is enabled for a PGD group, following GUCs control the production and use of LCR per node. By default these are `false`. For production and use of LCRs, enable the -decoding worker for the BDR group and set these GUCs to to `true` on each of the nodes in the BDR group. +decoding worker for the PGD group and set these GUCs to to `true` on each of the nodes in the PGD group. - `bdr.enable_wal_decoder` — When turned `false`, all WAL senders using LCRs restart to use WAL directly. When `true` - along with the BDR group config, a decoding worker process is + along with the PGD group config, a decoding worker process is started to produce LCR and WAL Senders use LCR. - `bdr.receive_lcr` — When `true` on the subscribing node, it requests WAL sender on the publisher node to use LCRs if available. @@ -522,7 +522,7 @@ decoding worker for the BDR group and set these GUCs to to `true` on each of the ### Notes As of now, a decoding worker decodes changes corresponding to the node where it's -running. A logical standby is sent changes from all the nodes in the BDR group +running. A logical standby is sent changes from all the nodes in the PGD group through a single source. Hence a WAL sender serving a logical standby can't use LCRs right now. @@ -553,7 +553,7 @@ defaults to 1 GB. ## Node restart and down node recovery -BDR is designed to recover from node restart or node disconnection. +PGD is designed to recover from node restart or node disconnection. The disconnected node rejoins the group by reconnecting to each peer node and then replicating any missing data from that node. @@ -598,37 +598,37 @@ predictable, you might be able to calculate how much space is used over time, allowing a prediction of the maximum time a node can be down before critical issues arise. -Don't manually remove replication slots created by BDR. If you do, the cluster +Don't manually remove replication slots created by PGD. If you do, the cluster becomes damaged and the node that was using the -slot must be parted from the cluster, as described in [Replication slots created by BDR](#replication-slots-created-by-bdr). +slot must be parted from the cluster, as described in [Replication slots created by PGD](#replication-slots-created-by-pgd). While a node is offline, the other nodes might not yet have received the same set of data from the offline node, so this might appear as a slight divergence across nodes. The parting process corrects this imbalance across nodes. (Later versions might do this earlier.) -### Replication slots created by BDR +### Replication slots created by PGD -On a BDR master node, the following replication slots are -created by BDR: +On a PGD master node, the following replication slots are +created by PGD: - One *group slot*, named `bdr__` - N-1 *node slots*, named `bdr___`, where N is the total number of BDR nodes in the cluster, + name>`, where N is the total number of PGD nodes in the cluster, including direct logical standbys, if any !!! Warning - Don't drop those slots. BDR creates and manages them and drops them when or if necessary. + Don't drop those slots. PGD creates and manages them and drops them when or if necessary. On the other hand, you can create or drop replication slots required by software like Barman or logical replication using the appropriate commands -for the software without any effect on BDR. +for the software without any effect on PGD. Don't start slot names used by other software with the prefix `bdr_`. For example, in a cluster composed of the three nodes `alpha`, `beta`, and -`gamma`, where BDR is used to replicate the `mydb` database and the -BDR group is called `mygroup`: +`gamma`, where PGD is used to replicate the `mydb` database and the +PGD group is called `mygroup`: - Node `alpha` has three slots: - One group slot named `bdr_mydb_mygroup` @@ -645,15 +645,15 @@ BDR group is called `mygroup`: #### Group replication slot -The group slot is an internal slot used by BDR primarily to track the -oldest safe position that any node in the BDR group (including all logical +The group slot is an internal slot used by PGD primarily to track the +oldest safe position that any node in the PGD group (including all logical standbys) has caught up to, for any outbound replication from this node. The group slot name is given by the function `bdr.local_group_slot_name()`. The group slot can: -- Join new nodes to the BDR group without having all existing nodes +- Join new nodes to the PGD group without having all existing nodes up and running (although the majority of nodes should be up), without incurring data loss in case the node that was down during join starts replicating again. @@ -674,14 +674,14 @@ in response to Raft progress messages from other nodes. ### Hashing long identifiers The name of a replication slot—like any other PostgreSQL -identifier—can't be longer than 63 bytes. BDR handles this by -shortening the database name, the BDR group name, and the name of the +identifier—can't be longer than 63 bytes. PGD handles this by +shortening the database name, the PGD group name, and the name of the node in case the resulting slot name is too long for that limit. Shortening an identifier is carried out by replacing the final section of the string with a hash of the string itself. For example, consider a cluster that replicates a database -named `db20xxxxxxxxxxxxxxxx` (20 bytes long) using a BDR group named +named `db20xxxxxxxxxxxxxxxx` (20 bytes long) using a PGD group named `group20xxxxxxxxxxxxx` (20 bytes long). The logical replication slot associated to node `a30xxxxxxxxxxxxxxxxxxxxxxxxxxx` (30 bytes long) is called since `3597186`, `be9cbd0`, and `7f304a2` are respectively the hashes @@ -692,9 +692,9 @@ of `db20xxxxxxxxxxxxxxxx`, `group20xxxxxxxxxxxxx`, and bdr_db20xxxx3597186_group20xbe9cbd0_a30xxxxxxxxxxxxx7f304a2 ``` -## Removing a node from a BDR group +## Removing a node from a PGD group -Since BDR is designed to recover from extended node outages, you +Since PGD is designed to recover from extended node outages, you must explicitly tell the system if you're removing a node permanently. If you permanently shut down a node and don't tell the other nodes, then performance suffers and eventually @@ -703,7 +703,7 @@ the whole system stops working. Node removal, also called *parting*, is done using the `bdr.part_node()` function. You must specify the node name (as passed during node creation) to remove a node. You can call the `bdr.part_node()` function from any active -node in the BDR group, including the node that you're removing. +node in the PGD group, including the node that you're removing. Just like the join procedure, parting is done using Raft consensus and requires a majority of nodes to be online to work. @@ -713,14 +713,14 @@ between nodes to see which node has the most recent data from the parting node. Then all remaining nodes make a secondary, temporary connection to the most-recent node to allow them to catch up any missing data. -A parted node still is known to BDR but won't consume resources. A +A parted node still is known to PGD but won't consume resources. A node might be added again under the same name as a parted node. In rare cases, you might want to clear all metadata of a parted node by using the function `bdr.drop_node()`. -### Uninstalling BDR +### Uninstalling PGD -Dropping the BDR extension removes all the BDR objects in a node, +Dropping the PGD extension removes all the PGD objects in a node, including metadata tables. You can do this with the following command: @@ -728,26 +728,26 @@ command: DROP EXTENSION bdr; ``` -If the database depends on some BDR-specific objects, then you can't drop the BDR +If the database depends on some PGD-specific objects, then you can't drop the PGD extension. Examples include: -- Tables using BDR-specific sequences such as `SnowflakeId` or `galloc` +- Tables using PGD-specific sequences such as `SnowflakeId` or `galloc` - Column using CRDT data types -- Views that depend on some BDR catalog tables +- Views that depend on some PGD catalog tables Remove those dependencies before dropping the BDR extension. For example, drop the dependent objects, alter the column -type to a non-BDR equivalent, or change the sequence type back to +type to a non-PGD equivalent, or change the sequence type back to `local`. !!! Warning You can drop the BDR extension only if the node was - successfully parted from its BDR node group or if it's the last - node in the group. Dropping BDR metadata breaks replication to and from the other nodes. + successfully parted from its PGD node group or if it's the last + node in the group. Dropping PGD metadata breaks replication to and from the other nodes. !!! Warning - When dropping a local BDR node or the BDR extension in the local - database, any preexisting session might still try to execute a BDR-specific workflow + When dropping a local PGD node or the BDR extension in the local + database, any preexisting session might still try to execute a PGD-specific workflow and therefore fail. You can solve the problem by disconnecting the session and then reconnecting the client or by restarting the instance. @@ -755,11 +755,11 @@ type to a non-BDR equivalent, or change the sequence type back to There's also a `bdr.drop_node()` function. Use this function only in emergencies, such as if there's a problem with parting. -## Listing BDR topology +## Listing PGD topology -### Listing BDR groups +### Listing PGD groups -The following simple query lists all the BDR node groups of which +The following simple query lists all the PGD node groups of which the current node is a member. It currently returns only one row. ```sql @@ -780,7 +780,7 @@ FROM bdr.local_node_summary ns JOIN bdr.node_group g USING (node_group_name); ``` -### Listing nodes in a BDR group +### Listing nodes in a PGD group You can extract the list of all nodes in a given node group (such as `mygroup`) from the `bdr.node_summary` view as shown in the following @@ -820,8 +820,8 @@ as `STANDBY`. move the node state to `ACTIVE`. These two `PROMOTE`states have to be coherent to the fact that only one node can be with a state higher than `STANDBY` but lower than `ACTIVE`. -- `PROMOTING`: Promotion from logical standby to full BDR node is in progress. -- `ACTIVE`: The node is a full BDR node and is currently `ACTIVE`. This is the +- `PROMOTING`: Promotion from logical standby to full PGD node is in progress. +- `ACTIVE`: The node is a full PGD node and is currently `ACTIVE`. This is the most common node status. - `PART_START`: Node was `ACTIVE` or `STANDBY` and we just called `bdr.part_node` to remove the node from the EDB Postgres Distributed cluster. @@ -893,7 +893,7 @@ bdr.drop_node(node_name text, cascade boolean DEFAULT false, force boolean DEFAU - `node_name` — Name of an existing node. - `cascade` — Deprecated, will be removed in the future. - `force` — Circumvents all sanity checks and forces the removal of - all metadata for the given BDR node despite a possible danger of + all metadata for the given PGD node despite a possible danger of causing inconsistencies. Only Technical Support uses a forced node drop in case of emergencies related to parting. @@ -908,7 +908,7 @@ including information about remote nodes. Or it can be the remote node, in which case only metadata for that specific node is removed. !!! Note - BDR4 can have a maximum of 1024 node records (both ACTIVE and PARTED) + PGD4 can have a maximum of 1024 node records (both ACTIVE and PARTED) at one time because each node has a unique sequence number assigned to it, for use by snowflakeid and timeshard sequences. PARTED nodes aren't automatically cleaned up. If this @@ -916,7 +916,7 @@ which case only metadata for that specific node is removed. ### bdr.create_node_group -This function creates a BDR group with the local node as the only member of the group. +This function creates a PGD group with the local node as the only member of the group. #### Synopsis @@ -929,7 +929,7 @@ bdr.create_node_group(node_group_name text, #### Parameters -- `node_group_name` — Name of the new BDR group. As with the node +- `node_group_name` — Name of the new PGD group. As with the node name, valid group names must consist of only lowercase letters, numbers, and underscores. - `parent_group_name` — The name of the parent group for the subgroup. @@ -961,7 +961,7 @@ The group creation doesn't hold any locks. ### bdr.alter_node_group_config -This function changes the configuration parameters of an existing BDR group. +This function changes the configuration parameters of an existing PGD group. Options with NULL value (default for all of them) aren't modified. #### Synopsis @@ -982,19 +982,19 @@ bdr.alter_node_group_config(node_group_name text, #### Parameters -- `node_group_name` — Name of an existing BDR group. The local node must be part +- `node_group_name` — Name of an existing PGD group. The local node must be part of the group. - `insert_to_update` — Reserved for backward compatibility. - `update_to_insert` — Reserved for backward compatibility. - - versions of BDR. Use `bdr.alter_node_set_conflict_resolver` instead. + + versions of PGD. Use `bdr.alter_node_set_conflict_resolver` instead. - `ignore_redundant_updates` — Reserved for backward compatibility. - `check_full_tuple` — Reserved for backward compatibility. - `apply_delay` — Reserved for backward compatibility. - `check_constraints` — Whether the apply process checks the constraints when writing replicated data. This option is deprecated and will be disabled or removed in future - versions of BDR. + versions of PGD. - `num_writers` — Number of parallel writers for subscription backing this node group. -1 means the default (as specified by the GUC `bdr.writers_per_subscription`) is used. Valid values @@ -1012,7 +1012,7 @@ bdr.alter_node_group_config(node_group_name text, one of the writers, if available. If parallel apply is disabled or no writer is free to handle streaming transaction, then the changes are written to a file and applied after the transaction is committed. If the - value is set to `auto`, BDR tries to intelligently pick between + value is set to `auto`, PGD tries to intelligently pick between `file` and `writer`, depending on the transaction property and available resources. You can't enable `streaming_mode` if the WAL decoder is already enabled. @@ -1046,7 +1046,7 @@ This function doesn't hold any locks. ### bdr.join_node_group -This function joins the local node to an already existing BDR group. +This function joins the local node to an already existing PGD group. #### Synopsis @@ -1063,8 +1063,8 @@ bdr.join_node_group ( #### Parameters - `join_target_dsn` — Specifies the connection string to an existing (source) node - in the BDR group you want to add the local node to. -- `node_group_name` — Optional name of the BDR group. Defaults to NULL, which + in the PGD group you want to add the local node to. +- `node_group_name` — Optional name of the PGD group. Defaults to NULL, which tries to detect the group name from information present on the source node. - `pause_in_standby` — Optionally tells the join process to join only as a @@ -1096,11 +1096,11 @@ to the local transaction if `wait_for_completion` was set to `true` or by callin Node can be part of only a single group, so you can call this function only once on each node. -Node join doesn't hold any locks in the BDR group. +Node join doesn't hold any locks in the PGD group. ### bdr.switch_node_group -This function switches the local node from its current subgroup to another subgroup within the same existing BDR node group. +This function switches the local node from its current subgroup to another subgroup within the same existing PGD node group. #### Synopsis @@ -1113,7 +1113,7 @@ bdr.switch_node_group ( #### Parameters -- `node_group_name` — Name of the BDR group or subgroup. +- `node_group_name` — Name of the PGD group or subgroup. - `wait_for_completion` — Wait for the switch process to complete before returning. Defaults to `true`. @@ -1133,16 +1133,16 @@ background and you can't roll it back. The changes are visible only to the local transaction if `wait_for_completion` was set to `true` or by calling `bdr.wait_for_join_completion` later. -The local node changes membership from its current subgroup to another subgroup within the same BDR node group without needing to part the cluster. The node's kind must match that of existing nodes within the target subgroup. +The local node changes membership from its current subgroup to another subgroup within the same PGD node group without needing to part the cluster. The node's kind must match that of existing nodes within the target subgroup. -Node switching doesn't hold any locks in the BDR group. +Node switching doesn't hold any locks in the PGD group. -Restrictions: Currently, the function only allows switching between a subgroup and its BDR node group. To effect a move between subgroups it is necessary to make two separate calls: 1) switch from subgroup to node group and, 2) switch from node group to other subgroup. +Restrictions: Currently, the function only allows switching between a subgroup and its PGD node group. To effect a move between subgroups it is necessary to make two separate calls: 1) switch from subgroup to node group and, 2) switch from node group to other subgroup. ### bdr.promote_node -This function promotes a local logical standby node to a full member of the BDR group. +This function promotes a local logical standby node to a full member of the PGD group. #### Synopsis @@ -1188,10 +1188,10 @@ state, which was set by `bdr.create_node_group`, `bdr.join_node_group`, or ### bdr.part_node -Removes (parts) the node from the BDR group but doesn't remove data +Removes (parts) the node from the PGD group but doesn't remove data from the node. -You can call the function from any active node in the BDR group, including +You can call the function from any active node in the PGD group, including the node that you're removing. However, once the node is parted, it can't part other nodes in the cluster. @@ -1225,7 +1225,7 @@ bdr.part_node ( process is stuck. !!! Warning - Using `force = true` can leave the BDR group in an inconsistent + Using `force = true` can leave the PGD group in an inconsistent state. Use it only to recover from failures in which you can't remove the node any other way. @@ -1270,7 +1270,7 @@ bdr.alter_node_interface(node_name text, interface_dsn text) #### Notes Run this function and make the changes only on the local node. This means that you normally execute it on every node in the -BDR group, including the node that is being changed. +PGD group, including the node that is being changed. This function is transactional. You can roll it back, and the changes are visible to the current transaction. @@ -1280,7 +1280,7 @@ The function holds lock on the local node. ### bdr.alter_subscription_enable This function enables either the specified subscription or all the subscriptions of the -local BDR node. This is also known as resume subscription. +local PGD node. This is also known as resume subscription. No error is thrown if the subscription is already enabled. Returns the number of subscriptions affected by this operation. @@ -1310,7 +1310,7 @@ by a background process after the transaction has committed. ### bdr.alter_subscription_disable This function disables either the specified subscription or all the -subscriptions of the local BDR node. Optionally, it can also immediately stop +subscriptions of the local PGD node. Optionally, it can also immediately stop all the workers associated with the disabled subscriptions. This is also known as pause subscription. No error is thrown if the subscription is already disabled. Returns the number of subscriptions affected by this operation. @@ -1350,9 +1350,9 @@ current work to finish. ## Node-management commands -BDR also provides a command-line utility for adding nodes to the BDR group using +PGD also provides a command-line utility for adding nodes to the PGD group using physical copy (`pg_basebackup`) of an existing node and for converting a -physical standby of an existing node to a new node in the BDR group. +physical standby of an existing node to a new node in the PGD group. ### bdr_init_physical @@ -1366,10 +1366,10 @@ If the specified data directory isn't empty, this is used as the base for the new node. If the data directory is already active as a physical standby node, you need to stop the standby before running `bdr_init_physical`, which manages Postgres. Initially it -waits for catchup and then promotes to a master node before joining the BDR +waits for catchup and then promotes to a master node before joining the PGD group. The `--standby` option, if used, turns the existing physical standby into a logical standby node. It refers to the end state -of the new BDR node, not the starting state of the specified data directory. +of the new PGD node, not the starting state of the specified data directory. This command drops all PostgreSQL-native logical replication subscriptions from the database (or disables them when the `-S` option is @@ -1418,10 +1418,10 @@ bdr_init_physical [OPTION] ... #### Notes The replication set names specified in the command don't affect the data that -exists in the data directory before the node joins the BDR group. This is true +exists in the data directory before the node joins the PGD group. This is true whether `bdr_init_physical` makes its own base backup or an existing base backup -is being promoted to a new BDR node. Thus the `--replication-sets` option -affects only the data published and subscribed to after the node joins the BDR node +is being promoted to a new PGD node. Thus the `--replication-sets` option +affects only the data published and subscribed to after the node joins the PGD node group. This behavior is different from the way replication sets are used in a logical join, as when using `bdr.join_node_group()`. @@ -1439,7 +1439,7 @@ strongly recommend that you truncate the tables rather than drop them, because: It's simpler and safer to truncate your nonreplicated tables, leaving them present but empty. - -A future version of BDR might automatically omit or remove tables that aren't + +A future version of PGD might automatically omit or remove tables that aren't part of the selected replication sets for a physical join, so your application should not rely on details of the behavior documented here. diff --git a/product_docs/docs/pgd/5/overview/index.mdx b/product_docs/docs/pgd/5/overview/index.mdx index d648a51cfb8..3e243b4f950 100644 --- a/product_docs/docs/pgd/5/overview/index.mdx +++ b/product_docs/docs/pgd/5/overview/index.mdx @@ -1,11 +1,11 @@ --- -title: "Overview" +title: "PGD overview" redirect: bdr --- -EDB Postgres Distributed (PGD) provides multi-master replication and data distribution with advanced conflict management, data-loss protection, and throughput up to 5X faster than native logical replication, and enables distributed Postgres clusters with high availability up to five 9s. +EDB Postgres Distributed (PGD) provides multi-master replication and data distribution with advanced conflict management, data-loss protection, and throughput up to 5X faster than native logical replication. It also enables distributed Postgres clusters with high availability up to five 9s. -PGD provides loosely coupled, multi-master logical replication using a mesh topology. This means that you can write to any server and the changes are sent directly, row-by-row, to all the other servers that are part of the same PGD group. +PGD provides loosely coupled, multimaster logical replication using a mesh topology. This means that you can write to any server and the changes are sent directly, row-by-row, to all the other servers that are part of the same PGD group. By default, PGD uses asynchronous replication, applying changes on the peer nodes only after the local commit. Multiple synchronous replication options are also available. @@ -13,38 +13,38 @@ By default, PGD uses asynchronous replication, applying changes on the peer node ### Multiple groups -A PGD node is a member of at least one *node group*, and in the most basic architecture there is a single node group for the whole PGD cluster. +A PGD node is a member of at least one *node group*. In the most basic architecture, there's a single node group for the whole PGD cluster. ### Multiple masters Each node (database) participating in a PGD group both receives changes from other members and can be written to directly by the user. -This is distinct from hot or warm standby, where only one master server accepts writes, and all the other nodes are standbys that replicate either from the master or from another standby. +This is distinct from hot or warm standby, where only one master server accepts writes and all the other nodes are standbys that replicate either from the master or from another standby. You don't have to write to all the masters all of the time. A frequent configuration directs writes mostly to just one master. ### Asynchronous, by default -Changes made on one PGD node aren't replicated to other nodes until they're committed locally. As a result, the data isn't exactly the same on all nodes at any given time. Some nodes have data that hasn't yet arrived at other nodes. PostgreSQL's block-based replication solutions default to asynchronous replication as well. In PGD, because there are multiple masters and, as a result, multiple data streams, data on different nodes might differ even when `synchronous_commit` and `synchronous_standby_names` are used. +Changes made on one PGD node aren't replicated to other nodes until they're committed locally. As a result, the data isn't exactly the same on all nodes at any given time. Some nodes have data that hasn't yet arrived at other nodes. PostgreSQL's block-based replication solutions default to asynchronous replication as well. In PGD, there are multiple masters and, as a result, multiple data streams. So data on different nodes might differ even when `synchronous_commit` and `synchronous_standby_names` are used. ### Mesh topology -PGD is structured around a mesh network where every node connects to every other node and all nodes exchange data directly with each other. There's no forwarding of data in PGD except in special circumstances such as adding and removing nodes. Data can arrive from outside the EDB Postgres Distributed cluster or be sent onwards using native PostgreSQL logical replication. +PGD is structured around a mesh network where every node connects to every other node, and all nodes exchange data directly with each other. There's no forwarding of data in PGD except in special circumstances, such as adding and removing nodes. Data can arrive from outside the EDB Postgres Distributed cluster or be sent onward using native PostgreSQL logical replication. ### Logical replication -Logical replication is a method of replicating data rows and their changes based on their replication identity (usually a primary key). We use the term *logical* in contrast to *physical* replication, which uses exact block addresses and byte-by-byte replication. Index changes aren't replicated, thereby avoiding write amplification and reducing bandwidth. +Logical replication is a method of replicating data rows and their changes based on their replication identity (usually a primary key). We use the term logical in contrast to physical replication, which uses exact block addresses and byte-by-byte replication. Index changes aren't replicated, thereby avoiding write amplification and reducing bandwidth. -Logical replication starts by copying a snapshot of the data from the source node. Once that is done, later commits are sent to other nodes as they occur in real time. Changes are replicated without re-executing SQL, so the exact data written is replicated quickly and accurately. +Logical replication starts by copying a snapshot of the data from the source node. Once that's done, later commits are sent to other nodes as they occur in real time. Changes are replicated without executing SQL again, so the exact data written is replicated quickly and accurately. Nodes apply data in the order in which commits were made on the source node, ensuring transactional consistency is guaranteed for the changes from any single node. Changes from different nodes are applied independently of other nodes to ensure the rapid replication of changes. -Replicated data is sent in binary form, when it's safe to do so. +Replicated data is sent in binary form when it's safe to do so. ### Connection management -[Connection management](../routing) leverages consensus-driven quorum to determine the correct connection end-point in a semi-exclusive manner to prevent unintended multi-node writes from an application. This reduces the potential for data conflicts. +[Connection management](../routing) leverages consensus-driven quorum to determine the correct connection endpoint in a semi-exclusive manner to prevent unintended multi-node writes from an application. This approach reduces the potential for data conflicts. [PGD Proxy](../routing/proxy) is the tool for application connection management provided as part of EDB Postgres Distributed. @@ -66,13 +66,13 @@ A number of different architectures can be configured, each of which has differe The group is the basic building block consisting of 2+ nodes (servers). In a group, each node is in a different availability zone, with dedicated router and backup, giving immediate switchover and high availability. Each group has a dedicated replication set defined on it. If the group loses a node, you can easily repair or replace it by copying an existing node from the group. -The Always On architectures are built from either one group in a single location or two groups in two separate locations. Each group provides high availability. When two groups are leveraged in remote locations, they together also provide disaster recovery (DR). +The Always On architectures are built from either one group in a single location or two groups in two separate locations. Each group provides high availability. When two groups are leveraged in remote locations, they together also provide disaster recovery (DR). Tables are created across both groups, so any change goes to all nodes, not just to nodes in the local group. -One node in each group is the target for the main application. All other nodes are described as shadow nodes (or "read-write replica"), waiting to take over when needed. If a node loses contact, we switch immediately to a shadow node to continue processing. If a group fails, we can switch to the other group. Scalability isn't the goal of this architecture. +One node in each group is the target for the main application. All other nodes are described as shadow nodes (or "read-write replica"), waiting to take over when needed. If a node loses contact, processsing switches immediately to a shadow node to continue processing. If a group fails, processing can switch to the other group. Scalability isn't the goal of this architecture. -Since we write mainly to only one node, the possibility of contention between is reduced to almost zero. As a result, performance impact is much reduced. +Since writes are mainly to only one node, the possibility of contention between nodes is reduced to almost zero. As a result, performance impact is much reduced. Secondary applications might execute against the shadow nodes, although these are reduced or interrupted if the main application begins using that node. @@ -82,9 +82,9 @@ In the future, one node will be elected as the main replicator to other groups, PGD is compatible with [PostgreSQL](https://www.postgresql.org/), [EDB Postgres Extended Server](https://techsupport.enterprisedb.com/customer_portal/sw/2ndqpostgres/) and [EDB Postgres Advanced Server](/epas/latest) and is deployed as a standard Postgres extension named BDR. See the [Compatibility matrix](../#compatibility-matrix) for details of supported version combinations. -Some key PGD features depend on certain core capabilities being available in the targeted Postgres database server. Therefore, PGD users must also adopt the Postgres database server distribution that's best suited to their business needs. For example, if having the PGD feature Commit At Most Once (CAMO) is mission critical to your use case, don't adopt the community PostgreSQL distribution because it doesn't have the core capability required to handle CAMO. See the full feature matrix compatibility in [Choosing a Postgres distribution](../choosing_server/). +Some key PGD features depend on certain core capabilities being available in the target Postgres database server. Therefore, PGD users must also adopt the Postgres database server distribution that's best suited to their business needs. For example, if having the PGD feature Commit At Most Once (CAMO) is mission critical to your use case, don't adopt the community PostgreSQL distribution. It doesn't have the core capability required to handle CAMO. See the full feature matrix compatibility in [Choosing a Postgres distribution](../choosing_server/). -PGD offers close to native Postgres compatibility. However, some access patterns don't necessarily work as well in multi-node setup as they do on a single instance. There are also some limitations in what can be safely replicated in multi-node setting. [Application usage](../appusage) goes into detail on how PGD behaves from an application development perspective. +PGD offers close-to-native Postgres compatibility. However, some access patterns don't necessarily work as well in multi-node setup as they do on a single instance. There are also some limitations in what you can safely replicate in a multi-node setting. [Application usage](../appusage) goes into detail about how PGD behaves from an application development perspective. ### Characteristics affecting performance @@ -92,13 +92,13 @@ By default, PGD keeps one copy of each table on each node in the group, and any Since copies of data are everywhere, SELECTs need only ever access the local node. On a read-only cluster, performance on any one node isn't affected by the number of nodes and is immune to replication conflicts on other nodes caused by long-running SELECT queries. Thus, adding nodes increases linearly the total possible SELECT throughput. -If an INSERT, UPDATE, and DELETE (DML) is performed locally, then the changes propagate to all nodes in the group. The overhead of DML apply is less than the original execution, so if you run a pure write workload on multiple nodes concurrently, a multi-node cluster can handle more TPS than a single node. +If an INSERT, UPDATE, and DELETE (DML) is performed locally, then the changes propagate to all nodes in the group. The overhead of DML apply is less than the original execution. So if you run a pure write workload on multiple nodes concurrently, a multi-node cluster can handle more TPS than a single node. -Conflict handling has a cost that acts to reduce the throughput. The throughput then depends on how much contention the application displays in practice. Applications with very low contention perform better than a single node. Applications with high contention can perform worse than a single node. These results are consistent with any multi-master technology. They aren't particular to PGD. +Conflict handling has a cost that acts to reduce the throughput. The throughput then depends on how much contention the application displays in practice. Applications with very low contention perform better than a single node. Applications with high contention can perform worse than a single node. These results are consistent with any multimaster technology and aren't particular to PGD. Synchronous replication options can send changes concurrently to multiple nodes so that the replication lag is minimized. Adding more nodes means using more CPU for replication, so peak TPS reduces slightly as each node is added. If the workload tries to use all CPU resources, then this resource constrains replication, which can then affect the replication lag. In summary, adding more master nodes to a PGD group doesn't result in significant write -throughput increase when most tables are replicated because all the writes will be replayed on all nodes. Because PGD writes are in general more effective than writes coming from Postgres clients by way of SQL, some performance increase can be achieved. Read throughput generally scales linearly with the number of nodes. +throughput increase when most tables are replicated because all the writes are replayed on all nodes. Because PGD writes are in general more effective than writes coming from Postgres clients by way of SQL, you can increase performance. Read throughput generally scales linearly with the number of nodes. diff --git a/product_docs/docs/pgd/5/repsets.mdx b/product_docs/docs/pgd/5/repsets.mdx index 9b23cac7fca..44bc808fb13 100644 --- a/product_docs/docs/pgd/5/repsets.mdx +++ b/product_docs/docs/pgd/5/repsets.mdx @@ -5,12 +5,12 @@ redirects: --- -A replication set is a group of tables that a BDR node can subscribe to. +A replication set is a group of tables that a PGD node can subscribe to. You can use replication sets to create more complex replication topologies than regular symmetric multi-master where each node is an exact copy of the other nodes. -Every BDR group creates a replication set with the same name as +Every PGD group creates a replication set with the same name as the group. This replication set is the default replication set, which is used for all user tables and DDL replication. All nodes are subscribed to it. In other words, by default all user tables are replicated between all nodes. @@ -32,11 +32,11 @@ joins the cluster and afterwards. Once the node is joined, you can still remove tables from the replication set, but you must add new tables using a resync operation. -By default, a newly defined replication set doesn't replicate DDL or BDR +By default, a newly defined replication set doesn't replicate DDL or PGD administration function calls. Use `replication_set_add_ddl_filter` to define the commands to replicate. -BDR creates replication set definitions on all nodes. Each node can then be +PGD creates replication set definitions on all nodes. Each node can then be defined to publish or subscribe to each replication set using `alter_node_replication_sets`. @@ -46,12 +46,12 @@ set. !!! Note Don't use the default replication set for selective replication. Don't drop or modify the default replication set on any of - the BDR nodes in the cluster as it is also used by default for DDL + the PGD nodes in the cluster as it is also used by default for DDL replication and administration function calls. ## Behavior of partitioned tables -BDR supports partitioned tables transparently, meaning that you can add a partitioned +PGD supports partitioned tables transparently, meaning that you can add a partitioned table to a replication set. Changes that involve any of the partitions are replicated downstream. @@ -79,7 +79,7 @@ table matches a row in the referenced table. Therefore, if the referencing table is a member of a replication set, the referenced table must also be a member of the same replication set. -The current version of BDR doesn't automatically check for or enforce +The current version of PGD doesn't automatically check for or enforce this condition. When adding a table to a replication set, the database administrator must make sure that all the tables referenced by foreign keys are also added. @@ -161,7 +161,7 @@ bdr.create_replication_set(set_name name, #### Parameters -- `set_name` — Name of the new replication set. Must be unique across the BDR +- `set_name` — Name of the new replication set. Must be unique across the PGD group. - `replicate_insert` — Indicates whether to replicate inserts into tables in this replication set. @@ -179,13 +179,13 @@ bdr.create_replication_set(set_name name, #### Notes -By default, new replication sets don't replicate DDL or BDR administration +By default, new replication sets don't replicate DDL or PGD administration function calls. See [ddl filters](repsets#ddl-replication-filtering) for how to set up DDL replication for replication sets. A preexisting DDL filter is set up for the default group replication set that replicates all DDL and admin function calls. It's created when the group is created but can be dropped -in case you don't want the BDR group default replication set to replicate -DDL or the BDR administration function calls. +in case you don't want the PGD group default replication set to replicate +DDL or the PGD administration function calls. This function uses the same replication mechanism as `DDL` statements. This means that the replication is affected by the [ddl filters](repsets#ddl-replication-filtering) @@ -313,13 +313,13 @@ since this function is designed to execute before the node joins. Be careful to specify replication set names correctly to avoid errors. This allows for calling the function not only on the node that's part of the -BDR group but also on a node that hasn't joined any group yet. This approach limits +PGD group but also on a node that hasn't joined any group yet. This approach limits the data synchronized during the join. However, the schema is always fully synchronized without regard to the replication sets setting. All tables are copied across, not just the ones specified in the replication set. You can drop unwanted tables by referring to the `bdr.tables` catalog table. These might be removed automatically in later -versions of BDR. This is currently true even if the [ddl filters](repsets#ddl-replication-filtering) +versions of PGD. This is currently true even if the [ddl filters](repsets#ddl-replication-filtering) configuration otherwise prevent replication of DDL. The replication sets that the node subscribes to after this call are published @@ -363,7 +363,7 @@ bdr.replication_set_add_table(relation regclass, #### Parameters - `relation` — Name or Oid of a table. -- `set_name` — Name of the replication set. If NULL (the default), then the BDR +- `set_name` — Name of the replication set. If NULL (the default), then the PGD group default replication set is used. - `columns` — Reserved for future use (currently does nothing and must be NULL). - `row_filter` — SQL expression to be used for filtering the replicated rows. @@ -417,7 +417,7 @@ bdr.replication_set_remove_table(relation regclass, #### Parameters - `relation` — Name or Oid of a table. -- `set_name` — Name of the replication set. If NULL (the default), then the BDR +- `set_name` — Name of the replication set. If NULL (the default), then the PGD group default replication set is used. #### Notes @@ -511,10 +511,10 @@ This shows, for example: ## DDL replication filtering -By default, the replication of all supported DDL happens by way of the default BDR +By default, the replication of all supported DDL happens by way of the default PGD group replication set. This is achieved with a DDL filter with -the same name as the BDR group. This filter is added to the default BDR -group replication set when the BDR group is created. +the same name as the PGD group. This filter is added to the default PGD +group replication set when the PGD group is created. You can adjust this by changing the DDL replication filters for all existing replication sets. These filters are independent of table @@ -539,7 +539,7 @@ replication and global locking. This function adds a DDL filter to a replication set. Any DDL that matches the given filter is replicated to any node that's -subscribed to that set. This also affects replication of BDR admin functions. +subscribed to that set. This also affects replication of PGD admin functions. This doesn't prevent execution of DDL on any node. It only alters whether DDL is replicated to other nodes. Suppose two nodes have @@ -554,9 +554,9 @@ for regular PostgreSQL commands. A typical example might be to create a filter that prevents additional index commands on a logical standby from being replicated to all other nodes. -You can filter the BDR admin functions used by using a tagname matching the +You can filter the PGD admin functions used by using a tagname matching the qualified function name. For example, `bdr.replication_set_add_table` is the -command tag for the function of the same name. In this case, this tag allows all BDR +command tag for the function of the same name. In this case, this tag allows all PGD functions to be filtered using `bdr.*`. The `role_name` is used for matching against the current role that is executing @@ -577,10 +577,10 @@ bdr.replication_set_add_ddl_filter(set_name name, #### Parameters -- `set_name` — name of the replication set; if NULL then the BDR +- `set_name` — name of the replication set; if NULL then the PGD group default replication set is used - `ddl_filter_name` — name of the DDL filter; this must be unique across the - whole BDR group + whole PGD group - `command_tag` — regular expression for matching command tags; NULL means match everything - `role_name` — regular expression for matching role name; NULL means @@ -611,7 +611,7 @@ To view the defined replication filters, use the view `bdr.ddl_replication`. #### Examples -To include only BDR admin functions, define a filter like this: +To include only PGD admin functions, define a filter like this: ```sql SELECT bdr.replication_set_add_ddl_filter('mygroup', 'mygroup_admin', $$bdr\..*$$); @@ -649,7 +649,7 @@ bdr.replication_set_remove_ddl_filter(set_name name, #### Parameters -- `set_name` — Name of the replication set. If NULL then the BDR +- `set_name` — Name of the replication set. If NULL then the PGD group default replication set is used. - `ddl_filter_name` — Name of the DDL filter to remove. diff --git a/product_docs/docs/pgd/5/routing/index.mdx b/product_docs/docs/pgd/5/routing/index.mdx index 654ee872e4c..aa22a01c29a 100644 --- a/product_docs/docs/pgd/5/routing/index.mdx +++ b/product_docs/docs/pgd/5/routing/index.mdx @@ -11,73 +11,76 @@ navigation: Managing application connections is an important part of high availability. -Especially with asynchronous replication, having consistent write lead node is -important in order to avoid conflicts and guarantee availability for the +Especially with asynchronous replication, having a consistent write lead node is +important to avoid conflicts and guarantee availability for the application. -EDB Postgres Distributed provides a proxy layer called PGD-Proxy which is -normally installed in highly available configuration (at least 2 instances per +EDB Postgres Distributed provides a proxy layer called PGD Proxy, which is +normally installed in highly available configuration (at least two instances per region). -The PGD-Proxy connects to one of the EDB Postgres Distributed nodes and monitors -routing configuration changes as decided by the EDB Postgres Distributed cluster -and ensures that the connections are routed to correct node(s) consistently. +The PGD Proxy connects to one of the EDB Postgres Distributed nodes and monitors +routing configuration changes as decided by the EDB Postgres Distributed cluster. +It ensures that the connections are routed to the correct nodes consistently. ## Configuration -The configuration of the routing is done through either SQL interfaces or through +Configuring the routing is done through either SQL interfaces or through PGD-CLI. -The SQL interfaces are described in this section. +You can enable routing decisions by calling the `bdr.alter_node_group_option()` function. +For example: -You can enable routing decisions by calling `bdr.alter_node_group_option()` function. -For example `SELECT bdr.alter_node_group_option('region1-group', 'enable_proxy_routing', 'true')`. -It can be disabled again by setting the same option to `false`. +```text +SELECT bdr.alter_node_group_option('region1-group', 'enable_proxy_routing', 'true') +``` -There are additional group-level options that affect the routing decisions: +You can disable it by setting the same option to `false`. -- route_writer_max_lag - Maximum lag in bytes of the new write candidate to be - selected as write leader, if no candidate passes this, there will be no writer +Additional group-level options affect the routing decisions: + +- `route_writer_max_lag` — Maximum lag in bytes of the new write candidate to be + selected as write leader. If no candidate passes this, no writer is selected automatically. -- route_reader_max_lag - Maximum lag in bytes for node to be considered viable - read-only node (currently reserved for future use). +- `route_reader_max_lag` — Maximum lag in bytes for a node to be considered a viable + read-only node. Currently reserved for future use. -Per node configuration of routing is set using `bdr.alter_node_option()`. The -available options that affect routing are following: +Per-node configuration of routing is set using `bdr.alter_node_option()`. The +available options that affect routing are the following: -- route_dsn - The dsn used by proxy to connect to this node. -- route_priority - Relative routing priority of the node against other nodes in +- `route_dsn` — The dsn used by proxy to connect to this node. +- `route_priority` — Relative routing priority of the node against other nodes in the same node group. -- route_fence - Whether the node is fenced from routing (can't receive connections - from PGD-Proxy) -- route_writes - Whether writes can be routed to this node, i.e. whether the node +- `route_fence` — Whether the node is fenced from routing, that is, it can't receive connections + from PGD Proxy. +- `route_writes` — Whether writes can be routed to this node, that is, whether the node can become write leader. -- route_reads - Whether read only connections can be routed to this node (currently - reserved for future use). - -The proxies are also configured using SQL interfaces. You can add proxy configuration -using `bdr.create_proxy`. For example `SELECT bdr.create_proxy('region1-proxy1', 'region1-group');` -will add default configuration for proxy named "region1-proxy1" that is member -of BDR group "region1-group". The name of the proxy given here must be same -as the name given in the proxy configuration file. Proxy configuration can be -removed using `SELECT bdr.drop_proxy('region1-proxy1')`, such proxy will be +- `route_reads` — Whether read-only connections can be routed to this node. Currently + reserved for future use. + +You can also configure The proxies using SQL interfaces. You can add proxy configuration +using `bdr.create_proxy`. For example, `SELECT bdr.create_proxy('region1-proxy1', 'region1-group');` +adds the default configuration for a proxy named `region1-proxy1` that's a member +of PGD group `region1-group`. The name of the proxy given here must be same +as the name given in the proxy configuration file. You can remove a proxy configuration +using `SELECT bdr.drop_proxy('region1-proxy1')`. The proxy is deactivated as a result. -Options for each proxy can be configured using `bdr.alter_proxy_option()` function. -The available option are: +You can configure options for each proxy using the `bdr.alter_proxy_option()` function. +The available options are: -- listen_address - Address the proxy should listen on. -- listen_port - Port the proxy should listen on. -- max_client_conn - Maximum number of connections the proxy will accept. -- max_server_conn - Maximum number of connections the proxy will make to the +- `listen_address` — Address for the proxy to listen on. +- `listen_port` — Port for the proxy to listen on. +- `max_client_conn` — Maximum number of connections for the proxy to accept. +- `max_server_conn` — Maximum number of connections the proxy can make to the Postgres node. -- server_conn_timeout - Connection timeout for server connections. -- server_conn_keepalive - Keepalive interval for server connections. +- `server_conn_timeout` — Connection timeout for server connections. +- `server_conn_keepalive` — Keepalive interval for server connections. The current configuration of every group is visible in the `bdr.node_group_routing_config_summary` view. Similarly, the -`bdr.node_routing_config_summary` view shows current per node routing -configuration and `bdr.proxy_config_summary` shows per proxy configuration. +`bdr.node_routing_config_summary` view shows current per-node routing +configuration. `bdr.proxy_config_summary` shows per-proxy configuration. -It's also possible to do a switch-over operation (changing which node is -the write leader explicitly) using `bdr.routing_leadership_transfer()` function. +You can also do a switchover operation to explicitly change the node that's +the write leader. To do so, use the `bdr.routing_leadership_transfer()` function. diff --git a/product_docs/docs/pgd/5/routing/installing_proxy.mdx b/product_docs/docs/pgd/5/routing/installing_proxy.mdx index 09e41dbc766..d9e5f28b442 100644 --- a/product_docs/docs/pgd/5/routing/installing_proxy.mdx +++ b/product_docs/docs/pgd/5/routing/installing_proxy.mdx @@ -5,11 +5,11 @@ navTitle: "Installing PGD Proxy" ## Installing PGD Proxy -There are two ways to install and configure PGD Proxy to manage Postgres Distributed cluster. The recommended way to install and configure PGD Proxy is to use the EDB Trusted Postgres Architect (TPA) utility for cluster deployment and management. +You can use two methods to install and configure PGD Proxy to manage a Postgres Distributed cluster. The recommended way to install and configure PGD Proxy is to use the EDB Trusted Postgres Architect (TPA) utility for cluster deployment and management. ### Installing through TPA -If PGD cluster is being deployed through TPA then it installs and configures PGD Proxy automatically as per recommended architecture. If you wish to install PGD Proxy on any other node in PGD cluster then, you simply need to attach the `pgd-proxy` role to that instance in TPA configuration file and set the `bdr_child_group` parameter as shown below before deploying. See [Trusted Postgres Architect](../tpa) for more information. +If the PGD cluster is being deployed through TPA, then TPA installs and configures PGD Proxy automatically as per the recommended architecture. If you want to install PGD Proxy on any other node in a PGD cluster, then you need to attach the `pgd-proxy` role to that instance in the TPA configuration file. Also set the `bdr_child_group` parameter before deploying, as this example shows. See [Trusted Postgres Architect](../tpa) for more information. ```yaml - Name: proxy-a1 @@ -26,7 +26,7 @@ If PGD cluster is being deployed through TPA then it installs and configures PGD #### Configuration -Proxy connects to the BDR database for its internal operations, like getting proxy options, getting write leader details, etc. Therefore, it needs a list of endpoints/dsn to connect to BDR nodes. Proxy expects these configurations in a local config file `pgd-proxy-config.yml`. Following is a functional example of `pgd-proxy-config.yml` file: +PGD Proxy connects to the PGD database for its internal operations, like getting proxy options and getting write leader details. Therefore, it needs a list of endpoints/dsn to connect to PGD nodes. PGD Proxy expects these configurations in a local config file `pgd-proxy-config.yml`. Following is a working example of the `pgd-proxy-config.yml` file: ```yaml log-level: debug @@ -40,26 +40,26 @@ cluster: name: "proxy-a1" ``` -By default, in the cluster created through TPA, `pgd-proxy-config.yml` is located in the `/etc/edb/pgd-proxy` directory. The PGD Proxy searches for `pgd-proxy-config.yml` in the following locations. Precedence order is high to low. +By default, in the cluster created through TPA, `pgd-proxy-config.yml` is located in the `/etc/edb/pgd-proxy` directory. PGD Proxy searches for `pgd-proxy-config.yml` in the following locations. Precedence order is high to low. 1. `/etc/edb/pgd-proxy` (default) 2. `$HOME/.edb/pgd-proxy` If you rename the file or move it to another location, specify the new name and location using the optional `-f` or `--config-file` flag when starting a service. See the [sample service file](#pgd-proxy-service). -The log level for the PGD Proxy service can be set using the top level config parameter `log-level` as shown in the sample config. The valid values for `log-level` are `debug`, `info`, `warn` and `error`. +You can set the log level for the PGD Proxy service using the top-level config parameter `log-level`, as shown in the sample config. The valid values for `log-level` are `debug`, `info`, `warn` and `error`. -The `cluster.endpoints` and `cluster.proxy.name` are mandatory fields in the config file. Proxy always tries to connect to the first endpoint in the list, if it fails it tries the next endpoint and so on. +`cluster.endpoints` and `cluster.proxy.name` are mandatory fields in the config file. PGD Proxy always tries to connect to the first endpoint in the list. If it fails, it tries the next endpoint, and so on. -Proxy uses endpoints given in the local config file only at the time of proxy startup. After that, proxy retrieves the list of actual endpoints (route_dsn) from the bdr catalog. Therefore, the node option - `route_dsn`, must be set for each bdr node. See [route_dsn](../routing#configuration) for more information. +PGD Proxy uses endpoints given in the local config file only at proxy startup. After that, PGD Proxy retrieves the list of actual endpoints (route_dsn) from the PGD Proxy catalog. Therefore, the node option `route_dsn` must be set for each PGD Proxy node. See [route_dsn](../routing#configuration) for more information. -#### Proxy user +#### PGD Proxy user -The database user specified in the endpoint doesn’t need to be a superuser. Typically, in the TPA environment, `pgdproxy` is an OS user as well as database user with the `bdr_superuser` role. +The database user specified in the endpoint doesn’t need to be a superuser. Typically, in the TPA environment, `pgdproxy` is an OS user as well as a database user with the `bdr_superuser` role. #### PGD Proxy service -PGD Proxy is preferably run as a systemd service. The `pgd-proxy` service unit file is located at `/etc/systemd/system/pgd-proxy.service` by default. Following is the sample service file created by TPA. +We recommend running PGD Proxy as a systemd service. The `pgd-proxy` service unit file is located at `/etc/systemd/system/pgd-proxy.service` by default. Following is the sample service file created by TPA: ```text [Unit] @@ -80,7 +80,7 @@ SyslogIdentifier=pgd-proxy WantedBy=multi-user.target ``` -Use the below commands to manage `pgd-proxy` service +Use these commands to manage the `pgd-proxy` service: ```sh systemctl status pgd-proxy diff --git a/product_docs/docs/pgd/5/routing/proxy.mdx b/product_docs/docs/pgd/5/routing/proxy.mdx index b1259c48226..74642ba840f 100644 --- a/product_docs/docs/pgd/5/routing/proxy.mdx +++ b/product_docs/docs/pgd/5/routing/proxy.mdx @@ -9,29 +9,36 @@ directoryDefaults: description: "The PGD Proxy is a service that acts as proxy layer between the client application and Postgres for your EDB Postgres Distributed cluster" --- -EDB Postgres Distributed Proxy is a daemon that acts as an abstraction layer between the client application and Postgres. It interfaces with the BDR consensus mechanism to obtain the identity of the current write leader node and redirects traffic to that node. +EDB Postgres Distributed Proxy is a daemon that acts as an abstraction layer between the client application and Postgres. It interfaces with the PGD consensus mechanism to get the identity of the current write leader node and redirects traffic to that node. -There is always at least one global group and one data group in the PGD cluster. BDR elects the write leader for each data group which has the `enable_proxy_routing` and `enable_raft` options set to true. Proxy can be attached to a global group or data group. There could be multiple proxies attached to each group. +The PGD cluster always has at least one global group and one data group. PGD elects the write leader for each data group that has the `enable_proxy_routing` and `enable_raft` options set to true. You can attach Proxy to a global group or data group. You can attach multiple proxies to each group. PGD Proxy is a TCP layer 4 proxy. -## How it works ? +## How it works -Upon starting, PGD Proxy connects to one of the endpoints given in the local config file and fetches DB connection information for all nodes, proxy options like listen address, listen port, routing details like current write leader, etc. Endpoints given in config file are only used at the time of startup, after that actual endpoints are taken from bdr catalog `bdr.node_routing_config_summary#route_dsn`. +Upon starting, PGD Proxy connects to one of the endpoints given in the local config file. It fetches: -The write leader election is managed by BDR itself. Proxy internally interacts with BDR to get write leader change events notifications on Postgres notify/listen channels and routes client traffic to current write leader. Proxy disconnects all client connections on write leader change. Write leader election is a Raft backed activity and is subject to Raft leader availability. +- DB connection information for all nodes +- Proxy options like listen address, listen port +- Routing details like current write leader -PGD Proxy responds to write leader change events that can be categorized into two modes of operation viz., `Failover` and `Switchover`. +Endpoints given in the config file are used only at startup. After that, actual endpoints are taken from the PGD catalog's `route_dsn` field in `bdr.node_routing_config_summary`. -Automatic transfer of write leadership from current write leader node to new node in the event of but not limited to Postgres or Operating system crash is termed as `Failover`. BDR automatically elects a new write leader when the current write leader goes down or becomes unresponsive. Once the new write leader is elected by BDR, proxy will close existing client connections (which were to the old write leader) and redirect new client connections to newly elected write leader. -User controlled, manual transfer of write leadership from the current write leader to a new target leader is termed as `Switchover`. Switchover is triggered through the [PGD CLI switchover](../cli/command_ref/pgd_switchover) command. The command is submitted to BDR which attempts to elect the given target node as new write leader. Similar to failover, proxy will close existing client connections and redirect new client connections to the newly elected write leader. This is useful at the time of server maintenance, e.g. if the current write leader node needs to be stopped for maintenance like a server update, OS patch update etc. +PGD manages write leader election. PGD Proxy interacts with PGD to get write leader change events notifications on Postgres notify/listen channels and routes client traffic to the current write leader. PGD Proxy disconnects all client connections on write leader change. Write leader election is a Raft-backed activity and is subject to Raft leader availability. + +PGD Proxy responds to write leader change events that can be categorized into two modes of operation: *failover* and *switchover*. + +Automatic transfer of write leadership from the current write leader node to a new node in the event of but not limited to Postgres or operating system crash is called failover. PGD elects a new write leader when the current write leader goes down or becomes unresponsive. Once the new write leader is elected by PGD, proxy closes existing client connections to the old write leader and redirects new client connections to the newly elected write leader. + +User-controlled, manual transfer of write leadership from the current write leader to a new target leader is called switchover. Switchover is triggered through the [PGD CLI switchover](../cli/command_ref/pgd_switchover) command. The command is submitted to PGD, which attempts to elect the given target node as the new write leader. Similar to failover, PGD Proxy closes existing client connections and redirects new client connections to the newly elected write leader. This is useful during server maintenance, for example, if the current write leader node needs to be stopped for maintenance like a server update or OS patch update. ## Managing PGD Proxy -PGD CLI provides a few commands to manage proxies in PGD cluster such as `create-proxy`, `delete-proxy`, `set-proxy-options` and `show-proxies`. See [PGD CLI](../cli/command_ref) for more information. +PGD CLI provides a few commands to manage proxies in a PGD cluster, such as `create-proxy`, `delete-proxy`, `set-proxy-options`, and `show-proxies`. See [PGD CLI](../cli/command_ref) for more information. -See [Connection management](../routing) for more information on BDR side of configuration and management of PGD Proxy. +See [Connection management](../routing) for more information on the PGD side of configuration and management of PGD Proxy. ## Proxy log location @@ -40,7 +47,7 @@ See [Connection management](../routing) for more information on BDR side of conf - Debian based - `/var/log/syslog` - Red Hat based - `/var/log/messages` -Use `journalctl` command to filter and view logs for troubleshooting Proxy. Below are few sample commands for quick reference. +Use the `journalctl` command to filter and view logs for troubleshooting Proxy. The following are few sample commands for quick reference: ```sh journalctl -u pgd-proxy -n100 -f diff --git a/product_docs/docs/pgd/5/scaling.mdx b/product_docs/docs/pgd/5/scaling.mdx index 27675e72108..57e7b2c823d 100644 --- a/product_docs/docs/pgd/5/scaling.mdx +++ b/product_docs/docs/pgd/5/scaling.mdx @@ -5,14 +5,14 @@ redirects: --- AutoPartition allows tables to grow easily to large sizes by automatic -partitioning management. This capability uses features of BDR +partitioning management. This capability uses features of PGD such as low-conflict locking of creating and dropping partitions. You can create new partitions regularly and then drop them when the data retention period expires. -BDR management is primarily accomplished by functions that can be called by SQL. -All functions in BDR are exposed in the `bdr` schema. Unless you put it into +PGD management is primarily accomplished by functions that can be called by SQL. +All functions in PGD are exposed in the `bdr` schema. Unless you put it into your search_path, you need to schema-qualify the name of each function. ## Auto creation of partitions @@ -205,7 +205,7 @@ bdr.drop_autopartition(relation regclass); ### Drop one AutoPartition -Use `bdr.autopartition_drop_partition` once a BDR AutoPartition table has been +Use `bdr.autopartition_drop_partition` once a PGD AutoPartition table has been made, as this function can specify single partitions to drop. If the partitioned table was successfully dropped, the function returns `true`. @@ -234,7 +234,7 @@ value is created. The function only waits for the partitions to be created locally. It doesn't guarantee that the partitions also exists on the remote nodes. -To wait for the partition to be created on all BDR nodes, use the +To wait for the partition to be created on all PGD nodes, use the `bdr.autopartition_wait_for_partitions_on_all_nodes()` function. This function internally checks local as well as all remote nodes and waits until the partition is created everywhere. diff --git a/product_docs/docs/pgd/5/security.mdx b/product_docs/docs/pgd/5/security.mdx index fb505cfcf4d..803cc0fbe06 100644 --- a/product_docs/docs/pgd/5/security.mdx +++ b/product_docs/docs/pgd/5/security.mdx @@ -7,20 +7,20 @@ redirects: Only superusers can create the BDR extension. However, if you want, you can set up the `pgextwlist` extension and configure it to allow a non-superuser to create a BDR extension. -Configuring and managing BDR doesn't require superuser access, nor is that recommended. -The privileges required by BDR are split across the following default/predefined roles, named +Configuring and managing PGD doesn't require superuser access, nor is that recommended. +The privileges required by PGD are split across the following default/predefined roles, named similarly to the PostgreSQL default/predefined roles: -- bdr_superuser — The highest-privileged role, having access to all BDR tables and functions. -- bdr_read_all_stats — The role having read-only access to the tables, views, and functions, sufficient to understand the state of BDR. +- bdr_superuser — The highest-privileged role, having access to all PGD tables and functions. +- bdr_read_all_stats — The role having read-only access to the tables, views, and functions, sufficient to understand the state of PGD. - bdr_monitor — At the moment, the same as `bdr_read_all_stats`. To be extended later. -- bdr_application — The minimal privileges required by applications running BDR. +- bdr_application — The minimal privileges required by applications running PGD. - bdr_read_all_conflicts — Can view all conflicts in `bdr.conflict_history`. -These BDR roles are created when the BDR extension is -installed. See [BDR default roles](#bdr-defaultpredefined-roles) for more details. +These PGD roles are created when the BDR extension is +installed. See [PGD default roles](#pgd-defaultpredefined-roles) for more details. -Managing BDR doesn't require that administrators have access to user data. +Managing PGD doesn't require that administrators have access to user data. Arrangements for securing conflicts are discussed in [Logging conflicts to a table](consistency/conflicts). @@ -29,28 +29,28 @@ You can monitor conflicts using the `BDR.conflict_history_summary` view. ## Catalog tables -System catalog and Information Schema tables are always excluded from replication by BDR. +System catalog and Information Schema tables are always excluded from replication by PGD. In addition, tables owned by extensions are excluded from replication. -## BDR functions and operators +## PGD functions and operators -All BDR functions are exposed in the `bdr` schema. Any calls to these +All PGD functions are exposed in the `bdr` schema. Any calls to these functions must be schema qualified, rather than putting `bdr` in the search_path. -All BDR operators are available by way of the `pg_catalog` schema to allow users +All PGD operators are available by way of the `pg_catalog` schema to allow users to exclude the `public` schema from the search_path without problems. ## Granting privileges on catalog objects Administrators must not grant explicit privileges on catalog objects such as tables, views, and functions. Manage access to those objects -by granting one of the roles described in [BDR default roles](#bdr-defaultpredefined-roles). +by granting one of the roles described in [PGD default roles](#pgd-defaultpredefined-roles). This requirement is a consequence of the flexibility that allows joining a node group even if the nodes on either side of the join don't -have the exact same version of BDR (and therefore of the BDR +have the exact same version of PGD (and therefore of the PGD catalog). More precisely, if privileges on individual catalog objects were @@ -62,15 +62,15 @@ node being joined might not apply to the node that is joining. Users are global objects in a PostgreSQL instance. `CREATE USER` and `CREATE ROLE` commands are replicated automatically if they -are executed in the database where BDR is running and the +are executed in the database where PGD is running and the `bdr.role_replication` is turned on. However, if these commands are executed in other databases in the same PostgreSQL instance, then they aren't replicated, -even if those users have rights on the BDR database. +even if those users have rights on the PGD database. -When a new BDR node joins the BDR group, existing users aren't automatically +When a new PGD node joins the PGD group, existing users aren't automatically copied unless the node is added using `bdr_init_physical`. This is intentional and is an important security feature. PostgreSQL allows users to access multiple -databases, with the default being to access any database. BDR doesn't know +databases, with the default being to access any database. PGD doesn't know which users access which database and so can't safely decide which users to copy across to the new node. @@ -107,7 +107,7 @@ replicating all rows. We recommend but don't enforce that the row security policies on all nodes be identical or at least compatible. -The user bdr_superuser controls replication for BDR and can +The user bdr_superuser controls replication for PGD and can add or remove any table from any replication set. bdr_superuser doesn't need any privileges over individual tables, nor is this recommended. If you need to restrict access @@ -117,12 +117,12 @@ and granted to the appropriate users. ## Connection role -When allocating a new BDR node, the user supplied in the DSN for the +When allocating a new PGD node, the user supplied in the DSN for the `local_dsn` argument of `bdr.create_node` and the `join_target_dsn` of `bdr.join_node_group` are used frequently to refer to, create, and manage database objects. -BDR is carefully written to prevent privilege escalation attacks even +PGD is carefully written to prevent privilege escalation attacks even when using a role with `SUPERUSER` rights in these DSNs. To further reduce the attack surface, you can specify a more restricted user @@ -144,7 +144,7 @@ just the following to still allow DML and DDL replication: ## Privilege restrictions -BDR enforces additional restrictions, effectively preventing the +PGD enforces additional restrictions, effectively preventing the use of DDL that relies solely on TRIGGER or REFERENCES privileges. `GRANT ALL` still grants both TRIGGER and REFERENCES privileges, @@ -158,7 +158,7 @@ SELECT privilege on the referenced table or if the referenced table has RLS restrictions enabled that the current user can't bypass. Thus, the REFERENCES privilege isn't sufficient to allow creating -a foreign key with BDR. Relying solely on the REFERENCES privilege +a foreign key with PGD. Relying solely on the REFERENCES privilege isn't typically useful since it makes the validation check execute using triggers rather than a table scan. It is typically too expensive to use successfully. @@ -167,11 +167,11 @@ to use successfully. In PostgreSQL, both the owner of a table and anyone who was granted the TRIGGER privilege can create triggers. Triggers granted by the non-table owner -execute as the table owner in BDR, which might cause a security issue. +execute as the table owner in PGD, which might cause a security issue. The TRIGGER privilege is seldom used and PostgreSQL Core Team has said "The separate TRIGGER permission is something we consider obsolescent." -BDR mitigates this problem by using stricter rules on who can create a trigger +PGD mitigates this problem by using stricter rules on who can create a trigger on a table: - superuser @@ -188,7 +188,7 @@ on a table: - Users who have TRIGGER privilege on the table can create triggers using functions that are defined with the SECURITY DEFINER clause if they have EXECUTE privilege on them. This clause makes the function always execute in the context - of the owner of the function both in standard PostgreSQL and BDR. + of the owner of the function both in standard PostgreSQL and PGD. This logic is built on the fact that, in PostgreSQL, the owner of the trigger isn't the user who created it but the owner of the function used by that trigger. @@ -197,30 +197,30 @@ The same rules apply to existing tables, and if the existing table has triggers aren't owned by the owner of the table and don't use SECURITY DEFINER functions, you can't add it to a replication set. -These checks were added with BDR 3.6.19. An application that +These checks were added with PGD 3.6.19. An application that relies on the behavior of previous versions can set `bdr.backwards_compatibility` to 30618 (or lower) to behave like earlier versions. -BDR replication apply uses the system-level default search_path only. +PGD replication apply uses the system-level default search_path only. Replica triggers, stream triggers, and index expression functions might assume other search_path settings which then fail when they execute on apply. To ensure this doesn't occur, resolve object references clearly using either the default search_path only (always use fully qualified references to objects, e.g., schema.objectname), or set the search path for a function using `ALTER FUNCTION ... SET search_path = ...` for the functions affected. -## BDR default/predefined roles +## PGD default/predefined roles -BDR predefined roles are created when the BDR extension is installed. +PGD predefined roles are created when the BDR extension is installed. After BDR extension is dropped from a database, the roles continue to exist -and need to be dropped manually if required. This allows BDR to be used in multiple +and need to be dropped manually if required. This allows PGD to be used in multiple databases on the same PostgreSQL instance without problem. -The `GRANT ROLE` DDL statement doesn't participate in BDR replication. +The `GRANT ROLE` DDL statement doesn't participate in PGD replication. Thus, execute this on each node of a cluster. ### bdr_superuser - + - ALL PRIVILEGES ON ALL TABLES IN SCHEMA BDR - ALL PRIVILEGES ON ALL ROUTINES IN SCHEMA BDR @@ -311,7 +311,7 @@ These additional rules are described with each specific function. ### bdr_read_all_conflicts -BDR logs conflicts into the `bdr.conflict_history` table. Conflicts are +PGD logs conflicts into the `bdr.conflict_history` table. Conflicts are visible to table owners only, so no extra privileges are required to read the conflict history. If it's useful to have a user that can see conflicts for all tables, you can optionally grant the role @@ -319,11 +319,11 @@ bdr_read_all_conflicts to that user. ## Verification -BDR was verified using the following tools and approaches. +PGD was verified using the following tools and approaches. ### Coverity -Coverity Scan was used to verify the BDR stack providing coverage +Coverity Scan was used to verify the PGD stack providing coverage against vulnerabilities using the following rules and coding standards: - MISRA C @@ -336,7 +336,7 @@ against vulnerabilities using the following rules and coding standards: ### CIS Benchmark -CIS PostgreSQL Benchmark v1, 19 Dec 2019 was used to verify the BDR stack. +CIS PostgreSQL Benchmark v1, 19 Dec 2019 was used to verify the PGD stack. Using the `cis_policy.yml` configuration available as an option with Trusted Postgres Architect gives the following results for the Scored tests: diff --git a/product_docs/docs/pgd/5/sequences.mdx b/product_docs/docs/pgd/5/sequences.mdx index 6c6f3b67c97..9041852abd5 100644 --- a/product_docs/docs/pgd/5/sequences.mdx +++ b/product_docs/docs/pgd/5/sequences.mdx @@ -18,23 +18,23 @@ produce values that are unique only on the local node. This is important because unique ids generated by such sequences cause conflict and data loss (by means of discarded `INSERT` actions) in multi-master replication. -## BDR global sequences +## PGD global sequences -For this reason, BDR provides an application-transparent way to generate unique -ids using sequences on bigint or bigserial datatypes across the whole BDR group, +For this reason, PGD provides an application-transparent way to generate unique +ids using sequences on bigint or bigserial datatypes across the whole PGD group, called *global sequences*. -BDR global sequences provide an easy way for applications to use the +PGD global sequences provide an easy way for applications to use the database to generate unique synthetic keys in an asynchronous distributed system that works for most—but not necessarily all—cases. -Using BDR global sequences allows you to avoid the problems with insert +Using PGD global sequences allows you to avoid the problems with insert conflicts. If you define a `PRIMARY KEY` or `UNIQUE` constraint on a column that's using a global sequence, no node can ever get -the same value as any other node. When BDR synchronizes inserts between the +the same value as any other node. When PGD synchronizes inserts between the nodes, they can never conflict. -BDR global sequences extend PostgreSQL sequences, so they are crash-safe. To use +PGD global sequences extend PostgreSQL sequences, so they are crash-safe. To use them, you must be granted the `bdr_application` role. There are various possible algorithms for global sequences: @@ -56,10 +56,10 @@ either BIGINT or INTEGER sequences. You can create a global sequence using the `bdr.alter_sequence_set_kind()` function. This function takes a standard PostgreSQL sequence and marks it as -a BDR global sequence. It can also convert the sequence back to the standard +a PGD global sequence. It can also convert the sequence back to the standard PostgreSQL sequence. -BDR also provides the configuration variable `bdr.default_sequence_kind`, which +PGD also provides the configuration variable `bdr.default_sequence_kind`, which determines the kind of sequence to create when the `CREATE SEQUENCE` command is executed or when a `serial`, `bigserial`, or `GENERATED BY DEFAULT AS IDENTITY` column is created. Valid settings are: @@ -98,7 +98,7 @@ SnowflakeId sequences generate unique ids in a different way from standard sequences. The algorithm uses three components for a sequence number. The first component of the sequence is a timestamp at the time of sequence number generation. The second component of -the sequence number is the unique id assigned to each BDR node, +the sequence number is the unique id assigned to each PGD node, which ensures that the ids from different nodes are always different. The third component is the number generated by the local sequence. @@ -202,7 +202,7 @@ values aren't useful as range partition keys. The main downside of the `galloc` sequences is that once the assigned range is used up, the sequence generator has to ask for consensus about the next range for the local node that requires inter-node communication. This could -lead to delays or operational issues if the majority of the BDR group isn't +lead to delays or operational issues if the majority of the PGD group isn't accessible. This might be avoided in later releases. The `CACHE`, `START`, `MINVALUE`, and `MAXVALUE` options work correctly @@ -212,12 +212,12 @@ correctly. However, you can't assign an increment value that's equal to or more than the above ranges assigned for each sequence datatype. `setval()` doesn't reset the global state for `galloc` sequences; don't use it. -A few limitations apply to `galloc` sequences. BDR tracks `galloc` sequences in a -special BDR catalog [bdr.sequence_alloc](catalogs#bdrsequence_alloc). This +A few limitations apply to `galloc` sequences. PGD tracks `galloc` sequences in a +special PGD catalog [bdr.sequence_alloc](catalogs#bdrsequence_alloc). This catalog is required to track the currently allocated chunks for the `galloc` sequences. The sequence name and namespace is stored in this catalog. Since the sequence chunk allocation is managed by Raft, whereas any changes to the -sequence name/namespace is managed by the replication stream, BDR currently doesn't +sequence name/namespace is managed by the replication stream, PGD currently doesn't support renaming `galloc` sequences or moving them to another namespace or renaming the namespace that contains a `galloc` sequence. Be mindful of this limitation while designing application schema. @@ -288,7 +288,7 @@ However, attempting the same operation on a third node fails with an When the sequence kind is altered to `galloc`, it's rewritten and restarts from the defined start value of the local sequence. If this happens on an existing sequence in a production database, you need to query the current value and -then set the start value appropriately. To assist with this use case, BDR +then set the start value appropriately. To assist with this use case, PGD allows users to pass a starting value with the function `bdr.alter_sequence_set_kind()`. If you're already using offset and you have writes from multiple nodes, you need to check what is the greatest used value and restart the sequence at least @@ -373,21 +373,21 @@ the new reserved chunk and starts to consume the old reserved chunk. ## UUIDs, KSUUIDs, and other approaches There are other ways to generate globally unique ids without using the global -sequences that can be used with BDR. For example: +sequences that can be used with PGD. For example: -- UUIDs and their BDR variant, KSUUIDs +- UUIDs and their PGD variant, KSUUIDs - Local sequences with a different offset per node (i.e., manual) - An externally coordinated natural key -BDR applications can't use other methods safely: +PGD applications can't use other methods safely: counter-table-based approaches relying on `SELECT ... FOR UPDATE`, `UPDATE ... RETURNING ...` -or similar for sequence generation doesn't work correctly in BDR because BDR +or similar for sequence generation doesn't work correctly in PGD because PGD doesn't take row locks between nodes. The same values are generated on more than one node. For the same reason, the usual strategies for "gapless" -sequence generation don't work with BDR. In most cases, the application +sequence generation don't work with PGD. In most cases, the application coordinates generation of sequences that must be gapless from some external source using two-phase commit. Or it generates them only on one node in -the BDR group. +the PGD group. ### UUIDs and KSUUIDs @@ -408,7 +408,7 @@ the network. They consume more space not only as a primary key but also where referenced in foreign keys and when transmitted on the wire. Also, not all applications cope well with `UUID` keys. -BDR provides functions for working with a K-Sortable variant of `UUID` data, +PGD provides functions for working with a K-Sortable variant of `UUID` data, known as KSUUID, which generates values that can be stored using the PostgreSQL standard `UUID` data type. A `KSUUID` value is similar to `UUIDv1` in that it stores both timestamp and random data, following the `UUID` standard. @@ -423,7 +423,7 @@ generated, so there are no security concerns from using them. `KSUUID` v2 is now recommended in all cases. You can directly sort values generated with regular comparison operators. -There are two versions of `KSUUID` in BDR: v1 and v2. +There are two versions of `KSUUID` in PGD: v1 and v2. The legacy `KSUUID` v1 is deprecated but is kept in order to support existing installations. Don't use it for new installations. @@ -442,7 +442,7 @@ must specify a maximum number of nodes when establishing the schema, and it requires per-node configuration. Mistakes can easily lead to overlapping sequences. -It's relatively simple to configure this approach with BDR by creating the +It's relatively simple to configure this approach with PGD by creating the desired sequence on one node, like this: ``` @@ -477,7 +477,7 @@ even if you use offsets of 10000 or more. It would take hundreds of years, with hundreds of machines, doing millions of inserts per second, to have any chance of approaching exhaustion. -BDR doesn't currently offer any automation for configuration of the +PGD doesn't currently offer any automation for configuration of the per-node offsets on such step/offset sequences. #### Composite keys @@ -492,8 +492,8 @@ value in each node. ## Global sequence management interfaces -BDR provides an interface for converting between a standard PostgreSQL sequence -and the BDR global sequence. +PGD provides an interface for converting between a standard PostgreSQL sequence +and the PGD global sequence. The following functions are considered to be `DDL`, so DDL replication and global locking applies to them. @@ -504,7 +504,7 @@ Allows the owner of a sequence to set the kind of a sequence. Once set, `seqkind` is visible only by way of the `bdr.sequences` view. In all other ways, the sequence appears as a normal sequence. -BDR treats this function as `DDL`, so DDL replication and global locking applies, +PGD treats this function as `DDL`, so DDL replication and global locking applies, if it's currently active. See [DDL Replication](ddl). #### Synopsis @@ -517,7 +517,7 @@ bdr.alter_sequence_set_kind(seqoid regclass, seqkind text) - `seqoid` — Name or Oid of the sequence to alter. - `seqkind` — `local` for a standard PostgreSQL sequence, `snowflakeid` or - `galloc` for globally unique BDR sequences, or `timeshard` for legacy + `galloc` for globally unique PGD sequences, or `timeshard` for legacy globally unique sequence. #### Notes diff --git a/product_docs/docs/pgd/5/striggers.mdx b/product_docs/docs/pgd/5/striggers.mdx index ee9c27a5f5c..e811faee938 100644 --- a/product_docs/docs/pgd/5/striggers.mdx +++ b/product_docs/docs/pgd/5/striggers.mdx @@ -5,7 +5,7 @@ redirects: --- -BDR introduces new types of triggers that you can use for additional +PGD introduces new types of triggers that you can use for additional data processing on the downstream/target node. - Conflict triggers @@ -22,7 +22,7 @@ normal PostgreSQL triggers. A trigger function is a program defined in this form: `CREATE FUNCTION ... RETURNS TRIGGER`. Creating the trigger doesn't require use of the `CREATE TRIGGER` command. Instead, create stream triggers -using the special BDR functions +using the special PGD functions `bdr.create_conflict_trigger()` and `bdr.create_transform_trigger()`. Once created, the trigger is visible in the catalog table `pg_trigger`. @@ -42,7 +42,7 @@ option for them to execute on the origin node. However, you might want to consid the use of `row_filter` expressions on the origin. Also, any DML that is applied while executing a stream -trigger isn't replicated to other BDR nodes and doesn't +trigger isn't replicated to other PGD nodes and doesn't trigger the execution of standard local triggers. This is intentional. You can use it, for example, to log changes or conflicts captured by a stream trigger into a table that is crash-safe and specific of that @@ -144,7 +144,7 @@ We use these row-types: ## Conflict triggers -Conflict triggers execute when a conflict is detected by BDR. +Conflict triggers execute when a conflict is detected by PGD. They decide what happens when the conflict has occurred. - If the trigger function returns a row, the action is applied to the target. @@ -168,7 +168,7 @@ trigger isn't possible. It is the responsibility of the author of the conflict t ensure that the trigger gives exactly the same result for all related events. Otherwise, data divergence occurs. Technical Support recommends that you formally test all conflict triggers using the isolationtester tool supplied with -BDR. +PGD. !!! Warning - You can specify multiple conflict triggers on a single table, but @@ -182,7 +182,7 @@ If the same conflict trigger matches more than one event, you can use the `TG_OP variable in the trigger to identify the operation that produced the conflict. -By default, BDR detects conflicts by observing a change of replication origin +By default, PGD detects conflicts by observing a change of replication origin for a row. Hence, you can call a conflict trigger even when only one change is occurring. Since, in this case, there's no real conflict, this conflict detection mechanism can generate @@ -226,7 +226,7 @@ for every row on the data stream against the specific table. The behavior of return values and the exposed variables is similar, but transform triggers execute before a target row is identified, so there is no `TARGET` row. -You can specify multiple transform triggers on each table in BDR. +You can specify multiple transform triggers on each table in PGD. Transform triggers execute in alphabetical order. A transform trigger can filter away rows, and it can do additional operations @@ -265,7 +265,7 @@ important differences: Both conflict triggers and transform triggers have access to information about rows and metadata by way of the predefined variables provided by the trigger API and -additional information functions provided by BDR. +additional information functions provided by PGD. In PL/pgSQL, you can use the predefined variables that follow. @@ -494,7 +494,7 @@ Similar to normal PostgreSQL triggers, the `bdr.create_conflict_trigger` function requires `TRIGGER` privilege on the `relation` and `EXECUTE` privilege on the function. This applies with a `bdr.backwards_compatibility` of 30619 or above. Additional -security rules apply in BDR to all triggers including conflict +security rules apply in PGD to all triggers including conflict triggers. See [Security and roles](security#triggers). ### bdr.create_transform_trigger @@ -536,7 +536,7 @@ transaction. Similarly to normal PostgreSQL triggers, the `bdr.create_transform_trigger` function requires the `TRIGGER` privilege on the `relation` and `EXECUTE` -privilege on the function. Additional security rules apply in BDR to all +privilege on the function. Additional security rules apply in PGD to all triggers including transform triggers. See [Security and roles](security#triggers). diff --git a/product_docs/docs/pgd/5/terminology.mdx b/product_docs/docs/pgd/5/terminology.mdx index c568e92c73f..673f01a1c8b 100644 --- a/product_docs/docs/pgd/5/terminology.mdx +++ b/product_docs/docs/pgd/5/terminology.mdx @@ -24,13 +24,13 @@ An approach for high availability in which multiple redundant systems are manage Enables scaling out a database by breaking up data into chunks called *shards* and distributing them across separate nodes. -#### Eager Replication for BDR +#### Eager Replication for PGD Conflict-free replication with all cluster members; technically, this is synchronous logical replication using two phase-commit (2PC). #### Eventual consistency -A distributed computing consistency model stating changes to the same item in different cluster members will converge to the same value. With BDR this is achieved through asynchronous logical replication with conflict resolution and conflict-free replicated data types. +A distributed computing consistency model stating changes to the same item in different cluster members will converge to the same value. With PGD this is achieved through asynchronous logical replication with conflict resolution and conflict-free replicated data types. #### Failover diff --git a/product_docs/docs/pgd/5/transaction-streaming.mdx b/product_docs/docs/pgd/5/transaction-streaming.mdx index 64ae9a3fb5b..3839d4438f5 100644 --- a/product_docs/docs/pgd/5/transaction-streaming.mdx +++ b/product_docs/docs/pgd/5/transaction-streaming.mdx @@ -20,7 +20,7 @@ the transaction commits (or discard them if the transaction aborts). This makes it possible to apply transactions on subscribers as soon as the transaction commits. -## BDR enhancements +## PGD enhancements PostgreSQL's built-in transaction streaming has the following limitations: @@ -30,7 +30,7 @@ limitations: - If the transaction aborts, the work (changes received by each subscriber and the associated storage I/O) is wasted. -However, starting with version 3.7, BDR supports parallel apply, enabling multiple writer +However, starting with version 3.7, PGD supports parallel apply, enabling multiple writer processes on each subscriber. This capability is leveraged to provide the following enhancements: - Decoded transactions can be streamed directly to a writer on the subscriber. @@ -118,7 +118,7 @@ either a writer or a file. The decision is based on several factors: (writer 0 is always reserved for non-streamed transactions.) - If parallel apply is on but all writers are already busy handling streamed transactions, then the new transaction is streamed to a file. See - [bdr.writers](../monitoring#monitoring-bdr-writers) to check BDR + [bdr.writers](../monitoring#monitoring-bdr-writers) to check PGD writer status. If streaming to a writer is possible (that is, a free writer is available), then the diff --git a/product_docs/docs/pgd/5/tssnapshots.mdx b/product_docs/docs/pgd/5/tssnapshots.mdx index 3cd0053217e..1d30db7f4f1 100644 --- a/product_docs/docs/pgd/5/tssnapshots.mdx +++ b/product_docs/docs/pgd/5/tssnapshots.mdx @@ -7,7 +7,7 @@ redirects: The timestamp-based snapshots allow reading data in a consistent manner by using a user-specified timestamp rather than the usual MVCC snapshot. You can use this -to access data on different BDR nodes at a common point in time. For +to access data on different PGD nodes at a common point in time. For example, you can use this as a way to compare data on multiple nodes for data-quality checking. This feature doesn't currently work with write transactions. @@ -26,14 +26,14 @@ SET snapshot_timestamp = '2018-12-08 02:28:30 GMT'; SELECT count(*) FROM customers; ``` -Without BDR, this works only with future timestamps or the +Without PGD, this works only with future timestamps or the special 'current' value, so you can't use it for historical queries. -BDR works with and improves on that feature in a multi-node environment. First, -BDR makes sure that all connections to other nodes replicate any +PGD works with and improves on that feature in a multi-node environment. First, +PGD makes sure that all connections to other nodes replicate any outstanding data that was added to the database before the specified timestamp. This ensures that the timestamp-based snapshot is consistent across the whole -multi-master group. Second, BDR adds a parameter called +multi-master group. Second, PGD adds a parameter called `bdr.timestamp_snapshot_keep`. This specifies a window of time when you can execute queries against the recent history on that node. @@ -52,7 +52,7 @@ snapshot is the time of last restart of the PostgreSQL instance. You can combine the use of `bdr.timestamp_snapshot_keep` with the `postgres_fdw` extension to get a consistent read across multiple nodes in a -BDR group. You can use this to run parallel queries across nodes, when used with foreign tables. +PGD group. You can use this to run parallel queries across nodes, when used with foreign tables. There are no limits on the number of nodes in a multi-node query when using this feature. diff --git a/product_docs/docs/pgd/5/twophase.mdx b/product_docs/docs/pgd/5/twophase.mdx index bc2ac005a56..fdb153f131b 100644 --- a/product_docs/docs/pgd/5/twophase.mdx +++ b/product_docs/docs/pgd/5/twophase.mdx @@ -6,7 +6,7 @@ redirects: --- -An application can explicitly opt to use two-phase commit with BDR. See +An application can explicitly opt to use two-phase commit with PGD. See [Distributed Transaction Processing: The XA Specification](http://pubs.opengroup.org/onlinepubs/009680699/toc.pdf). The X/Open Distributed Transaction Processing (DTP) model envisions three @@ -20,14 +20,14 @@ software components: to transactions, monitors their progress, and takes responsibility for transaction completion and for failure recovery -BDR supports explicit external 2PC using the `PREPARE TRANSACTION` and +PGD supports explicit external 2PC using the `PREPARE TRANSACTION` and `COMMIT PREPARED`/`ROLLBACK PREPARED` commands. Externally, a EDB Postgres Distributed cluster appears to be a single resource manager to the transaction manager for a single session. When `bdr.commit_scope` is `local`, the transaction is prepared only on the local node. Once committed, changes are replicated, and -BDR then applies post-commit conflict resolution. +PGD then applies post-commit conflict resolution. Using `bdr.commit_scope` set to `local` might not seem to make sense with explicit two-phase commit, but the option is offered to allow you diff --git a/product_docs/docs/pgd/5/upgrades/app-upgrades.mdx b/product_docs/docs/pgd/5/upgrades/app-upgrades.mdx index f964fdbd73f..fce570cfe8c 100644 --- a/product_docs/docs/pgd/5/upgrades/app-upgrades.mdx +++ b/product_docs/docs/pgd/5/upgrades/app-upgrades.mdx @@ -20,13 +20,13 @@ By default, DDL will automatically be sent to all nodes. This can be controlled manually, as described in [DDL Replication](../ddl/), which could be used to create differences between database schemas across nodes. -BDR is designed to allow replication to continue even while minor +PGD is designed to allow replication to continue even while minor differences exist between nodes. These features are designed to allow application schema migration without downtime, or to allow logical standby nodes for reporting or testing. !!! Warning - Rolling Application Schema Upgrades have to be managed outside of BDR. + Rolling Application Schema Upgrades have to be managed outside of PGD. Careful scripting is required to make this work correctly on production clusters. Extensive testing is advised. diff --git a/product_docs/docs/pgd/5/upgrades/bdr_pg_upgrade.mdx b/product_docs/docs/pgd/5/upgrades/bdr_pg_upgrade.mdx index b75915c667f..f284d16e4ec 100644 --- a/product_docs/docs/pgd/5/upgrades/bdr_pg_upgrade.mdx +++ b/product_docs/docs/pgd/5/upgrades/bdr_pg_upgrade.mdx @@ -2,11 +2,11 @@ title: In-place Postgres Major Version Upgrades --- -Upgrading a BDR Node to a newer major version of Postgres is possible using the +Upgrading a PGD Node to a newer major version of Postgres is possible using the command-line utility `bdr_pg_upgrade`. `bdr_pg_upgrade` internally uses the standard [`pg_upgrade`](https://www.postgresql.org/docs/current/pgupgrade.html) -with BDR specific logic to ensure a smooth upgrade. +with PGD specific logic to ensure a smooth upgrade. ## Terminology @@ -23,7 +23,7 @@ that all the requirements for [`pg_upgrade`](https://www.postgresql.org/docs/cur must be met by both clusters. Additionaly, `bdr_pg_upgrade` should not be used if there are other tools using -replication slots and replication origins, only BDR slots and origins will be +replication slots and replication origins, only PGD slots and origins will be restored after the upgrade. There are several prerequisites for `bdr_pg_upgrade` that have to be met: @@ -32,10 +32,10 @@ There are several prerequisites for `bdr_pg_upgrade` that have to be met: be redirected to another node in the cluster - Peer authentication is configured for both clusters, `bdr_pg_upgrade` requires peer authentication -- BDR versions on both clusters must be exactly the same and must be version +- PGD versions on both clusters must be exactly the same and must be version 4.1.0 or above - The new cluster must be in a shutdown state -- BDR packages must be installed in the new cluster +- PGD packages must be installed in the new cluster - The new cluster must be already initialized and configured as needed to match the old cluster configuration - Databases, tables, and other objects must not exist in the new cluster @@ -68,7 +68,7 @@ can be passed to `bdr_pg_upgrade`: - `-B, --new-bindir`- new cluster bin directory (required) - `-d, --old-datadir` - old cluster data directory (required) - `-D, --new-datadir` - `REQUIRED` new cluster data directory (required) -- `--database` - BDR database name (required) +- `--database` - PGD database name (required) - `-p, --old-port` - old cluster port number - `-s, --socketdir` - directory to use for postmaster sockets during upgrade - `--check`- only perform checks, do not modify clusters @@ -116,13 +116,13 @@ Steps performed when running `bdr_pg_upgrade`. When `--check` is supplied as an argument to `bdr_pg_upgrade`, the CLI will `skip` steps that modify the database. -#### BDR Postgres Checks +#### PGD Postgres Checks | Steps | `--check` supplied | | :-----------------------------------------------|:------------------:| | Collecting pre-upgrade new cluster control data | `run` | | Checking new cluster state is shutdown | `run` | -| Checking BDR versions | `run` | +| Checking PGD versions | `run` | | Starting old cluster (if shutdown) | `skip` | | Connecting to old cluster | `skip` | | Checking if bdr schema exists | `skip` | @@ -132,7 +132,7 @@ Steps performed when running `bdr_pg_upgrade`. | Waiting for all slots to be flushed | `skip` | | Disconnecting from old cluster | `skip` | | Stopping old cluster | `skip` | -| Starting old cluster with BDR disabled | `skip` | +| Starting old cluster with PGD disabled | `skip` | | Connecting to old cluster | `skip` | | Collecting replication origins | `skip` | | Collecting replication slots | `skip` | @@ -146,14 +146,14 @@ Standard `pg_upgrade` steps are performed !!! Note `--check` is passed to pg_upgrade if supplied -#### BDR Post-Upgrade Steps +#### PGD Post-Upgrade Steps | Steps | `--check` supplied | | :-----------------------------------------------|:------------------:| | Collecting old cluster control data | `skip` | | Collecting new cluster control data | `skip` | | Advancing LSN of new cluster | `skip` | -| Starting new cluster with BDR disabled | `skip` | +| Starting new cluster with PGD disabled | `skip` | | Connecting to new cluster | `skip` | | Creating replication origin Repeated for each origin | `skip` | | Advancing replication origin Repeated for each origin | `skip` | diff --git a/product_docs/docs/pgd/5/upgrades/index.mdx b/product_docs/docs/pgd/5/upgrades/index.mdx index 39bc40a6d75..c4347a5c69b 100644 --- a/product_docs/docs/pgd/5/upgrades/index.mdx +++ b/product_docs/docs/pgd/5/upgrades/index.mdx @@ -35,7 +35,7 @@ Both of these approaches can be done in a rolling manner. ### Rolling Upgrade considerations While the cluster is going through a rolling upgrade, mixed versions of software -are running in the cluster. For example, nodeA has BDR 3.7.16, while +are running in the cluster. For example, nodeA has PGD 3.7.16, while nodeB and nodeC has 4.1.0. In this state, the replication and group management uses the protocol and features from the oldest version (3.7.16 in case of this example), so any new features provided by the newer version @@ -43,12 +43,12 @@ which require changes in the protocol are disabled. Once all nodes are upgraded to the same version, the new features are automatically enabled. Similarly, when a cluster with WAL decoder enabled nodes is going through a -rolling upgrade, WAL decoder on a higher version of BDR node produces LCRs -with a higher pglogical version and WAL decoder on a lower version of BDR node +rolling upgrade, WAL decoder on a higher version of PGD node produces LCRs +with a higher pglogical version and WAL decoder on a lower version of PGD node produces LCRs with lower pglogical version. As a result, WAL senders on a higher -version of BDR nodes are not expected to use LCRs due to a mismatch in protocol -versions while on a lower version of BDR nodes, WAL senders may continue to use -LCRs. Once all the BDR nodes are on the same BDR version, WAL senders use +version of PGD nodes are not expected to use LCRs due to a mismatch in protocol +versions while on a lower version of PGD nodes, WAL senders may continue to use +LCRs. Once all the PGD nodes are on the same PGD version, WAL senders use LCRs. A rolling upgrade starts with a cluster with all nodes at a prior release, @@ -102,7 +102,7 @@ new DDL syntax that may have been added to a newer release of Postgres. `bdr_init_physical` makes a byte-by-byte of the source node so it cannot be used while upgrading from one major Postgres version to another. In fact, currently `bdr_init_physical` requires that even the - BDR version of the source and the joining node is exactly the same. + PGD version of the source and the joining node is exactly the same. It cannot be used for rolling upgrades via joining a new node method. Instead, a logical join must be used. ### Upgrading a CAMO-Enabled Cluster @@ -115,7 +115,7 @@ using the new [Commit Scope](../durability/commit-scopes) based settings. Each major release of the software contains several changes that may affect compatibility with previous releases. These may affect the Postgres -configuration, deployment scripts, as well as applications using BDR. We +configuration, deployment scripts, as well as applications using PGD. We recommend to consider and possibly adjust in advance of the upgrade. Please see individual changes mentioned in [release notes](../rel_notes/) and any version @@ -124,7 +124,7 @@ specific upgrade notes in this topic. ## Server Software Upgrade The upgrade of EDB Postgres Distributed on individual nodes happens in-place. -There is no need for backup and restore when upgrading the BDR extension. +There is no need for backup and restore when upgrading the PGD extension. ### BDR Extension Upgrade @@ -176,8 +176,8 @@ which can be used to do a [In-place Postgres Major Version Upgrades](bdr_pg_upgr ## Upgrade Check and Validation -After this procedure, your BDR node is upgraded. You can verify the current -version of BDR4 binary like this: +After this procedure, your PGD node is upgraded. You can verify the current +version of PGD4 binary like this: ```sql SELECT bdr.bdr_version(); diff --git a/product_docs/docs/pgd/5/upgrades/upgrade_paths.mdx b/product_docs/docs/pgd/5/upgrades/upgrade_paths.mdx index dd4faba6461..bbc86f64892 100644 --- a/product_docs/docs/pgd/5/upgrades/upgrade_paths.mdx +++ b/product_docs/docs/pgd/5/upgrades/upgrade_paths.mdx @@ -1,12 +1,12 @@ --- -title: Supported BDR upgrade paths +title: Supported PGD upgrade paths --- ## Upgrading from version 4 to version 5 Upgrades from PGD 4 to PGD 5 are supported from version 4.3.0, for older versions, please upgrade to 4.3.0 before upgrading to 5. See [Upgrading within 4](/pgd/4/upgrades/upgrade_paths/#upgrading-within-version-4) in the 4 documentation for more information. After upgrading to 4.3.0 or later the following combinations are allowed. -| 4.3.0 | Target BDR version | +| 4.3.0 | Target PGD version | |-------|--------------------| | X | 5.0.0 | @@ -16,7 +16,7 @@ Upgrades from PGD 4 to PGD 5 are supported from version 4.3.0, for older version Upgrades from PGD 3.7 to PGD 5 are supported from version 3.7.20, please upgrade to 3.7.20 before upgrading to 5. See [Upgrading within from 3.7](/pgd/3.7/bdr/upgrades/supported_paths/#upgrading-within-version-37) in the 3.7 documentation for more information. After upgrading to 3.7.20 or later the following combinations are allowed -| 3.7.20 | Target BDR version | +| 3.7.20 | Target PGD version | |--------|--------------------| | X | 5.0.0 |