github-actions[bot] commented on code in PR #67770:
URL: https://github.com/apache/doris/pull/67770#discussion_r4018143612


##########
fe/fe-core/src/main/java/org/apache/doris/backup/BackupHandler.java:
##########
@@ -237,6 +245,10 @@ public void alterRepository(String repoName, Map<String, 
String> newProps)
             if (oldRepo == null) {
                 throw new DdlException("Repository does not exist");
             }
+            if (oldRepo.getUnavailableReason() != null) {

Review Comment:
   [P2] Allow ALTER to repair descriptor-present unavailable repositories
   
   `gsonPostProcess()` deliberately keeps `fileSystemDescriptor` when binding 
its old properties fails, but this unconditional check returns before 
`mergeProperties()` can apply the user's correction. A persisted S3/Azure 
repository whose endpoint, credentials, or other formerly accepted property 
becomes invalid after an upgrade is therefore impossible to repair with the 
supported `ALTER REPOSITORY`; reconstructing the same replacement below would 
validate the merged properties safely. Please reject only descriptor-null 
legacy/corrupt records here, and cover a load-time bind failure followed by a 
successful corrective ALTER.



##########
fe/fe-core/src/main/java/org/apache/doris/backup/Repository.java:
##########
@@ -251,36 +271,98 @@ public void gsonPostProcess() {
             LOG.info("Repository '{}': migrating legacy 'fs' field to 
'fs_descriptor'", name);
             Map<String, String> props = legacyFs.properties != null ? 
legacyFs.properties : new HashMap<>();
             String fsName = legacyFs.name != null ? legacyFs.name : "";
+            // Both binds run plugin code (bindPrimary probes every loaded 
provider) at image load and
+            // edit-log replay: LinkageError included, so a half-installed 
plugin costs this
+            // repository, not the FE - the same catch CatalogFactory uses for 
catalogs.
             try {
                 StorageAdapter storageAdapter = StorageAdapter.of(props);
                 fileSystemDescriptor = 
FileSystemDescriptor.fromStorageAdapter(storageAdapter, "");
-            } catch (RuntimeException e) {
-                LOG.warn("Repository '{}': primary storage migration failed 
({}), trying broker fallback",
-                        name, e.getMessage());
+            } catch (RuntimeException | LinkageError e) {
+                // A typed legacy record names its storage type ("S3", "HDFS", 
"AZURE", ...); a broker
+                // record names its broker. The descriptor carries an explicit 
type and is persisted by
+                // the next checkpoint, so a wrong guess here is permanent: a 
typed record must never
+                // become BROKER because its plugin merely failed to load. 
When the name is a shipped
+                // provider's and that provider is not loaded, its absence 
explains why nothing claims
+                // the properties, whatever brokers are registered (a broker 
may legally be called
+                // HDFS). Only a name that is not an absent provider's and is 
a registered broker's is
+                // read as a broker record. Anything else is kept as it was, 
so the migration is
+                // retried at the next start, and every use reports the reason 
until then.
+                if (StorageRegistry.Provider.byName(fsName).isPresent() && 
!StorageAdapter.hasProvider(fsName)) {

Review Comment:
   [P1] Do not convert provider failures into broker repositories
   
   This condition only protects an *absent* typed provider. If a loaded 
HDFS/S3/etc. provider throws `LinkageError` (or another bind failure) inside 
`StorageAdapter.of()`, `hasProvider(fsName)` is true; when a legal broker has 
the same name, the next condition is also false and this typed legacy record is 
persisted as BROKER. The added tests cover the same-name collision and a 
throwing provider separately, but their conjunction takes this path and the 
next checkpoint loses the original type permanently. Please distinguish a clean 
'no provider claimed the properties' result from provider execution/binding 
failure, and leave the legacy record untouched on the latter.



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/lineage/LineageEventProcessor.java:
##########
@@ -218,8 +220,12 @@ pluginRoots, getClass().getClassLoader(),
                     plugins.add(plugin);
                     LOG.info("Loaded lineage plugin: {}, pluginPath={}", 
pluginName, props.get("plugin.path"));
                 }
-            } catch (Exception e) {
+            } catch (Exception | LinkageError e) {
+                // create() and initialize() are the first calls into the 
plugin implementation (the
+                // factory only named it): a dependency it lacks arrives here 
as NoClassDefFoundError,
+                // which must cost this plugin alone, not FE startup. Its 
classloader goes with it.
                 LOG.warn("Failed to create/initialize lineage plugin: {}", 
pluginName, e);
+                runtimeManager.discard(pluginName);

Review Comment:
   [P2] Roll back every published lineage-plugin state on init failure
   
   At this point the external factory was already inserted into `factories` and 
registered in `PluginRegistry`, while `discard()` only removes the runtime 
handle and closes its URLClassLoader. The factory therefore still strongly 
retains that loader, `information_schema.extensions` still advertises a plugin 
whose create/initialize failed, and if `create()` returned an instance before 
`initialize()` threw, that instance is never closed. The new test throws 
directly from `create()` and only checks `hasActivePlugins()`, so it misses 
these leaks. Please make admission transactional (or remove the 
factory/registry row and close any created instance here) and test an 
initialize-time failure.



##########
fe/fe-core/src/main/java/org/apache/doris/fs/FileSystemDescriptor.java:
##########
@@ -80,7 +80,13 @@ public StorageBackend.StorageType getThriftStorageType() {
      * by BE to initialize its storage client for snapshot/upload/download 
tasks.
      */
     public Map<String, String> getBackendConfigProperties() {
-        return StorageAdapter.of(properties).getBackendConfigProperties();
+        // A BROKER descriptor carries the raw WITH BROKER properties, which 
routing does not claim
+        // (ofBroker documents that it bypasses routing): bind it the way it 
was bound, or the first
+        // BACKUP on a broker repository throws here out of the job loop.
+        StorageAdapter adapter = storageType == FsStorageType.BROKER
+                ? StorageAdapter.ofBroker(name, properties)

Review Comment:
   [P2] Contain broker-provider failure before task construction
   
   Persisted BROKER descriptors skip binding in `Repository.gsonPostProcess()`, 
so if the BROKER filesystem plugin is missing or fails binding after restart, 
`unavailableReason` remains null. A journaled backup in `UPLOAD_SNAPSHOT` can 
then rebind this repository, pass `getBrokerAddress()` because the broker 
daemon still exists, and throw here from `StorageAdapter.ofBroker()` while 
constructing its upload task (restore has the same path). The outer daemon 
catch only logs, leaving the job state/status unchanged and retrying until 
timeout. Please validate/mark broker descriptors unavailable at load, or 
convert this bind failure into the job's normal repository `Status`, and cover 
resumed upload/download with an unavailable BROKER provider.



##########
fe/fe-core/src/main/java/org/apache/doris/backup/Repository.java:
##########
@@ -251,36 +271,98 @@ public void gsonPostProcess() {
             LOG.info("Repository '{}': migrating legacy 'fs' field to 
'fs_descriptor'", name);
             Map<String, String> props = legacyFs.properties != null ? 
legacyFs.properties : new HashMap<>();
             String fsName = legacyFs.name != null ? legacyFs.name : "";
+            // Both binds run plugin code (bindPrimary probes every loaded 
provider) at image load and
+            // edit-log replay: LinkageError included, so a half-installed 
plugin costs this
+            // repository, not the FE - the same catch CatalogFactory uses for 
catalogs.
             try {
                 StorageAdapter storageAdapter = StorageAdapter.of(props);
                 fileSystemDescriptor = 
FileSystemDescriptor.fromStorageAdapter(storageAdapter, "");
-            } catch (RuntimeException e) {
-                LOG.warn("Repository '{}': primary storage migration failed 
({}), trying broker fallback",
-                        name, e.getMessage());
+            } catch (RuntimeException | LinkageError e) {
+                // A typed legacy record names its storage type ("S3", "HDFS", 
"AZURE", ...); a broker
+                // record names its broker. The descriptor carries an explicit 
type and is persisted by
+                // the next checkpoint, so a wrong guess here is permanent: a 
typed record must never
+                // become BROKER because its plugin merely failed to load. 
When the name is a shipped
+                // provider's and that provider is not loaded, its absence 
explains why nothing claims
+                // the properties, whatever brokers are registered (a broker 
may legally be called
+                // HDFS). Only a name that is not an absent provider's and is 
a registered broker's is
+                // read as a broker record. Anything else is kept as it was, 
so the migration is
+                // retried at the next start, and every use reports the reason 
until then.
+                if (StorageRegistry.Provider.byName(fsName).isPresent() && 
!StorageAdapter.hasProvider(fsName)) {
+                    unavailableReason = "legacy record of storage type '" + 
fsName + "' was not migrated:"
+                            + " its filesystem provider is not loaded (" + 
e.getMessage() + ")";
+                } else if (!isRegisteredBroker(fsName)) {

Review Comment:
   [P2] Recover this legacy broker repository after ADD BROKER
   
   If the legacy broker name is absent during image load, this branch leaves 
the descriptor null and sets `unavailableReason`. A later live or replayed `ADD 
BROKER` only updates `BrokerMgr`; `ping()`, I/O, and ALTER all return early on 
that retained reason, so the otherwise valid repository stays unusable until 
another FE restart. Descriptor-backed broker repositories already resolve 
BrokerMgr dynamically per I/O. Please retry this specifically classified legacy 
migration when the broker becomes registered (or notify repositories from 
broker ADD), clear the transient failure, and test absent-at-load followed by 
ADD without restart.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to