| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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. |
| */ |
| package org.apache.vxquery.runtime.functions.index.indexCentralizer; |
| |
| import java.io.DataOutput; |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import javax.xml.bind.JAXBContext; |
| import javax.xml.bind.JAXBException; |
| import javax.xml.bind.Marshaller; |
| import javax.xml.bind.Unmarshaller; |
| |
| import org.apache.commons.io.FileUtils; |
| import org.apache.hyracks.data.std.util.ArrayBackedValueStorage; |
| import org.apache.vxquery.datamodel.builders.atomic.StringValueBuilder; |
| import org.apache.vxquery.datamodel.builders.sequence.SequenceBuilder; |
| import org.apache.vxquery.datamodel.values.ValueTag; |
| |
| /** |
| * Class for maintaining the centralized index information file. |
| * Index centralization procedure. |
| * User can specify the collection directory in VXQuery.java, ncConfig.ioDevices = < index_directory > . |
| * Then all the indexes will be created in that particular directory in sub-folders corresponding to collections. |
| * There will be a single xml file, located in the directory specified in local.xml, which contains all information |
| * about the existing indexes. |
| * This class can be used to read, add, delete, modify the entries and write the file back to the disk. |
| */ |
| public class IndexCentralizerUtil { |
| |
| private final String FILE_NAME = "VXQuery-Index-Directory.xml"; |
| private final List<String> collections = new ArrayList<>(); |
| private final Logger LOGGER = Logger.getLogger("IndexCentralizerUtil"); |
| private File XML_FILE; |
| private String INDEX_LOCATION; |
| private static ConcurrentHashMap<String, IndexLocator> indexCollectionMap = new ConcurrentHashMap<>(); |
| |
| public IndexCentralizerUtil(File index) { |
| this.INDEX_LOCATION = index.getPath(); |
| if (!index.exists()) { |
| try { |
| FileUtils.forceMkdir(index); |
| } catch (IOException e) { |
| LOGGER.log(Level.SEVERE, "Could not create the index directory for path: " + INDEX_LOCATION + " " + e); |
| } |
| } |
| XML_FILE = new File(index.getPath() + "/" + FILE_NAME); |
| } |
| |
| /** |
| * Get the index directory containing index of the given collection |
| * |
| * @param collection : Collection folder |
| * @return Index folder. |
| */ |
| public String getIndexForCollection(String collection) { |
| return indexCollectionMap.get(collection).getIndex(); |
| } |
| |
| /** |
| * Put the index location corresponding to given collection. |
| * Index location is created by using the last 100 characters of collection. |
| * |
| * @param collection : Collection directory |
| * @return index |
| */ |
| public String putIndexForCollection(String collection) { |
| int length = collection.replaceAll("/", "").length(); |
| String index = collection.replaceAll("/", ""); |
| index = INDEX_LOCATION + "/" + (length > 100 ? index.substring(length - 100) : index); |
| IndexLocator il = new IndexLocator(); |
| il.setCollection(collection); |
| il.setIndex(index); |
| if (indexCollectionMap.get(collection) != null) { |
| return index; |
| } |
| indexCollectionMap.put(collection, il); |
| return index; |
| } |
| |
| /** |
| * Remove the entry for given collection directory. |
| * |
| * @param collection : Collection directory |
| */ |
| public void deleteEntryForCollection(String collection) { |
| indexCollectionMap.remove(collection); |
| } |
| |
| /** |
| * Prints all collections which have an index created. |
| * @param sb : The output is stored in a sequence |
| * @throws IOException : If writing the dataOutput generates {@link IOException} |
| */ |
| public void getAllCollections(SequenceBuilder sb) throws IOException { |
| for (String s : collections) { |
| StringValueBuilder svb = new StringValueBuilder(); |
| ArrayBackedValueStorage abvs = new ArrayBackedValueStorage(); |
| DataOutput output = abvs.getDataOutput(); |
| output.write(ValueTag.XS_STRING_TAG); |
| svb.write(s, output); |
| sb.addItem(abvs); |
| } |
| } |
| |
| /** |
| * Read the collection, index directory file and populate the HashMap. |
| */ |
| public void readIndexDirectory() { |
| if (this.XML_FILE.exists()) { |
| try { |
| JAXBContext jaxbContext = JAXBContext.newInstance(IndexDirectory.class); |
| Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); |
| IndexDirectory indexDirectory = (IndexDirectory) jaxbUnmarshaller.unmarshal(this.XML_FILE); |
| |
| for (IndexLocator il : indexDirectory.getDirectory()) { |
| indexCollectionMap.put(il.getCollection(), il); |
| this.collections.add(il.getCollection()); |
| } |
| } catch (JAXBException e) { |
| LOGGER.log(Level.SEVERE, "Could not read the XML file due to " + e); |
| } |
| } |
| |
| } |
| |
| /** |
| * Write back the contents of the HashMap to the file. |
| */ |
| public void writeIndexDirectory() { |
| IndexDirectory id = new IndexDirectory(); |
| List<IndexLocator> indexLocators = new ArrayList<>(indexCollectionMap.values()); |
| id.setDirectory(indexLocators); |
| try { |
| FileOutputStream fileOutputStream = new FileOutputStream(this.XML_FILE); |
| JAXBContext context = JAXBContext.newInstance(IndexDirectory.class); |
| Marshaller jaxbMarshaller = context.createMarshaller(); |
| jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); |
| jaxbMarshaller.marshal(id, fileOutputStream); |
| } catch (JAXBException | FileNotFoundException e) { |
| LOGGER.log(Level.SEVERE, "Could not read the XML file due to " + e); |
| } |
| } |
| } |