package com.codecademy.eventhub.index;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.codecademy.eventhub.base.DB;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.io.Closeable;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
/**
* DatedEventIndex is responsible for tracking the earliest event id for a given date.
*/
public class DatedEventIndex implements Closeable {
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormat.forPattern("yyyyMMdd");
private static final String DATE_PREFIX = "d";
private static final String ID_PREFIX = "i";
private final DB db;
// O(numDays)
private final List<String> dates;
// O(numDays)
private final List<Long> earliestEventIds;
private String currentDate;
public DatedEventIndex(DB db, List<String> dates, List<Long> earliestEventIds,
String currentDate) {
this.db = db;
this.dates = dates;
this.earliestEventIds = earliestEventIds;
this.currentDate = currentDate;
}
public long findFirstEventIdOnDate(long eventIdForStartDate, int numDaysAfter) {
int startDateOffset = Collections.binarySearch(earliestEventIds, eventIdForStartDate);
if (startDateOffset < 0) {
if (startDateOffset == -1) {
startDateOffset = 0;
} else {
startDateOffset = -startDateOffset - 2;
}
}
String dateOfEvent = dates.get(startDateOffset);
String endDate = DATE_TIME_FORMATTER.print(
DateTime.parse(dateOfEvent, DATE_TIME_FORMATTER).plusDays(numDaysAfter));
int endDateOffset = Collections.binarySearch(dates, endDate);
if (endDateOffset < 0) {
endDateOffset = -endDateOffset - 1;
if (endDateOffset >= earliestEventIds.size()) {
return Long.MAX_VALUE;
}
}
return earliestEventIds.get(endDateOffset);
}
public synchronized void addEvent(long eventId, String date) {
if (currentDate != null && date.compareTo(currentDate) <= 0) {
return;
}
currentDate = date;
dates.add(date);
earliestEventIds.add(eventId);
db.put(DATE_PREFIX + date, "");
db.put(ID_PREFIX + String.format("%020d", eventId), "");
}
public String getCurrentDate() {
return currentDate;
}
@Override
public void close() throws IOException {
db.close();
}
public static DatedEventIndex create(DB db) {
List<String> dates = db.findByPrefix(DATE_PREFIX, DATE_PREFIX.length());
List<Long> earliestEventIds = Lists.newArrayList(
Lists.transform(db.findByPrefix(ID_PREFIX, ID_PREFIX.length()), new Function<String, Long>() {
@Override
public Long apply(String s) {
return Long.parseLong(s);
}
}));
return new DatedEventIndex(db, dates, earliestEventIds,
dates.isEmpty() ? "" : dates.get(dates.size() - 1));
}
}