/** * This software is licensed to you under the Apache License, Version 2.0 (the * "Apache License"). * * LinkedIn's contributions are made under the Apache License. If you contribute * to the Software, the contributions will be deemed to have been made under the * Apache License, unless you expressly indicate otherwise. Please do not make any * contributions that would be inconsistent with the Apache License. * * You may obtain a copy of the Apache License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, this software * distributed under the Apache License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Apache * License for the specific language governing permissions and limitations for the * software governed under the Apache License. * * © 2012 LinkedIn Corp. All Rights Reserved. */ package com.senseidb.search.node; import java.io.IOException; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.log4j.Logger; import proj.zoie.api.DataProvider; import proj.zoie.api.IndexReaderFactory; import proj.zoie.api.Zoie; import proj.zoie.api.ZoieException; import proj.zoie.api.ZoieIndexReader; import proj.zoie.impl.indexing.ZoieSystem; import com.browseengine.bobo.api.BoboIndexReader; import com.browseengine.bobo.facets.FacetHandler; import com.browseengine.bobo.facets.RuntimeFacetHandlerFactory; import com.google.common.base.Preconditions; import com.senseidb.indexing.SenseiIndexPruner; import com.senseidb.indexing.SenseiIndexPruner.DefaultSenseiIndexPruner; import com.senseidb.jmx.JmxUtil; import com.senseidb.search.plugin.PluggableSearchEngineManager; import com.senseidb.search.req.SenseiSystemInfo; public class SenseiCore{ private static final Logger logger = Logger.getLogger(SenseiServer.class); private SenseiZoieFactory<?> _zoieFactory; private SenseiIndexingManager _indexManager; private SenseiQueryBuilderFactory _queryBuilderFactory; private final HashSet<Zoie<BoboIndexReader,?>> zoieSystems = new HashSet<Zoie<BoboIndexReader,?>>(); private final int[] _partitions; private final int _id; private final Map<Integer,Zoie<BoboIndexReader,?>> _readerFactoryMap; private SenseiSystemInfo _senseiSystemInfo; private volatile boolean _started; private SenseiIndexPruner _pruner; private PluggableSearchEngineManager pluggableSearchEngineManager; private final SenseiIndexReaderDecorator decorator; public SenseiCore(int id,int[] partitions, SenseiZoieFactory<?> zoieSystemFactory, SenseiIndexingManager indexManager, SenseiQueryBuilderFactory queryBuilderFactory, SenseiIndexReaderDecorator decorator){ _zoieFactory = zoieSystemFactory; _indexManager = indexManager; _queryBuilderFactory = queryBuilderFactory; _partitions = partitions; _id = id; this.decorator = decorator; _readerFactoryMap = new HashMap<Integer,Zoie<BoboIndexReader,?>>(); _started = false; _pruner = null; } public void setIndexPruner(SenseiIndexPruner pruner){ _pruner = pruner; } public SenseiIndexPruner getIndexPruner(){ return _pruner == null ? new DefaultSenseiIndexPruner() : _pruner; } public int getNodeId(){ return _id; } public int[] getPartitions(){ return _partitions; } public SenseiSystemInfo getSystemInfo() { if (_senseiSystemInfo == null) _senseiSystemInfo = new SenseiSystemInfo(); //if (_senseiSystemInfo.getClusterInfo() == null) //{ //List<Integer> partitionList = new ArrayList<Integer>(_partitions.length); //for (int i=0; i<_partitions.length; ++i) //{ //partitionList.add(_partitions[i]); //} //Map<Integer, List<Integer>> clusterInfo = new HashMap<Integer, List<Integer>>(); //clusterInfo.put(_id, partitionList); //_senseiSystemInfo.setClusterInfo(clusterInfo); //} if (_senseiSystemInfo.getFacetInfos() == null) { Set<SenseiSystemInfo.SenseiFacetInfo> facetInfos = new HashSet<SenseiSystemInfo.SenseiFacetInfo>(); if (_zoieFactory.getDecorator() != null && _zoieFactory.getDecorator().getFacetHandlerList() != null) { for (FacetHandler<?> facetHandler : _zoieFactory.getDecorator().getFacetHandlerList()) { facetInfos.add(new SenseiSystemInfo.SenseiFacetInfo(facetHandler.getName())); } } if (_zoieFactory.getDecorator() != null && _zoieFactory.getDecorator().getFacetHandlerFactories() != null) { for (RuntimeFacetHandlerFactory<?,?> runtimeFacetHandlerFactory : _zoieFactory.getDecorator().getFacetHandlerFactories()) { SenseiSystemInfo.SenseiFacetInfo facetInfo = new SenseiSystemInfo.SenseiFacetInfo(runtimeFacetHandlerFactory.getName()); facetInfo.setRunTime(true); facetInfos.add(facetInfo); } } _senseiSystemInfo.setFacetInfos(facetInfos); } Date lastModified = new Date(0L); String version = null; for(Zoie<BoboIndexReader,?> zoieSystem : zoieSystems) { if (version == null || _zoieFactory.getVersionComparator().compare(version, zoieSystem.getVersion()) < 0) version = zoieSystem.getVersion(); } /* for (ObjectName name : _registeredMBeans) { try { Date lastModifiedB = (Date)mbeanServer.getAttribute(name, "LastDiskIndexModifiedTime"); if (lastModified.compareTo(lastModifiedB) < 0) lastModified = lastModifiedB; } catch (Exception e) { // Simplely ignore. } } */ // TODO: fix this after zoie/hourglass jmx is done: http://linkedin.jira.com/browse/ZOIE-81 _senseiSystemInfo.setLastModified(lastModified.getTime()); if (version != null) _senseiSystemInfo.setVersion(version); return _senseiSystemInfo; } public void setSystemInfo(SenseiSystemInfo senseiSystemInfo) { _senseiSystemInfo = senseiSystemInfo; } public void start() throws Exception{ if (_started) return; for (int part : _partitions){ Zoie<BoboIndexReader,?> zoieSystem = _zoieFactory.getZoieInstance(_id,part); // register ZoieSystemAdminMBean String[] mbeannames = zoieSystem.getStandardMBeanNames(); for(String name : mbeannames) { JmxUtil.registerMBean(zoieSystem.getStandardMBean(name), "zoie-name", name + "-" + _id+"-"+part); } if(!zoieSystems.contains(zoieSystem)) { zoieSystem.start(); zoieSystems.add(zoieSystem); } _readerFactoryMap.put(part, zoieSystem); } try{ pluggableSearchEngineManager.start(this); logger.info("initializing index manager..."); if (_indexManager!=null){ _indexManager.initialize(_readerFactoryMap); } logger.info("starting index manager..."); if (_indexManager!=null){ _indexManager.start(); } logger.info("index manager started..."); } catch(Exception e){ logger.error("Unable to start indexing manager, indexing not started...",e); } _started = true; } public void shutdown() { if (!_started) return; logger.info("unregistering mbeans..."); // shutdown the index manager logger.info("Closing the pluggable index manager..."); pluggableSearchEngineManager.close(); logger.info("shutting down index manager..."); if (_indexManager != null) { _indexManager.shutdown(); } logger.info("index manager shutdown..."); // shutdown the zoieSystems for (Zoie<BoboIndexReader, ?> zoieSystem : zoieSystems) { zoieSystem.shutdown(); } zoieSystems.clear(); _started = false; } public DataProvider getDataProvider() { return _indexManager.getDataProvider(); } public IndexReaderFactory<ZoieIndexReader<BoboIndexReader>> getIndexReaderFactory(int partition) { IndexReaderFactory<ZoieIndexReader<BoboIndexReader>> readerFactory = _readerFactoryMap.get(partition); if (readerFactory == null) { logger.error("IndexReaderFactory not found for partition: " + partition + ". I'm serving partition " + _readerFactoryMap.keySet() + " only. Please check the routing strategy."); } return readerFactory; } public SenseiQueryBuilderFactory getQueryBuilderFactory() { return _queryBuilderFactory; } public Collection<Zoie<BoboIndexReader, ?>> getZoieSystems() { return zoieSystems; } public int getNumZoieSystems() { return zoieSystems.size(); } // Export snapshot from zoie to list of channels. public long exportSnapshot(List<WritableByteChannel> channels) throws IOException { return exportSnapshot(channels, 0L); } // Export snapshot from zoie to list of channels. public long exportSnapshot(List<WritableByteChannel> channels, long maxBps) throws IOException { Preconditions.checkNotNull(channels); Preconditions.checkArgument(channels.size() > 0); Preconditions.checkArgument(channels.size() >= zoieSystems.size()); int i = 0; // TODO: allow run in parallel long result = 0L; for (Zoie<BoboIndexReader,?> zoieSystem : zoieSystems) { if (zoieSystem instanceof ZoieSystem) { try { result += ((ZoieSystem<BoboIndexReader,?>)zoieSystem).exportSnapshot(channels.get(i++), maxBps); } catch (IOException e) { logger.error("exportSnapshot " + i, e); throw new IOException(e); } } } return result; } // Import snapshot to zoie from list of channels. public void importSnapshot(List<ReadableByteChannel> channels) throws IOException { importSnapshot(channels, 0L); } // Import snapshot to zoie from list of channels. public void importSnapshot(List<ReadableByteChannel> channels, long maxBps) throws IOException { Preconditions.checkNotNull(channels); Preconditions.checkArgument(channels.size() > 0); Preconditions.checkArgument(channels.size() >= zoieSystems.size()); int i = 0; // TODO: allow run in parallel for (Zoie<BoboIndexReader,?> zoieSystem : zoieSystems) { if (zoieSystem instanceof ZoieSystem) { try { ((ZoieSystem<BoboIndexReader,?>)zoieSystem).importSnapshot(channels.get(i++), maxBps); } catch (IOException e) { logger.error("exportSnapshot " + i, e); throw new IOException(e); } } } } public void optimize() { for (Zoie<BoboIndexReader,?> zoieSystem : zoieSystems) { if (zoieSystem instanceof ZoieSystem) { ((ZoieSystem<BoboIndexReader,?>)zoieSystem).optimize(); } } } public void syncWithVersion(long timeToWait, String version) throws ZoieException { _indexManager.syncWithVersion(timeToWait, version); } public void setPluggableSearchEngineManager(PluggableSearchEngineManager pluggableSearchEngineManager) { this.pluggableSearchEngineManager = pluggableSearchEngineManager; } public PluggableSearchEngineManager getPluggableSearchEngineManager() { return pluggableSearchEngineManager; } public SenseiIndexReaderDecorator getDecorator() { return decorator; } }