blob: 38dcc2a8d67e22d288aea768e97c50fbb3e33439 [file] [log] [blame]
/*
* 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
*/
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.
*
* @throws 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);
}
}
}