package com.codecademy.eventhub.index;
import com.google.common.collect.Ordering;
import com.google.common.io.Files;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.List;
import java.util.Map;
/**
* ShardedEventIndex is responsible for managing individual EventIndex sharded by event type.
*/
public class ShardedEventIndex implements Closeable {
private final String filename;
private final EventIndex.Factory eventIndexFactory;
// O(numEventTypes), from eventType to its index
private final Map<String, EventIndex> eventIndexMap;
// O(numEventTypes)
private final Map<String, Integer> eventTypeIdMap;
public ShardedEventIndex(String filename, EventIndex.Factory eventIndexFactory,
Map<String, EventIndex> eventIndexMap, Map<String, Integer> eventTypeIdMap) {
this.filename = filename;
this.eventIndexFactory = eventIndexFactory;
this.eventIndexMap = eventIndexMap;
this.eventTypeIdMap = eventTypeIdMap;
}
public void enumerateEventIds(String eventType, String startDate, String endDate,
EventIndex.Callback callback) {
eventIndexMap.get(eventType).enumerateEventIds(startDate, endDate, callback);
}
public int ensureEventType(String eventType) {
if (eventTypeIdMap.containsKey(eventType)) {
return eventTypeIdMap.get(eventType);
}
synchronized (this) {
int eventTypeId = eventIndexMap.size();
eventTypeIdMap.put(eventType, eventTypeId);
eventIndexMap.put(eventType, eventIndexFactory.build(eventType));
persistEventTypeIdMap();
return eventTypeId;
}
}
public synchronized void addEvent(long eventId, String eventType, String date) {
eventIndexMap.get(eventType).addEvent(eventId, date);
}
public List<String> getEventTypes() {
return Ordering.from(String.CASE_INSENSITIVE_ORDER).sortedCopy(eventTypeIdMap.keySet());
}
public int getEventTypeId(String eventType) {
return eventTypeIdMap.get(eventType);
}
@Override
public void close() throws IOException {
for (String eventType : eventIndexMap.keySet()) {
eventIndexMap.get(eventType).close();
}
persistEventTypeIdMap();
}
public String getVarz(int indentation) {
String indent = new String(new char[indentation]).replace('\0', ' ');
return String.format(indent + "filename: %s", filename);
}
private void persistEventTypeIdMap() {
//noinspection ResultOfMethodCallIgnored
new File(filename).getParentFile().mkdirs();
String newFilename = filename + ".new";
try {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(newFilename))) {
oos.writeObject(eventTypeIdMap);
}
Files.move(new File(newFilename), new File(filename));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}