Package com.orientechnologies.orient.server.distributed

Source Code of com.orientechnologies.orient.server.distributed.ODistributedAbstractPlugin

/*
     *
     *  *  Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
     *  *
     *  *  Licensed under the Apache License, Version 2.0 (the "License");
     *  *  you may not use this file except in compliance with the License.
     *  *  You may obtain a copy of the License at
     *  *
     *  *       http://www.apache.org/licenses/LICENSE-2.0
     *  *
     *  *  Unless required by applicable law or agreed to in writing, software
     *  *  distributed under the License is distributed on an "AS IS" BASIS,
     *  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     *  *  See the License for the specific language governing permissions and
     *  *  limitations under the License.
     *  *
     *  * For more information: http://www.orientechnologies.com
     *
     */
package com.orientechnologies.orient.server.distributed;

import com.orientechnologies.common.log.OLogManager;
import com.orientechnologies.common.parser.OSystemVariableResolver;
import com.orientechnologies.orient.core.Orient;
import com.orientechnologies.orient.core.db.ODatabaseComplex;
import com.orientechnologies.orient.core.db.ODatabaseInternal;
import com.orientechnologies.orient.core.db.ODatabaseLifecycleListener;
import com.orientechnologies.orient.core.exception.OConfigurationException;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.storage.OStorage;
import com.orientechnologies.orient.core.storage.OStorageEmbedded;
import com.orientechnologies.orient.server.OServer;
import com.orientechnologies.orient.server.config.OServerParameterConfiguration;
import com.orientechnologies.orient.server.distributed.ODistributedServerLog.DIRECTION;
import com.orientechnologies.orient.server.distributed.conflict.OReplicationConflictResolver;
import com.orientechnologies.orient.server.plugin.OServerPluginAbstract;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
  * Abstract plugin to manage the distributed environment.
  *
  * @author Luca Garulli (l.garulli--at--orientechnologies.com)
  *
  */
public abstract class ODistributedAbstractPlugin extends OServerPluginAbstract implements ODistributedServerManager,
     ODatabaseLifecycleListener {
   public static final String                               REPLICATOR_USER             = "replicator";
   protected static final String                            MASTER_AUTO                 = "$auto";

   protected static final String                            PAR_DEF_DISTRIB_DB_CONFIG   = "configuration.db.default";
   protected static final String                            FILE_DISTRIBUTED_DB_CONFIG  = "distributed-config.json";

   protected OServer                                        serverInstance;
   protected Map<String, ODocument>                         cachedDatabaseConfiguration = new HashMap<String, ODocument>();

   protected boolean                                        enabled                     = true;
   protected String                                         nodeName                    = null;
   protected Class<? extends OReplicationConflictResolver>  confictResolverClass;
   protected File                                           defaultDatabaseConfigFile;
   protected ConcurrentHashMap<String, ODistributedStorage> storages                    = new ConcurrentHashMap<String, ODistributedStorage>();

   @Override
   public PRIORITY getPriority() {
     return PRIORITY.LAST;
   }

   @SuppressWarnings("unchecked")
   @Override
   public void config(OServer oServer, OServerParameterConfiguration[] iParams) {
     serverInstance = oServer;
     oServer.setVariable("ODistributedAbstractPlugin", this);

     for (OServerParameterConfiguration param : iParams) {
       if (param.name.equalsIgnoreCase("enabled")) {
         if (!Boolean.parseBoolean(OSystemVariableResolver.resolveSystemVariables(param.value))) {
           // DISABLE IT
           enabled = false;
           return;
         }
       } else if (param.name.equalsIgnoreCase("nodeName"))
         nodeName = param.value;
       else if (param.name.startsWith(PAR_DEF_DISTRIB_DB_CONFIG)) {
         setDefaultDatabaseConfigFile(param.value);
       } else if (param.name.equalsIgnoreCase("conflict.resolver.impl"))
         try {
           confictResolverClass = (Class<? extends OReplicationConflictResolver>) Class.forName(param.value);
         } catch (ClassNotFoundException e) {
           OLogManager.instance().error(this, "Cannot find the conflict resolver implementation '%s'", e, param.value);
         }
     }

     if (serverInstance.getUser(REPLICATOR_USER) == null)
       // CREATE THE REPLICATOR USER
       try {
         serverInstance.addUser(REPLICATOR_USER, null, "database.passthrough");
         serverInstance.saveConfiguration();
       } catch (IOException e) {
         throw new OConfigurationException("Error on creating 'replicator' user", e);
       }
   }

   public void setDefaultDatabaseConfigFile(final String iFile) {
     defaultDatabaseConfigFile = new File(OSystemVariableResolver.resolveSystemVariables(iFile));
     if (!defaultDatabaseConfigFile.exists())
       throw new OConfigurationException("Cannot find distributed database config file: " + defaultDatabaseConfigFile);
   }

   @Override
   public void startup() {
     if (!enabled)
       return;

     Orient.instance().addDbLifecycleListener(this);
   }

   @Override
   public void shutdown() {
     if (!enabled)
       return;

     // CLOSE AND FREE ALL THE STORAGES
     for (ODistributedStorage s : storages.values())
       try {
         s.shutdownAsynchronousWorker();
         s.close();
       } catch (Exception e) {
       }
     storages.clear();

     Orient.instance().removeDbLifecycleListener(this);
   }

   /**
    * Auto register myself as hook.
    */
   @Override
   public void onOpen(final ODatabaseInternal iDatabase) {
     final String dbUrl = OSystemVariableResolver.resolveSystemVariables(iDatabase.getURL());

     if (dbUrl.startsWith("plocal:")) {
       // CHECK SPECIAL CASE WITH MULTIPLE SERVER INSTANCES ON THE SAME JVM
       final String dbDirectory = serverInstance.getDatabaseDirectory();
       if (!dbUrl.substring("plocal:".length()).startsWith(dbDirectory))
         // SKIP IT: THIS HAPPENS ONLY ON MULTIPLE SERVER INSTANCES ON THE SAME JVM
         return;
     }

     synchronized (cachedDatabaseConfiguration) {
       final ODistributedConfiguration cfg = getDatabaseConfiguration(iDatabase.getName());
       if (cfg == null)
         return;

       final OStorage dbStorage = iDatabase.getStorage();

       if (iDatabase instanceof ODatabaseComplex<?> && dbStorage instanceof OStorageEmbedded) {
         ODistributedStorage storage = storages.get(iDatabase.getURL());
         if (storage == null) {
           storage = new ODistributedStorage(serverInstance, (OStorageEmbedded) dbStorage);
           final ODistributedStorage oldStorage = storages.putIfAbsent(iDatabase.getURL(), storage);
           if (oldStorage != null)
             storage = oldStorage;
         }

         iDatabase.replaceStorage(storage);
       }
     }
   }

   @Override
   public void onCreate(ODatabaseInternal iDatabase) {
     onOpen(iDatabase);
   }

   /**
    * Remove myself as hook.
    */
   @Override
   public void onClose(final ODatabaseInternal iDatabase) {
   }

   @Override
   public void sendShutdown() {
     super.sendShutdown();
   }

   @Override
   public String getName() {
     return "cluster";
   }

   public String getLocalNodeId() {
     return nodeName;
   }

   public boolean updateCachedDatabaseConfiguration(final String iDatabaseName, final ODocument cfg, final boolean iSaveToDisk) {
     synchronized (cachedDatabaseConfiguration) {
       ODocument oldCfg = cachedDatabaseConfiguration.get(iDatabaseName);
       Integer oldVersion = oldCfg != null ? (Integer) oldCfg.field("version") : null;
       if (oldVersion == null)
         oldVersion = 1;

       Integer currVersion = (Integer) cfg.field("version");
       if (currVersion == null)
         currVersion = 1;

       if (oldCfg != null && oldVersion > currVersion) {
         // NO CHANGE, SKIP IT
         OLogManager.instance().debug(this,
             "Skip saving of distributed configuration file for database '%s' because is unchanged (version %d)", iDatabaseName,
             (Integer) cfg.field("version"));
         return false;
       }

       // SAVE IN NODE'S LOCAL RAM
       cachedDatabaseConfiguration.put(iDatabaseName, cfg);

       // PRINT THE NEW CONFIGURATION
       ODistributedServerLog.info(this, getLocalNodeName(), null, DIRECTION.NONE,
           "updated distributed configuration for database: %s:\n----------\n%s\n----------", iDatabaseName,
           cfg.toJSON("prettyPrint"));

       if (iSaveToDisk) {
         // SAVE THE CONFIGURATION TO DISK
         FileOutputStream f = null;
         try {
           File file = getDistributedConfigFile(iDatabaseName);

           ODistributedServerLog.info(this, getLocalNodeName(), null, DIRECTION.NONE,
               "Saving distributed configuration file for database '%s' to: %s", iDatabaseName, file);

           if (!file.exists()) {
             file.getParentFile().mkdirs();
             file.createNewFile();
           }

           f = new FileOutputStream(file);
           f.write(cfg.toJSON().getBytes());
           f.flush();
         } catch (Exception e) {
           ODistributedServerLog.error(this, getLocalNodeName(), null, DIRECTION.NONE,
               "Error on saving distributed configuration file", e);

         } finally {
           if (f != null)
             try {
               f.close();
             } catch (IOException e) {
             }
         }
       }
     }
     return true;
   }

   public ODistributedConfiguration getDatabaseConfiguration(final String iDatabaseName) {
     synchronized (cachedDatabaseConfiguration) {
       ODocument cfg = cachedDatabaseConfiguration.get(iDatabaseName);
       if (cfg == null) {

         // LOAD FILE IN DATABASE DIRECTORY IF ANY
         final File specificDatabaseConfiguration = getDistributedConfigFile(iDatabaseName);
         cfg = loadDatabaseConfiguration(iDatabaseName, specificDatabaseConfiguration);

         if (cfg == null) {
           // FIRST TIME RUNNING: GET DEFAULT CFG
           cfg = loadDatabaseConfiguration(iDatabaseName, defaultDatabaseConfigFile);
           if (cfg == null)
             throw new OConfigurationException("Cannot load default distributed database config file: " + defaultDatabaseConfigFile);
         }

         cachedDatabaseConfiguration.put(iDatabaseName, cfg);
       }

       final ODistributedConfiguration dCfg = new ODistributedConfiguration(cfg);
       if (dCfg.upgrade())
         // UPGRADED, SAVE IT AGAIN
         updateCachedDatabaseConfiguration(iDatabaseName, dCfg.serialize(), true);
       return dCfg;
     }
   }

   public File getDistributedConfigFile(final String iDatabaseName) {
     return new File(serverInstance.getDatabaseDirectory() + iDatabaseName + "/" + FILE_DISTRIBUTED_DB_CONFIG);
   }

   public OServer getServerInstance() {
     return serverInstance;
   }

   protected ODocument loadDatabaseConfiguration(final String iDatabaseName, final File file) {
     if (!file.exists() || file.length() == 0)
       return null;

     ODistributedServerLog.info(this, getLocalNodeName(), null, DIRECTION.NONE, "loaded database configuration from disk: %s", file);

     FileInputStream f = null;
     try {
       f = new FileInputStream(file);
       final byte[] buffer = new byte[(int) file.length()];
       f.read(buffer);

       final ODocument doc = (ODocument) new ODocument().fromJSON(new String(buffer), "noMap");
       doc.field("version", 0);
       updateCachedDatabaseConfiguration(iDatabaseName, doc, false);
       return doc;

     } catch (Exception e) {
       ODistributedServerLog.error(this, getLocalNodeName(), null, DIRECTION.NONE,
           "Error on loading distributed configuration file in: %s", e, file.getAbsolutePath());
     } finally {
       if (f != null)
         try {
           f.close();
         } catch (IOException e) {
         }
     }
     return null;
   }
}
TOP

Related Classes of com.orientechnologies.orient.server.distributed.ODistributedAbstractPlugin

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.