From 55a07ce2479e1b4c74dec15ce4e78e3fdf50a27c Mon Sep 17 00:00:00 2001
From: mrossign <mrossign@localhost>
Date: Wed, 16 Sep 2009 08:34:51 +0000
Subject: [PATCH] Fix for #4098 Initializing a fractional domain through import-ldif when server is down does not work
---
opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java | 302 +++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 263 insertions(+), 39 deletions(-)
diff --git a/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java b/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java
index 9afb119..1f43a02 100644
--- a/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java
+++ b/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java
@@ -27,6 +27,7 @@
package org.opends.server.replication.plugin;
import java.util.ArrayList;
+import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -34,24 +35,31 @@
import org.opends.messages.Message;
import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.server.ServerManagementContext;
import org.opends.server.admin.std.server.FractionalLDIFImportPluginCfg;
import org.opends.server.admin.std.server.PluginCfg;
+import org.opends.server.admin.std.server.ReplicationDomainCfg;
+import org.opends.server.admin.std.server.ReplicationSynchronizationProviderCfg;
+import org.opends.server.admin.std.server.RootCfg;
import org.opends.server.api.plugin.*;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.replication.plugin.LDAPReplicationDomain.
AttributeValueStringIterator;
+import org.opends.server.replication.plugin.LDAPReplicationDomain.
+ FractionalConfig;
import org.opends.server.types.*;
import static org.opends.messages.ReplicationMessages.*;
/**
* This class implements a Directory Server plugin that is used in fractional
- * replication when an online full update occurs.
+ * replication to initialize a just configured fractional domain (when an online
+ * full update occurs or offline/online ldif import).
* The following tasks are done:
- * - check that the fractional configuration (if any) stored in the root entry
- * of the domain is compliant with the fractional configuration of the domain
- * (if not make online update stop)
+ * - check that the fractional configuration (if any) stored in the (incoming)
+ * root entry of the domain is compliant with the fractional configuration of
+ * the domain (if not make online update stop)
* - perform filtering according to fractional configuration of the domain
* - flush the fractional configuration of the domain in the root entry
* (if no one already present)
@@ -60,6 +68,57 @@
extends DirectoryServerPlugin<FractionalLDIFImportPluginCfg>
implements ConfigurationChangeListener<FractionalLDIFImportPluginCfg>
{
+ // Holds the fractional configuration and if available the replication domain
+ // matching this import session (they form the importfractional context).
+ // Domain is available if the server is online (import-ldif, online full
+ // update..) otherwise, this is an import-ldif with server off. The key is the
+ // ImportConfig object of the session which acts as a cookie for the whole
+ // session. This allows to potentially run man imports at the same time.
+ private final Hashtable<LDIFImportConfig, ImportFractionalContext>
+ importSessionContexts = new Hashtable<LDIFImportConfig,
+ ImportFractionalContext>();
+
+ /**
+ * Holds an import session fractional context.
+ */
+ private static class ImportFractionalContext
+ {
+ // Fractional configuration of the local domain (may be null if import on a
+ // not replicated domain)
+ private FractionalConfig fractionalConfig = null;
+ // The local domain object (may stay null if server is offline)
+ private LDAPReplicationDomain domain = null;
+
+ /**
+ * Constructor.
+ * @param fractionalConfig
+ * @param domain
+ */
+ public ImportFractionalContext(FractionalConfig fractionalConfig,
+ LDAPReplicationDomain domain)
+ {
+ this.fractionalConfig = fractionalConfig;
+ this.domain = domain;
+ }
+
+ /**
+ * Getter for the fractional configuration.
+ * @return the fractionalConfig
+ */
+ public FractionalConfig getFractionalConfig()
+ {
+ return fractionalConfig;
+ }
+
+ /**
+ * Getter for the domain..
+ * @return the domain
+ */
+ public LDAPReplicationDomain getDomain()
+ {
+ return domain;
+ }
+ }
/**
* Creates a new instance of this Directory Server plugin. Every plugin must
@@ -86,6 +145,7 @@
switch (t)
{
case LDIF_IMPORT:
+ case LDIF_IMPORT_END:
// This is acceptable.
break;
@@ -104,9 +164,81 @@
@Override()
public final void finalizePlugin()
{
+ // Nothing to do
}
/**
+ * Attempts to retrieve the fractional configuration of the domain being
+ * imported.
+ * @param entry An imported entry of the imported domain
+ * @return The parsed fractional configuration for the domain matching the
+ * passed entry. Null if no configuration is found for the domain
+ * (not a replicated domain).
+ */
+ private static FractionalConfig getStaticReplicationDomainFractionalConfig(
+ Entry entry) throws Exception {
+
+ // Retrieve the configuration
+ ServerManagementContext context = ServerManagementContext.getInstance();
+ RootCfg root = context.getRootConfiguration();
+
+
+ ReplicationSynchronizationProviderCfg sync =
+ (ReplicationSynchronizationProviderCfg)
+ root.getSynchronizationProvider("Multimaster Synchronization");
+
+ String[] domainNames = sync.listReplicationDomains();
+ if (domainNames == null)
+ {
+ // No domain in replication
+ return null;
+ }
+
+ // Find the configuration for domain the entry is part of
+ ReplicationDomainCfg matchingReplicatedDomainCfg = null;
+ for (String domainName : domainNames)
+ {
+ // Get the domain configuration object
+ ReplicationDomainCfg replicationDomainCfg =
+ sync.getReplicationDomain(domainName);
+ // Is the entry a sub entry of the replicated domain main entry ?
+ DN replicatedDn = replicationDomainCfg.getBaseDN();
+ DN entryDn = entry.getDN();
+ if (entryDn.isDescendantOf(replicatedDn))
+ {
+ // Found the matching replicated domain configuration object
+ matchingReplicatedDomainCfg = replicationDomainCfg;
+ break;
+ }
+ }
+
+ if (matchingReplicatedDomainCfg == null)
+ {
+ // No matching replicated domain found
+ return null;
+ }
+
+ // Extract the fractional configuration from the domain configuration object
+ // and return it.
+ return FractionalConfig.toFractionalConfig(matchingReplicatedDomainCfg);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override()
+ public final void doLDIFImportEnd(
+ LDIFImportConfig importConfig)
+ {
+ // Remove the cookie of this import session
+ synchronized(importSessionContexts)
+ {
+ importSessionContexts.remove(importConfig);
+ }
+ }
+
+ /**
+ * See class comment for what we achieve here...
* {@inheritDoc}
*/
@Override()
@@ -114,24 +246,93 @@
LDIFImportConfig importConfig, Entry entry)
{
/**
- * See class comment for what we achieve here...
+ * try to get the import fractional context for this entry. If not found,
+ * create and initialize it. The mechanism here is done to take a lock only
+ * once for the whole import session (except the necessary lock of the
+ * doLDIFImportEnd method)
*/
+ ImportFractionalContext importFractionalContext =
+ importSessionContexts.get(importConfig);
- // Retrieve the replicated domain this entry belongs to
DN entryDn = entry.getDN();
- LDAPReplicationDomain domain = MultimasterReplication.findDomain(entryDn,
- null);
- if (domain == null)
+ FractionalConfig localFractionalConfig = null;
+
+ // If no context, create it
+ if (importFractionalContext == null)
+ {
+ synchronized(importSessionContexts)
+ {
+ // Insure antoher thread was not creating the context at the same time
+ // (we would create it for the second time which is useless)
+ importFractionalContext = importSessionContexts.get(importConfig);
+ if (importFractionalContext == null)
+ {
+ /*
+ * Create context
+ */
+
+ /**
+ * Retrieve the replicated domain this entry belongs to. Try to
+ * retrieve replication domain instance first. If we are in an online
+ * server, we should get it (if we are treating an entry that belongs
+ * to a replicated domain), otherwise the domain is not replicated or
+ * we are in an offline server context (import-ldif command run with
+ * offline server) and we must retrieve the fractional configuration
+ * directly from the configuration management system.
+ */
+ LDAPReplicationDomain domain =
+ MultimasterReplication.findDomain(entryDn, null);
+
+ // Get the fractional configuration extracted from the local server
+ // configuration for the currently imported domain
+ if (domain == null)
+ {
+ // Server may be offline, attempt to find fractional configuration
+ // from config sub-system
+ try
+ {
+ localFractionalConfig =
+ getStaticReplicationDomainFractionalConfig(entry);
+ } catch (Exception ex)
+ {
+ Message message = ERR_FRACTIONAL_COULD_NOT_RETRIEVE_CONFIG.get(
+ entry.toString());
+ return PluginResult.ImportLDIF.stopEntryProcessing(message);
+ }
+ } else
+ {
+ // Found a live domain, retrieve the fractional configuration from
+ // it.
+ localFractionalConfig = domain.getFractionalConfig();
+ }
+ // Create context and store it
+ importFractionalContext =
+ new ImportFractionalContext(localFractionalConfig, domain);
+ importSessionContexts.put(importConfig, importFractionalContext);
+ }
+ }
+ }
+
+ // Extract the fractional configuration from the context
+ localFractionalConfig = importFractionalContext.getFractionalConfig();
+ if (localFractionalConfig == null)
{
// Not part of a replicated domain : nothing to do
return PluginResult.ImportLDIF.continueEntryProcessing();
}
- // Is the entry to treat the root entry of the domain ? If yes, analyze the
- // fractional configuration in it and compare with local domain fractional
- // configuration. Stop the import if some inconsistency is detcted
- DN domainBaseDn = domain.getBaseDN();
- if (domainBaseDn.equals(entryDn))
+ /**
+ * At this point, either the domain instance has been found and we use its
+ * fractional configuration, or the server is offline and we use the parsed
+ * fractional configuration. We differentiate both cases testing if domain
+ * is null. We are also for sure handling an entry of a replicated suffix.
+ */
+
+ // Is the entry to handle the root entry of the domain ? If yes, analyze the
+ // fractional configuration in it and compare with local fractional
+ // configuration. Stop the import if some inconsistency is detected
+ DN replicatedDomainBaseDn = localFractionalConfig.getBaseDn();
+ if (replicatedDomainBaseDn.equals(entryDn))
{
/*
* This is the root entry, try to read a fractional configuration from it
@@ -169,8 +370,9 @@
}
// Compare backend and local fractional configuration
- boolean sameConfig = domain.isFractionalConfigConsistent(exclIt, inclIt);
- if (domain.isFractional())
+ boolean sameConfig = LDAPReplicationDomain.
+ isFractionalConfigConsistent(localFractionalConfig, exclIt, inclIt);
+ if (localFractionalConfig.isFractional())
{
// Local domain is fractional
if (sameConfig)
@@ -190,19 +392,28 @@
}
if (remoteDomainHasSomeConfig)
{
- // Local domain is fractional, remote domain has some config which
- // is different : stop import (error will be logged when import is
- // stopped)
- domain.setImportErrorMessageId(
- LDAPReplicationDomain.IMPORT_ERROR_MESSAGE_BAD_REMOTE);
- domain.setFollowImport(false);
- return PluginResult.ImportLDIF.continueEntryProcessing();
+ LDAPReplicationDomain domain = importFractionalContext.getDomain();
+ if (domain != null)
+ {
+ // Local domain is fractional, remote domain has some config which
+ // is different : stop import (error will be logged when import is
+ // stopped)
+ domain.setImportErrorMessageId(
+ LDAPReplicationDomain.IMPORT_ERROR_MESSAGE_BAD_REMOTE);
+ domain.setFollowImport(false);
+ return PluginResult.ImportLDIF.stopEntryProcessing(null);
+ } else
+ {
+ Message message = NOTE_ERR_LDIF_IMPORT_FRACTIONAL_BAD_DATA_SET.
+ get(replicatedDomainBaseDn.toString());
+ return PluginResult.ImportLDIF.stopEntryProcessing(message);
+ }
} else
{
// Local domain is fractional but remote domain has no config :
// flush local config into root entry and follow import with
// filtering
- flushFractionalConfigIntoEntry(domain, entry);
+ flushFractionalConfigIntoEntry(localFractionalConfig, entry);
}
}
} else
@@ -215,20 +426,32 @@
return PluginResult.ImportLDIF.continueEntryProcessing();
} else
{
- // Local domain is not fractional but remote one is : stop import :
- // local domain should be configured with the same config as remote
- // one
- domain.setImportErrorMessageId(
- LDAPReplicationDomain.IMPORT_ERROR_MESSAGE_REMOTE_IS_FRACTIONAL);
- domain.setFollowImport(false);
- return PluginResult.ImportLDIF.continueEntryProcessing();
+ LDAPReplicationDomain domain = importFractionalContext.getDomain();
+ if (domain != null)
+ {
+ // Local domain is not fractional but remote one is : stop import :
+ // local domain should be configured with the same config as remote
+ // one
+ domain.setImportErrorMessageId(
+ LDAPReplicationDomain.
+ IMPORT_ERROR_MESSAGE_REMOTE_IS_FRACTIONAL);
+ domain.setFollowImport(false);
+ return PluginResult.ImportLDIF.stopEntryProcessing(null);
+ } else
+ {
+ Message message =
+ NOTE_ERR_LDIF_IMPORT_FRACTIONAL_DATA_SET_IS_FRACTIONAL.get(
+ replicatedDomainBaseDn.toString());
+ return PluginResult.ImportLDIF.stopEntryProcessing(message);
+ }
}
}
}
// If we get here, local domain fractional configuration is enabled.
// Now filter for potential attributes to be removed.
- domain.fractionalRemoveAttributesFromEntry(entry.getDN().getRDN(),
+ LDAPReplicationDomain.fractionalRemoveAttributesFromEntry(
+ localFractionalConfig, entry.getDN().getRDN(),
entry.getObjectClasses(), entry.getUserAttributes(), true);
return PluginResult.ImportLDIF.continueEntryProcessing();
@@ -240,20 +463,21 @@
* WARNING: assumption is that no fractional attributes at all is already
* present in the passed entry. Also assumption is that domain fractional
* configuration is on.
- * @param domain Domain containing the fractional configuration to use
+ * @param localFractionalConfig The local domain fractional configuration
* @param entry The entry to modify
*/
- private static void flushFractionalConfigIntoEntry(
- LDAPReplicationDomain domain, Entry entry)
+ private static void flushFractionalConfigIntoEntry(FractionalConfig
+ localFractionalConfig, Entry entry)
{
- if (domain.isFractional()) // Paranoia check
+ if (localFractionalConfig.isFractional()) // Paranoia check
{
// Get the fractional configuration of the domain
- boolean fractionalExclusive = domain.isFractionalExclusive();
+ boolean fractionalExclusive =
+ localFractionalConfig.isFractionalExclusive();
Map<String, List<String>> fractionalSpecificClassesAttributes =
- domain.getFractionalSpecificClassesAttributes();
+ localFractionalConfig.getFractionalSpecificClassesAttributes();
List<String> fractionalAllClassesAttributes =
- domain.getFractionalAllClassesAttributes();
+ localFractionalConfig.getFractionalAllClassesAttributes();
// Create attribute builder for the rigth fractional mode
String fractAttribute = null;
--
Gitblit v1.10.0