Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pLZYt-0007Uo-QG for pgsql-hackers@arkaria.postgresql.org; Sat, 28 Jan 2023 00:59:19 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.92) (envelope-from ) id 1pLZYr-0004sQ-Dq for pgsql-hackers@arkaria.postgresql.org; Sat, 28 Jan 2023 00:59:17 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1pLZYr-0004sE-1G for pgsql-hackers@lists.postgresql.org; Sat, 28 Jan 2023 00:59:17 +0000 Received: from mail-pl1-x62c.google.com ([2607:f8b0:4864:20::62c]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1pLZYo-00047Q-DG for pgsql-hackers@postgresql.org; Sat, 28 Jan 2023 00:59:15 +0000 Received: by mail-pl1-x62c.google.com with SMTP id d9so6609864pll.9 for ; Fri, 27 Jan 2023 16:59:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=a7JohQhj8MHwSid4WlV/O3hAGlEpapkUt1RW+7l5TCw=; b=dvQORNRBnDiH2ck5ysuPMF/uGNsm2tz4VHcmtyMxji0Hwij1tay8IiwqHVcTNB54NH qden10/UBIOvmWB91wA2ALkg5Ewqn8b6Kvc3kfI5DlPrmQs/QqsPQZBa2zRVfx8KM/hN m29abEL/EwmoAx+z0i1HqRnqEnGDZPQ7BmumqgSMXu+2FaVds8c4yd9+UmdHnsrVji3o p9LAlf2JrjIj+NMYl8mdGpy8Uw6YTco6jgS8/TAAjmaU6cd4tszIj7VUPnP6vCdZCXtE ervPKqK9yxevOeEwmvFecVjzJhRC+2JVbEBcazvZzxWKWAzVpwSSKmNAl+vqS4FIQ/8P qSqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=a7JohQhj8MHwSid4WlV/O3hAGlEpapkUt1RW+7l5TCw=; b=JcHjAvBaL4cPXMxVbahS23+1pT3afeE3/XRc7DXU/+nwWWcZISZ16s3EkRrOatQojL 8rhjeaCeqUGHBk+dM5ibhCx13dl9WQQAfIdmsv34FiQm81blUuPSGzYeZ4mPwEZPZKO+ PiPNZ/sCUPQBrpHmgABdYiOMGK1Q7CV5VLgypyk7qjTv2LuNHFjggMlcIPpV9N7P3dAF 0iLJpQ53kVXJ2noOLswmoNrmFxgQ5WaI/sl/CtCblTN4O95giRDOCqhKIaLE5kFj2UNX MPs1Di2jVD3QYlEoocwKzDqmJyS4PH8yEhKZKGWsAWDINShmum6KMsewfZoKkQ6iawbb t3yw== X-Gm-Message-State: AO0yUKWDO8NMPwetD/jcFqwQ2ykC/J6a0Tx10e3Uwo7q1mIo33VQrQbx c3MFPbldqkcWXPG+GIgGobE= X-Google-Smtp-Source: AK7set+f0v6g+KW981gfVU9+qna5qNg8OdsLvWf2NoPYbiF1/jK5C33qAnE4rCg+H/Qc6mjfUCP4AQ== X-Received: by 2002:a17:902:d491:b0:196:2e10:ba5c with SMTP id c17-20020a170902d49100b001962e10ba5cmr269098plg.49.1674867553296; Fri, 27 Jan 2023 16:59:13 -0800 (PST) Received: from nathanxps13 ([50.47.162.83]) by smtp.gmail.com with ESMTPSA id z1-20020a1709028f8100b001888cadf8f6sm3449289plo.49.2023.01.27.16.59.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 27 Jan 2023 16:59:12 -0800 (PST) Date: Fri, 27 Jan 2023 16:59:10 -0800 From: Nathan Bossart To: Andres Freund Cc: Michael Paquier , pgsql-hackers@postgresql.org Subject: Re: recovery modules Message-ID: <20230128005910.GA2245287@nathanxps13> References: <20230116224040.GB2714038@nathanxps13> <20230117182356.GA3015764@nathanxps13> <20230118044427.GA3369836@nathanxps13> <20230123214428.GA572995@nathanxps13> <20230128002319.362oxrxf7ardfz2a@awork3.anarazel.de> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20230128002319.362oxrxf7ardfz2a@awork3.anarazel.de> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Fri, Jan 27, 2023 at 04:23:19PM -0800, Andres Freund wrote: >> +typedef bool (*RecoveryRestoreCB) (const char *file, const char *path, >> + const char *lastRestartPointFileName); >> +typedef void (*RecoveryArchiveCleanupCB) (const char *lastRestartPointFileName); >> +typedef void (*RecoveryEndCB) (const char *lastRestartPointFileName); >> +typedef void (*RecoveryShutdownCB) (void); > > I think the signature of these forces bad coding practices, because there's no > way to have state within a recovery module (as there's no parameter for it). > > It's possible we would eventually support multiple modules, e.g. restoring > from shorter term file based archiving and from longer term archiving in some > blob store. Then we'll regret not having a varible for this. Are you suggesting that we add a "void *arg" to each one of these? Or put the arguments into a struct? Or something else? >> +extern RecoveryModuleCallbacks RecoveryContext; > > I think that'll typically be interpreteted as a MemoryContext by readers. How about RecoveryCallbacks? > Also, why is this a global var? Exported too? It's needed in xlog.c, xlogarchive.c, and xlogrecovery.c. Would you rather it be static to xlogarchive.c and provide accessors for the others? >> +/* >> + * Type of the shared library symbol _PG_recovery_module_init that is looked up >> + * when loading a recovery library. >> + */ >> +typedef void (*RecoveryModuleInit) (RecoveryModuleCallbacks *cb); > > I think this is a bad way to return callbacks. This way the > RecoveryModuleCallbacks needs to be modifiable, which makes the job for the > compiler harder (and isn't the greatest for security). > > I strongly encourage you to follow the model used e.g. by tableam. The init > function should return a pointer to a *constant* struct. Which is compile-time > initialized with the function pointers. > > See the bottom of heapam_handler.c for how that ends up looking. Hm. I used the existing strategy for archive modules and logical decoding output plugins here. I think it would be weird for the archive module and recovery module interfaces to look so different, but if that's okay, I can change it. >> +void >> +LoadRecoveryCallbacks(void) >> +{ >> + RecoveryModuleInit init; >> + >> + /* >> + * If the shell command is enabled, use our special initialization >> + * function. Otherwise, load the library and call its >> + * _PG_recovery_module_init(). >> + */ >> + if (restoreLibrary[0] == '\0') >> + init = shell_restore_init; >> + else >> + init = (RecoveryModuleInit) >> + load_external_function(restoreLibrary, "_PG_recovery_module_init", >> + false, NULL); > > Why a special rule for shell, instead of just defaulting the GUC to it? I'm not following this one. The default value of the restore_library GUC is an empty string, which means that the shell commands should be used. >> + /* >> + * If using shell commands, remove callbacks for any commands that are not >> + * set. >> + */ >> + if (restoreLibrary[0] == '\0') >> + { >> + if (recoveryRestoreCommand[0] == '\0') >> + RecoveryContext.restore_cb = NULL; >> + if (archiveCleanupCommand[0] == '\0') >> + RecoveryContext.archive_cleanup_cb = NULL; >> + if (recoveryEndCommand[0] == '\0') >> + RecoveryContext.recovery_end_cb = NULL; > > I'd just mandate that these are implemented and that the module has to handle > if it doesn't need to do anything. Wouldn't this just force module authors to write empty functions for the parts they don't need? -- Nathan Bossart Amazon Web Services: https://aws.amazon.com