use java.time for time
This commit is contained in:
@@ -3,5 +3,6 @@ dependencies {
|
|||||||
//compile 'com.fasterxml.jackson.core:jackson-databind:2.8.5'
|
//compile 'com.fasterxml.jackson.core:jackson-databind:2.8.5'
|
||||||
compile 'org.lucares:ludb:1.0.20161002111352'
|
compile 'org.lucares:ludb:1.0.20161002111352'
|
||||||
//compile 'commons-io:commons-io:2.5'
|
//compile 'commons-io:commons-io:2.5'
|
||||||
|
//compile 'joda-time:joda-time:2.9.6'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.lucares.performance.db;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface BlockingIterator<E> {
|
||||||
|
|
||||||
|
public Optional<E> next() throws InterruptedException;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.lucares.performance.db;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
final class BlockingIteratorIterator<E> implements BlockingIterator<E> {
|
||||||
|
|
||||||
|
private final Iterator<E> iterator;
|
||||||
|
|
||||||
|
public BlockingIteratorIterator(final Iterator<E> iterator) {
|
||||||
|
this.iterator = iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<E> next() throws InterruptedException {
|
||||||
|
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
final E next = iterator.next();
|
||||||
|
return Optional.of(next);
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package org.lucares.performance.db;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
|
||||||
|
final class BlockingQueueIterator<E> implements BlockingIterator<E> {
|
||||||
|
|
||||||
|
private final BlockingQueue<E> queue;
|
||||||
|
|
||||||
|
private boolean closed = false;
|
||||||
|
|
||||||
|
private final E poison;
|
||||||
|
|
||||||
|
public BlockingQueueIterator(final BlockingQueue<E> queue, final E poison) {
|
||||||
|
this.queue = queue;
|
||||||
|
this.poison = poison;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<E> next() throws InterruptedException {
|
||||||
|
|
||||||
|
if (closed) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
final E next = queue.take();
|
||||||
|
|
||||||
|
if (next == poison) {
|
||||||
|
closed = true;
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.of(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package org.lucares.performance.db;
|
package org.lucares.performance.db;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
@@ -8,70 +11,26 @@ import java.util.TimeZone;
|
|||||||
public class DateUtils {
|
public class DateUtils {
|
||||||
|
|
||||||
private static final TimeZone TIME_ZONE_UTC = TimeZone.getTimeZone("UTC");
|
private static final TimeZone TIME_ZONE_UTC = TimeZone.getTimeZone("UTC");
|
||||||
private static final SimpleDateFormat YEAR = new SimpleDateFormat("yyyy");
|
|
||||||
private static final SimpleDateFormat MONTH = new SimpleDateFormat("MM");
|
|
||||||
private static final SimpleDateFormat DAY = new SimpleDateFormat("dd");
|
|
||||||
|
|
||||||
public static final synchronized Day getDay(final Date date) {
|
public static long getDateOffset(final OffsetDateTime date) {
|
||||||
|
|
||||||
final String yearString = YEAR.format(date);
|
return date.truncatedTo(ChronoUnit.DAYS).toInstant().toEpochMilli();
|
||||||
final String monthString = MONTH.format(date);
|
|
||||||
final String dayString = DAY.format(date);
|
|
||||||
|
|
||||||
final int year = Integer.parseInt(yearString, 10);
|
|
||||||
final int month = Integer.parseInt(monthString, 10);
|
|
||||||
final int day = Integer.parseInt(dayString, 10);
|
|
||||||
|
|
||||||
return new Day(year, month, day);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getDateOffset(final Date date) {
|
|
||||||
|
|
||||||
return getMidnightSameDay(date).getTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Calendar getCalendar() {
|
public static Calendar getCalendar() {
|
||||||
return Calendar.getInstance(TIME_ZONE_UTC);
|
return Calendar.getInstance(TIME_ZONE_UTC);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Date getMidnightSameDay(final Date date) {
|
public static OffsetDateTime getLastInstantOfDay(final OffsetDateTime date) {
|
||||||
|
|
||||||
final Calendar exactTime = getCalendar();
|
return date.truncatedTo(ChronoUnit.DAYS).plusDays(1).minusNanos(1);
|
||||||
exactTime.setTime(date);
|
|
||||||
|
|
||||||
final Calendar midnight = getCalendar();
|
|
||||||
final int year = exactTime.get(Calendar.YEAR);
|
|
||||||
final int month = exactTime.get(Calendar.MONTH);
|
|
||||||
final int day = exactTime.get(Calendar.DATE);
|
|
||||||
midnight.set(year, month, day);
|
|
||||||
midnight.set(Calendar.HOUR, 0);
|
|
||||||
midnight.set(Calendar.MINUTE, 0);
|
|
||||||
midnight.set(Calendar.SECOND, 0);
|
|
||||||
midnight.set(Calendar.MILLISECOND, 0);
|
|
||||||
|
|
||||||
return midnight.getTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Date getMidnightNextDay(final Date date) {
|
public static OffsetDateTime getDate(final int year, final int month, final int day, final int hour,
|
||||||
final Calendar exactTime = Calendar.getInstance(TIME_ZONE_UTC);
|
final int minute, final int second) {
|
||||||
exactTime.setTime(date);
|
|
||||||
|
|
||||||
exactTime.add(Calendar.DATE, 1);
|
final OffsetDateTime result = OffsetDateTime.of(year, month, day, hour, minute, second, 0, ZoneOffset.UTC);
|
||||||
exactTime.add(Calendar.MILLISECOND, -1);
|
return result;
|
||||||
|
|
||||||
return exactTime.getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Date getDate(final int year, final int month, final int day, final int hour, final int minute,
|
|
||||||
final int second) {
|
|
||||||
|
|
||||||
final Calendar calendar = getCalendar();
|
|
||||||
calendar.set(year, month - 1, day);
|
|
||||||
calendar.set(Calendar.HOUR, hour);
|
|
||||||
calendar.set(Calendar.MINUTE, minute);
|
|
||||||
calendar.set(Calendar.SECOND, second);
|
|
||||||
calendar.set(Calendar.MILLISECOND, 0);
|
|
||||||
return calendar.getTime();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String format(final Date date) {
|
public static String format(final Date date) {
|
||||||
@@ -80,4 +39,8 @@ public class DateUtils {
|
|||||||
|
|
||||||
return dateFormat.format(date);
|
return dateFormat.format(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static OffsetDateTime nowInUtc() {
|
||||||
|
return OffsetDateTime.now(ZoneOffset.UTC);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,44 @@
|
|||||||
package org.lucares.performance.db;
|
package org.lucares.performance.db;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.time.temporal.TemporalAccessor;
|
||||||
|
import java.time.temporal.TemporalQuery;
|
||||||
|
|
||||||
class Day {
|
class Day {
|
||||||
private final int year;
|
|
||||||
private final int month;
|
private final OffsetDateTime date;
|
||||||
private final int day;
|
|
||||||
|
|
||||||
public Day(final int year, final int month, final int day) {
|
public Day(final int year, final int month, final int day) {
|
||||||
super();
|
date = OffsetDateTime.of(year, month, day, 0, 0, 0, 0, ZoneOffset.UTC);
|
||||||
this.year = year;
|
}
|
||||||
this.month = month;
|
|
||||||
this.day = day;
|
public Day(final OffsetDateTime date) {
|
||||||
|
this.date = date.truncatedTo(ChronoUnit.DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Day() {
|
||||||
|
date = OffsetDateTime.now(ZoneOffset.UTC);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getYear() {
|
public int getYear() {
|
||||||
return year;
|
return date.getYear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMonth() {
|
public int getMonth() {
|
||||||
return month;
|
return date.getMonthValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDay() {
|
public int getDay() {
|
||||||
return day;
|
return date.getDayOfMonth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getOffsetInEpochMilli() {
|
||||||
|
return date.toInstant().toEpochMilli();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -30,7 +47,67 @@ class Day {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String format(final String separator) {
|
public String format(final String separator) {
|
||||||
return String.format("%04d%s%02d%s%02d", year, separator, month, separator, day);
|
|
||||||
|
final String pattern = createPattern(separator);
|
||||||
|
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
|
||||||
|
return date.format(formatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String createPattern(final String separator) {
|
||||||
|
return String.format("yyyy%1$sMM%1$sdd", separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String serialize() {
|
||||||
|
|
||||||
|
return format("-");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Day fromString(final String dateOffset) {
|
||||||
|
|
||||||
|
final String pattern = createPattern("-");
|
||||||
|
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
|
||||||
|
final TemporalQuery<OffsetDateTime> query = new TemporalQuery<OffsetDateTime>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OffsetDateTime queryFrom(final TemporalAccessor temporal) {
|
||||||
|
final LocalDate localDate = LocalDate.from(temporal);
|
||||||
|
final LocalTime localTime = LocalTime.MIDNIGHT;
|
||||||
|
return OffsetDateTime.of(localDate, localTime, ZoneOffset.UTC);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
final OffsetDateTime date = formatter.parse(dateOffset, query);
|
||||||
|
return new Day(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeRange toTimeRange() {
|
||||||
|
final OffsetDateTime from = date;
|
||||||
|
final OffsetDateTime to = DateUtils.getLastInstantOfDay(from);
|
||||||
|
return new TimeRange(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((date == null) ? 0 : date.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
final Day other = (Day) obj;
|
||||||
|
if (date == null) {
|
||||||
|
if (other.date != null)
|
||||||
|
return false;
|
||||||
|
} else if (!date.equals(other.date))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,54 @@
|
|||||||
package org.lucares.performance.db;
|
package org.lucares.performance.db;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
public class Entry {
|
public class Entry {
|
||||||
private final Date date;
|
public static final Comparator<Entry> BY_DATE = new EntryByDateComparator();
|
||||||
|
|
||||||
|
private final long epochMilli;
|
||||||
|
|
||||||
private final long value;
|
private final long value;
|
||||||
|
|
||||||
public Entry(final Date date, final long value) {
|
public Entry(final OffsetDateTime date, final long value) {
|
||||||
super();
|
super();
|
||||||
this.date = date;
|
this.epochMilli = date.toInstant().toEpochMilli();
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getDate() {
|
Entry(final long epochMilli, final long value) {
|
||||||
return date;
|
super();
|
||||||
|
this.epochMilli = epochMilli;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OffsetDateTime getDate() {
|
||||||
|
final Instant instant = Instant.ofEpochMilli(epochMilli);
|
||||||
|
return OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getValue() {
|
public long getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long getEpochMilli() {
|
||||||
|
return epochMilli;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return DateUtils.format(date) + " = " + value;
|
final OffsetDateTime date = getDate();
|
||||||
|
return date.format(DateTimeFormatter.ISO_ZONED_DATE_TIME) + " = " + value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + ((date == null) ? 0 : date.hashCode());
|
result = prime * result + (int) (epochMilli ^ (epochMilli >>> 32));
|
||||||
result = prime * result + (int) (value ^ (value >>> 32));
|
result = prime * result + (int) (value ^ (value >>> 32));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -44,13 +62,11 @@ public class Entry {
|
|||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
final Entry other = (Entry) obj;
|
final Entry other = (Entry) obj;
|
||||||
if (date == null) {
|
if (epochMilli != other.epochMilli)
|
||||||
if (other.date != null)
|
|
||||||
return false;
|
|
||||||
} else if (!date.equals(other.date))
|
|
||||||
return false;
|
return false;
|
||||||
if (value != other.value)
|
if (value != other.value)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.lucares.performance.db;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
public class EntryByDateComparator implements Comparator<Entry> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(final Entry o1, final Entry o2) {
|
||||||
|
|
||||||
|
long result = o1.getEpochMilli() - o2.getEpochMilli();
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
result = o1.getValue() - o2.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result < 0 ? -1 : (result == 0 ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,35 +1,23 @@
|
|||||||
package org.lucares.performance.db;
|
package org.lucares.performance.db;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
class PdbFile {
|
class PdbFile {
|
||||||
private final Tags tags;
|
private final Tags tags;
|
||||||
|
|
||||||
private final long dateOffset;
|
private final Day day;
|
||||||
|
|
||||||
private final File file;
|
private final File file;
|
||||||
|
|
||||||
public PdbFile(final long dateOffset, final File file, final Tags tags) {
|
public PdbFile(final Day day, final File file, final Tags tags) {
|
||||||
checkOffset(dateOffset);
|
this.day = day;
|
||||||
this.dateOffset = dateOffset;
|
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PdbFile today(final File file, final Tags tags) {
|
public static PdbFile today(final File file, final Tags tags) {
|
||||||
final long dateOffset = DateUtils.getDateOffset(new Date());
|
final Day day = new Day();
|
||||||
return new PdbFile(dateOffset, file, tags);
|
return new PdbFile(day, file, tags);
|
||||||
}
|
|
||||||
|
|
||||||
private void checkOffset(final long dateOffset) {
|
|
||||||
|
|
||||||
final Date date = new Date(dateOffset);
|
|
||||||
final long expectedDateOffset = DateUtils.getDateOffset(date);
|
|
||||||
if (dateOffset != expectedDateOffset) {
|
|
||||||
throw new IllegalArgumentException("dateOffset must be at exactly midnight UTC: " + dateOffset + " != "
|
|
||||||
+ expectedDateOffset + "(" + date + " != " + new Date(expectedDateOffset) + ")");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tags getTags() {
|
public Tags getTags() {
|
||||||
@@ -40,14 +28,17 @@ class PdbFile {
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getDateOffset() {
|
public Day getDay() {
|
||||||
return dateOffset;
|
return day;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeRange getTimeRange() {
|
public TimeRange getTimeRange() {
|
||||||
final Date from = new Date(dateOffset);
|
|
||||||
final Date to = DateUtils.getMidnightNextDay(from);
|
return day.toTimeRange();
|
||||||
return new TimeRange(from, to);
|
}
|
||||||
|
|
||||||
|
public long getOffsetInEpochMilli() {
|
||||||
|
return getTimeRange().getFrom().toInstant().toEpochMilli();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -59,7 +50,7 @@ class PdbFile {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + (int) (dateOffset ^ (dateOffset >>> 32));
|
result = prime * result + ((day == null) ? 0 : day.hashCode());
|
||||||
result = prime * result + ((file == null) ? 0 : file.hashCode());
|
result = prime * result + ((file == null) ? 0 : file.hashCode());
|
||||||
result = prime * result + ((tags == null) ? 0 : tags.hashCode());
|
result = prime * result + ((tags == null) ? 0 : tags.hashCode());
|
||||||
return result;
|
return result;
|
||||||
@@ -74,7 +65,10 @@ class PdbFile {
|
|||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
final PdbFile other = (PdbFile) obj;
|
final PdbFile other = (PdbFile) obj;
|
||||||
if (dateOffset != other.dateOffset)
|
if (day == null) {
|
||||||
|
if (other.day != null)
|
||||||
|
return false;
|
||||||
|
} else if (!day.equals(other.day))
|
||||||
return false;
|
return false;
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
if (other.file != null)
|
if (other.file != null)
|
||||||
@@ -88,4 +82,5 @@ class PdbFile {
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.lucares.performance.db;
|
package org.lucares.performance.db;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
public class PdbFileByTimeAsc implements Comparator<PdbFile> {
|
public class PdbFileByTimeAsc implements Comparator<PdbFile> {
|
||||||
@@ -7,8 +8,9 @@ public class PdbFileByTimeAsc implements Comparator<PdbFile> {
|
|||||||
@Override
|
@Override
|
||||||
public int compare(final PdbFile o1, final PdbFile o2) {
|
public int compare(final PdbFile o1, final PdbFile o2) {
|
||||||
|
|
||||||
final long difference = o1.getDateOffset() - o2.getDateOffset();
|
final OffsetDateTime o1From = o1.getTimeRange().getFrom();
|
||||||
return difference < 0 ? -1 : (difference == 0 ? 0 : 1);
|
final OffsetDateTime o2From = o2.getTimeRange().getFrom();
|
||||||
|
return o1From.compareTo(o2From);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package org.lucares.performance.db;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.util.Date;
|
import java.time.Instant;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
class PdbReader implements AutoCloseable {
|
class PdbReader implements AutoCloseable {
|
||||||
@@ -36,18 +38,26 @@ class PdbReader implements AutoCloseable {
|
|||||||
/**
|
/**
|
||||||
* Reads the next date value.
|
* Reads the next date value.
|
||||||
*
|
*
|
||||||
* @return the date, or {@code null} if end of stream has been reached
|
* @return the date, or {@code -1} if end of stream has been reached
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public Date readDate() {
|
public long readEpochMilli() {
|
||||||
assertPositionIsADatePosition();
|
assertPositionIsADatePosition();
|
||||||
|
|
||||||
final long value = read();
|
final long value = read();
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return pdbFile.getDay().getOffsetInEpochMilli() + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OffsetDateTime readDate() {
|
||||||
|
final long epochMilli = readEpochMilli();
|
||||||
|
|
||||||
|
if (epochMilli < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new Date(pdbFile.getDateOffset() + value);
|
return Instant.ofEpochMilli(epochMilli).atOffset(ZoneOffset.UTC);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// visible for test
|
// visible for test
|
||||||
@@ -174,8 +184,8 @@ class PdbReader implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Entry> readEntry() throws ReadRuntimeException {
|
public Optional<Entry> readEntry() throws ReadRuntimeException {
|
||||||
final Date date = readDate();
|
final long epochMilli = readEpochMilli();
|
||||||
if (date == null) {
|
if (epochMilli < 0) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
final long value = readValue();
|
final long value = readValue();
|
||||||
@@ -183,7 +193,7 @@ class PdbReader implements AutoCloseable {
|
|||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
return Optional.of(new Entry(date, value));
|
return Optional.of(new Entry(epochMilli, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
class PdbWriter implements AutoCloseable {
|
class PdbWriter implements AutoCloseable {
|
||||||
|
|
||||||
@@ -24,12 +23,12 @@ class PdbWriter implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void write(final Entry entry) throws WriteException {
|
public void write(final Entry entry) throws WriteException {
|
||||||
write(entry.getDate(), entry.getValue());
|
write(entry.getEpochMilli(), entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(final Date time, final long value) throws WriteException {
|
void write(final long epochMilli, final long value) throws WriteException {
|
||||||
final long timeValue = time.getTime();
|
final long offsetEpochMill = pdbFile.getOffsetInEpochMilli();
|
||||||
final long adjustedValue = timeValue - pdbFile.getDateOffset();
|
final long adjustedValue = epochMilli - offsetEpochMill;
|
||||||
assertValueInRange(adjustedValue);
|
assertValueInRange(adjustedValue);
|
||||||
assertValueInRange(value);
|
assertValueInRange(value);
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,14 @@ package org.lucares.performance.db;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Spliterator;
|
import java.util.Spliterator;
|
||||||
import java.util.Spliterators;
|
import java.util.Spliterators;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@@ -24,7 +26,7 @@ public class PerformanceDb implements AutoCloseable {
|
|||||||
tagsToFile = new TagsToFile(dataDirectory);
|
tagsToFile = new TagsToFile(dataDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void put(final Date date, final long value, final Tags tags) throws WriteException {
|
public void put(final OffsetDateTime date, final long value, final Tags tags) throws WriteException {
|
||||||
put(new Entry(date, value), tags);
|
put(new Entry(date, value), tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,31 +35,53 @@ public class PerformanceDb implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void put(final Iterable<Entry> entries, final Tags tags) throws WriteException {
|
public void put(final Iterable<Entry> entries, final Tags tags) throws WriteException {
|
||||||
|
put(entries.iterator(), tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(final BlockingQueue<Entry> entries, final Entry poisonObject, final Tags tags)
|
||||||
|
throws WriteException {
|
||||||
|
final BlockingQueueIterator<Entry> iterator = new BlockingQueueIterator<>(entries, poisonObject);
|
||||||
|
put(iterator, tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(final Iterator<Entry> entries, final Tags tags) throws WriteException {
|
||||||
|
|
||||||
|
final BlockingIteratorIterator<Entry> iterator = new BlockingIteratorIterator<>(entries);
|
||||||
|
put(iterator, tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(final BlockingIterator<Entry> entries, final Tags tags) throws WriteException {
|
||||||
|
|
||||||
final long start = System.nanoTime();
|
final long start = System.nanoTime();
|
||||||
double timeSpendInWrite = 0.0;
|
final double timeSpendInWrite = 0.0;
|
||||||
long count = 0;
|
long count = 0;
|
||||||
PdbWriter writer = null;
|
PdbWriter writer = null;
|
||||||
PdbFile pdbFile = null;
|
PdbFile pdbFile = null;
|
||||||
try {
|
try {
|
||||||
for (final Entry entry : entries) {
|
while (true) {
|
||||||
final Date date = entry.getDate();
|
final Optional<Entry> entryOptional = entries.next();
|
||||||
|
if (!entryOptional.isPresent()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
final Entry entry = entryOptional.get();
|
||||||
|
|
||||||
|
final long epochMilli = entry.getEpochMilli();
|
||||||
final long value = entry.getValue();
|
final long value = entry.getValue();
|
||||||
|
|
||||||
if (pdbFile == null //
|
if (pdbFile == null //
|
||||||
|| !pdbFile.getTimeRange().inRange(date)) // TODO @ahr
|
|| !pdbFile.getTimeRange().inRange(epochMilli)) // TODO
|
||||||
// correct
|
// @ahr
|
||||||
// would be
|
// correct
|
||||||
// to check
|
// would be
|
||||||
// if the
|
// to check
|
||||||
// date is
|
// if the
|
||||||
// in the
|
// date is
|
||||||
// available
|
// in the
|
||||||
// range
|
// available
|
||||||
|
// range
|
||||||
{
|
{
|
||||||
final long startWrite = System.nanoTime();
|
final OffsetDateTime date = entry.getDate();
|
||||||
pdbFile = tagsToFile.getFile(date, tags);
|
pdbFile = tagsToFile.getFile(date, tags);
|
||||||
timeSpendInWrite += (System.nanoTime() - startWrite) / 1_000_000.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (writer == null || !writer.getFile().equals(pdbFile)) {
|
if (writer == null || !writer.getFile().equals(pdbFile)) {
|
||||||
@@ -67,10 +91,13 @@ public class PerformanceDb implements AutoCloseable {
|
|||||||
writer = new PdbWriter(pdbFile);
|
writer = new PdbWriter(pdbFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write(date, value);
|
writer.write(epochMilli, value);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
LOGGER.info("Thread was interrupted. Aborting exectution.");
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
throw new WriteException(e);
|
throw new WriteException(e);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -31,7 +31,7 @@ public class TagsToFile implements AutoCloseable, CollectionUtils {
|
|||||||
try {
|
try {
|
||||||
db = new H2DB(new File(dataDirectory.toFile(), "lu.db"));
|
db = new H2DB(new File(dataDirectory.toFile(), "lu.db"));
|
||||||
try {
|
try {
|
||||||
db.createField(Fields.DATE_OFFSET, FieldType.BIGINT);
|
db.createField(Fields.DATE_OFFSET, FieldType.STRING);
|
||||||
} catch (final FieldExistsException e) {
|
} catch (final FieldExistsException e) {
|
||||||
// TODO @ahr ludb needs a hasField method, or a
|
// TODO @ahr ludb needs a hasField method, or a
|
||||||
// createIfNotExists
|
// createIfNotExists
|
||||||
@@ -69,9 +69,10 @@ public class TagsToFile implements AutoCloseable, CollectionUtils {
|
|||||||
|
|
||||||
private PdbFile toPdbFile(final Document document) {
|
private PdbFile toPdbFile(final Document document) {
|
||||||
final File file = document.getFile();
|
final File file = document.getFile();
|
||||||
final long dateOffset = document.getPropertyLong(Fields.DATE_OFFSET);
|
final String dateOffset = document.getPropertyString(Fields.DATE_OFFSET);
|
||||||
|
final Day day = Day.fromString(dateOffset);
|
||||||
final Tags tagsOfFile = toTags(document);
|
final Tags tagsOfFile = toTags(document);
|
||||||
final PdbFile pdbFile = new PdbFile(dateOffset, file, tagsOfFile);
|
final PdbFile pdbFile = new PdbFile(day, file, tagsOfFile);
|
||||||
return pdbFile;
|
return pdbFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ public class TagsToFile implements AutoCloseable, CollectionUtils {
|
|||||||
return tagsOfFile;
|
return tagsOfFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PdbFile getFile(final Date date, final Tags tags) throws FileNotFoundException, IOException {
|
public PdbFile getFile(final OffsetDateTime date, final Tags tags) throws FileNotFoundException, IOException {
|
||||||
|
|
||||||
final List<PdbFile> pdbFiles = getFilesMatchingTagsExactly(tags);
|
final List<PdbFile> pdbFiles = getFilesMatchingTagsExactly(tags);
|
||||||
final List<PdbFile> preResult = new ArrayList<>();
|
final List<PdbFile> preResult = new ArrayList<>();
|
||||||
@@ -123,21 +124,20 @@ public class TagsToFile implements AutoCloseable, CollectionUtils {
|
|||||||
try (PdbReader reader = new PdbReader(pdbFile)) {
|
try (PdbReader reader = new PdbReader(pdbFile)) {
|
||||||
if (reader.canSeekTail(2)) {
|
if (reader.canSeekTail(2)) {
|
||||||
reader.seekTail(2);
|
reader.seekTail(2);
|
||||||
final Date lastDate = reader.readDate();
|
final OffsetDateTime lastWrittenDate = reader.readDate();
|
||||||
|
|
||||||
return new TimeRange(lastDate, pdbFile.getTimeRange().getTo());
|
return new TimeRange(lastWrittenDate, pdbFile.getTimeRange().getTo());
|
||||||
} else {
|
} else {
|
||||||
return pdbFile.getTimeRange();
|
return pdbFile.getTimeRange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PdbFile createNewPdbFile(final Date date, final Tags tags) {
|
private PdbFile createNewPdbFile(final OffsetDateTime date, final Tags tags) {
|
||||||
final File file;
|
final File file;
|
||||||
final long dateOffset;
|
|
||||||
PdbFile result;
|
PdbFile result;
|
||||||
file = createNewFile(date, tags);
|
file = createNewFile(date, tags);
|
||||||
dateOffset = DateUtils.getDateOffset(date);
|
final Day day = new Day(date);
|
||||||
|
|
||||||
db.addDocument(file);
|
db.addDocument(file);
|
||||||
|
|
||||||
@@ -147,9 +147,9 @@ public class TagsToFile implements AutoCloseable, CollectionUtils {
|
|||||||
db.setProperty(file, Fields.prefixedKey(key), value);
|
db.setProperty(file, Fields.prefixedKey(key), value);
|
||||||
});
|
});
|
||||||
|
|
||||||
db.setProperty(file, Fields.DATE_OFFSET, dateOffset);
|
db.setProperty(file, Fields.DATE_OFFSET, day.serialize());
|
||||||
|
|
||||||
result = new PdbFile(dateOffset, file, tags);
|
result = new PdbFile(day, file, tags);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,8 +168,8 @@ public class TagsToFile implements AutoCloseable, CollectionUtils {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private File createNewFile(final Date date, final Tags tags) {
|
private File createNewFile(final OffsetDateTime date, final Tags tags) {
|
||||||
final Day day = DateUtils.getDay(date);
|
final Day day = new Day(date);
|
||||||
final String name = tags.abbreviatedRepresentation() + UUID.randomUUID().toString();
|
final String name = tags.abbreviatedRepresentation() + UUID.randomUUID().toString();
|
||||||
|
|
||||||
final File result = StorageUtils.createStorageFile(dataDirectory, day, name);
|
final File result = StorageUtils.createStorageFile(dataDirectory, day, name);
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
package org.lucares.performance.db;
|
package org.lucares.performance.db;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.time.Duration;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
|
||||||
public class TimeRange {
|
public class TimeRange {
|
||||||
private final Date from;
|
private final OffsetDateTime from;
|
||||||
private final Date to;
|
private final OffsetDateTime to;
|
||||||
|
|
||||||
public TimeRange(final Date from, final Date to) {
|
public TimeRange(final OffsetDateTime from, final OffsetDateTime to) {
|
||||||
if (!from.before(to)) {
|
if (from.isAfter(to)) {
|
||||||
throw new IllegalArgumentException("from date must be before to date. from: " + from + " to: " + to);
|
throw new IllegalArgumentException("from date must be before to date. from: " + from + " to: " + to);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,20 +19,27 @@ public class TimeRange {
|
|||||||
this.to = to;
|
this.to = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getFrom() {
|
public OffsetDateTime getFrom() {
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getTo() {
|
public OffsetDateTime getTo() {
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long length(final TimeUnit timeUnit) {
|
public Duration duration() {
|
||||||
final long duration = to.getTime() - from.getTime();
|
return Duration.between(from, to);
|
||||||
return timeUnit.convert(duration, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean inRange(final Date date) {
|
public boolean inRange(final long epochMilli) {
|
||||||
|
// TODO @ahr cache the epoch millis
|
||||||
|
final long fromEpochMilli = from.toInstant().toEpochMilli();
|
||||||
|
final long toEpochMilli = to.toInstant().toEpochMilli();
|
||||||
|
|
||||||
|
return fromEpochMilli <= epochMilli && epochMilli <= toEpochMilli;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean inRange(final OffsetDateTime date) {
|
||||||
return from.compareTo(date) <= 0 && to.compareTo(date) >= 0;
|
return from.compareTo(date) <= 0 && to.compareTo(date) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,14 +52,17 @@ public class TimeRange {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[" + from + ":" + to + "]";
|
|
||||||
|
final DateTimeFormatter formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(ZoneOffset.UTC);
|
||||||
|
final String fromUtc = from.format(formatter);
|
||||||
|
final String totc = from.format(formatter);
|
||||||
|
|
||||||
|
return "[" + fromUtc + ":" + totc + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TimeRange today() {
|
public static TimeRange ofDay(final OffsetDateTime day) {
|
||||||
|
final OffsetDateTime from = day.truncatedTo(ChronoUnit.DAYS);
|
||||||
final Date now = new Date();
|
final OffsetDateTime to = from.plusDays(1).minusNanos(1);
|
||||||
final Date from = DateUtils.getMidnightSameDay(now);
|
|
||||||
final Date to = DateUtils.getMidnightNextDay(now);
|
|
||||||
|
|
||||||
return new TimeRange(from, to);
|
return new TimeRange(from, to);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Date;
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
import org.testng.Assert;
|
import org.testng.Assert;
|
||||||
import org.testng.annotations.AfterMethod;
|
import org.testng.annotations.AfterMethod;
|
||||||
@@ -41,7 +41,8 @@ public class PdbReaderWriterTest {
|
|||||||
|
|
||||||
final File file = Files.createTempFile(dataDirectory, "pdb", ".db").toFile();
|
final File file = Files.createTempFile(dataDirectory, "pdb", ".db").toFile();
|
||||||
final PdbFile pdbFile = PdbFile.today(file, new Tags());
|
final PdbFile pdbFile = PdbFile.today(file, new Tags());
|
||||||
final Date now = new Date(); // TODO @ahr might fail at midnight
|
final OffsetDateTime now = OffsetDateTime.now(); // TODO @ahr might fail
|
||||||
|
// at midnight
|
||||||
final Entry entry = new Entry(now, value);
|
final Entry entry = new Entry(now, value);
|
||||||
|
|
||||||
try (PdbWriter writer = new PdbWriter(pdbFile)) {
|
try (PdbWriter writer = new PdbWriter(pdbFile)) {
|
||||||
|
|||||||
@@ -4,14 +4,15 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.testng.Assert;
|
import org.testng.Assert;
|
||||||
import org.testng.annotations.AfterMethod;
|
import org.testng.annotations.AfterMethod;
|
||||||
import org.testng.annotations.BeforeMethod;
|
import org.testng.annotations.BeforeMethod;
|
||||||
@@ -35,7 +36,7 @@ public class PerformanceDbTest {
|
|||||||
public void testInsertRead() throws Exception {
|
public void testInsertRead() throws Exception {
|
||||||
|
|
||||||
try (PerformanceDb performanceDb = new PerformanceDb(dataDirectory)) {
|
try (PerformanceDb performanceDb = new PerformanceDb(dataDirectory)) {
|
||||||
final Date date = new Date();
|
final OffsetDateTime date = DateUtils.nowInUtc();
|
||||||
final long value = 1;
|
final long value = 1;
|
||||||
final Tags tags = new Tags("myKey", "myValue");
|
final Tags tags = new Tags("myKey", "myValue");
|
||||||
performanceDb.put(date, value, tags);
|
performanceDb.put(date, value, tags);
|
||||||
@@ -51,8 +52,8 @@ public class PerformanceDbTest {
|
|||||||
public void testInsertIntoMultipleFilesRead() throws Exception {
|
public void testInsertIntoMultipleFilesRead() throws Exception {
|
||||||
|
|
||||||
try (PerformanceDb performanceDb = new PerformanceDb(dataDirectory)) {
|
try (PerformanceDb performanceDb = new PerformanceDb(dataDirectory)) {
|
||||||
final Date dayOne = DateUtils.getDate(2016, 11, 1, 10, 0, 0);
|
final OffsetDateTime dayOne = DateUtils.getDate(2016, 11, 1, 10, 0, 0);
|
||||||
final Date dayTwo = DateUtils.getDate(2016, 11, 2, 12, 34, 56);
|
final OffsetDateTime dayTwo = DateUtils.getDate(2016, 11, 2, 12, 34, 56);
|
||||||
final long valueOne = 1;
|
final long valueOne = 1;
|
||||||
final long valueTwo = 2;
|
final long valueTwo = 2;
|
||||||
final Tags tags = new Tags("myKey", "myValue");
|
final Tags tags = new Tags("myKey", "myValue");
|
||||||
@@ -69,15 +70,14 @@ public class PerformanceDbTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Entry> generateEntries(final TimeRange timeRange, final long n) {
|
private List<Entry> generateEntries(final TimeRange timeRange, final long n, final int addToDate) {
|
||||||
final List<Entry> result = new ArrayList<>();
|
final List<Entry> result = new ArrayList<>();
|
||||||
final long differenceInMs = timeRange.length(TimeUnit.MILLISECONDS) / n;
|
final long differenceInMs = timeRange.duration().toMillis() / n;
|
||||||
long currentTime = timeRange.getFrom().getTime();
|
long currentTime = timeRange.getFrom().toInstant().toEpochMilli();
|
||||||
|
|
||||||
for (long i = 0; i < n; i++) {
|
for (long i = 0; i < n; i++) {
|
||||||
final Date date = new Date(currentTime);
|
|
||||||
final long value = ThreadLocalRandom.current().nextInt(0, Integer.MAX_VALUE);
|
final long value = ThreadLocalRandom.current().nextInt(0, Integer.MAX_VALUE);
|
||||||
result.add(new Entry(date, value));
|
result.add(new Entry(currentTime + addToDate, value));
|
||||||
|
|
||||||
currentTime += differenceInMs;
|
currentTime += differenceInMs;
|
||||||
}
|
}
|
||||||
@@ -88,11 +88,11 @@ public class PerformanceDbTest {
|
|||||||
|
|
||||||
try (PerformanceDb performanceDb = new PerformanceDb(dataDirectory)) {
|
try (PerformanceDb performanceDb = new PerformanceDb(dataDirectory)) {
|
||||||
|
|
||||||
final TimeRange timeRange = TimeRange.today();
|
final TimeRange timeRange = TimeRange.ofDay(OffsetDateTime.now(ZoneOffset.UTC));
|
||||||
final long numberOfEntries = 2;
|
final long numberOfEntries = 2;
|
||||||
|
|
||||||
final Tags tags = new Tags("myKey", "one");
|
final Tags tags = new Tags("myKey", "one");
|
||||||
final List<Entry> entries = generateEntries(timeRange, numberOfEntries);
|
final List<Entry> entries = generateEntries(timeRange, numberOfEntries, 0);
|
||||||
|
|
||||||
printEntries(entries, "");
|
printEntries(entries, "");
|
||||||
|
|
||||||
@@ -103,8 +103,8 @@ public class PerformanceDbTest {
|
|||||||
final List<Entry> actualEntries = performanceDb.getAsList(tags);
|
final List<Entry> actualEntries = performanceDb.getAsList(tags);
|
||||||
Assert.assertEquals(actualEntries, entries);
|
Assert.assertEquals(actualEntries, entries);
|
||||||
|
|
||||||
final File storageFileForToday = StorageUtils.createStorageFile(dataDirectory,
|
final File storageFileForToday = StorageUtils.createStorageFile(dataDirectory, new Day(timeRange.getFrom()),
|
||||||
DateUtils.getDay(timeRange.getFrom()), "name doesn't matter");
|
"name doesn't matter");
|
||||||
final File storageFolderForToday = storageFileForToday.getParentFile();
|
final File storageFolderForToday = storageFileForToday.getParentFile();
|
||||||
final File[] filesInStorage = storageFolderForToday.listFiles();
|
final File[] filesInStorage = storageFolderForToday.listFiles();
|
||||||
Assert.assertEquals(filesInStorage.length, 1,
|
Assert.assertEquals(filesInStorage.length, 1,
|
||||||
@@ -115,27 +115,25 @@ public class PerformanceDbTest {
|
|||||||
public void testInsertIntoMultipleFilesWithDifferentTags() throws Exception {
|
public void testInsertIntoMultipleFilesWithDifferentTags() throws Exception {
|
||||||
|
|
||||||
try (PerformanceDb performanceDb = new PerformanceDb(dataDirectory)) {
|
try (PerformanceDb performanceDb = new PerformanceDb(dataDirectory)) {
|
||||||
final Date from = DateUtils.getDate(2016, 1, 1, 00, 00, 00);
|
final OffsetDateTime from = DateUtils.getDate(2016, 1, 1, 00, 00, 00);
|
||||||
final Date to = DateUtils.getDate(2016, 12, 31, 23, 59, 59);
|
final OffsetDateTime to = DateUtils.getDate(2016, 1, 1, 23, 59, 50);
|
||||||
|
|
||||||
final TimeRange timeRange = new TimeRange(from, to);
|
final TimeRange timeRange = new TimeRange(from, to);
|
||||||
final long numberOfEntries = timeRange.length(TimeUnit.DAYS) * 2; // two
|
final long numberOfEntries = timeRange.duration().toHours();
|
||||||
// entries
|
|
||||||
// per
|
|
||||||
// day
|
|
||||||
|
|
||||||
|
final Tags tagsCommon = new Tags("commonKey", "commonValue");
|
||||||
final Tags tagsOne = new Tags("myKey", "one", "commonKey", "commonValue");
|
final Tags tagsOne = new Tags("myKey", "one", "commonKey", "commonValue");
|
||||||
final List<Entry> entriesOne = generateEntries(timeRange, numberOfEntries);
|
final List<Entry> entriesOne = generateEntries(timeRange, numberOfEntries, 1);
|
||||||
printEntries(entriesOne, "one");
|
printEntries(entriesOne, "one");
|
||||||
performanceDb.put(entriesOne, tagsOne);
|
performanceDb.put(entriesOne, tagsOne);
|
||||||
|
|
||||||
final Tags tagsTwo = new Tags("myKey", "two", "commonKey", "commonValue");
|
final Tags tagsTwo = new Tags("myKey", "two", "commonKey", "commonValue");
|
||||||
final List<Entry> entriesTwo = generateEntries(timeRange, numberOfEntries);
|
final List<Entry> entriesTwo = generateEntries(timeRange, numberOfEntries, 2);
|
||||||
printEntries(entriesTwo, "two");
|
printEntries(entriesTwo, "two");
|
||||||
performanceDb.put(entriesTwo, tagsTwo);
|
performanceDb.put(entriesTwo, tagsTwo);
|
||||||
|
|
||||||
final Tags tagsThree = new Tags("myKey", "three", "commonKey", "commonValue");
|
final Tags tagsThree = new Tags("myKey", "three", "commonKey", "commonValue");
|
||||||
final List<Entry> entriesThree = generateEntries(timeRange, numberOfEntries);
|
final List<Entry> entriesThree = generateEntries(timeRange, numberOfEntries, 3);
|
||||||
printEntries(entriesThree, "three");
|
printEntries(entriesThree, "three");
|
||||||
performanceDb.put(entriesThree, tagsThree);
|
performanceDb.put(entriesThree, tagsThree);
|
||||||
|
|
||||||
@@ -148,6 +146,13 @@ public class PerformanceDbTest {
|
|||||||
final List<Entry> actualEntriesThree = performanceDb.getAsList(tagsThree);
|
final List<Entry> actualEntriesThree = performanceDb.getAsList(tagsThree);
|
||||||
Assert.assertEquals(actualEntriesThree, entriesThree);
|
Assert.assertEquals(actualEntriesThree, entriesThree);
|
||||||
|
|
||||||
|
final List<Entry> actualEntriesAll = performanceDb.getAsList(tagsCommon);
|
||||||
|
final List<Entry> expectedAll = CollectionUtils.collate(entriesOne,
|
||||||
|
CollectionUtils.collate(entriesTwo, entriesThree, Entry.BY_DATE), Entry.BY_DATE);
|
||||||
|
|
||||||
|
actualEntriesAll.sort(Entry.BY_DATE);
|
||||||
|
Assert.assertEquals(actualEntriesAll, expectedAll);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,8 +160,12 @@ public class PerformanceDbTest {
|
|||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (final Entry entry : entriesOne) {
|
for (final Entry entry : entriesOne) {
|
||||||
System.out.printf("%4d %s %d (%s)\n", index, DateUtils.format(entry.getDate()), entry.getValue(), label);
|
System.out.printf("%4d %s %d (%s)\n", index, entry.getDate(), entry.getValue(), label);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testBlockingIteratorInput() throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ package org.lucares.performance.db;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Date;
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
|
||||||
import org.testng.Assert;
|
import org.testng.Assert;
|
||||||
import org.testng.annotations.AfterMethod;
|
import org.testng.annotations.AfterMethod;
|
||||||
@@ -28,7 +29,7 @@ public class TagsToFilesTest {
|
|||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
try (final TagsToFile tagsToFile = new TagsToFile(dataDirectory)) {
|
try (final TagsToFile tagsToFile = new TagsToFile(dataDirectory)) {
|
||||||
|
|
||||||
final Date date = new Date();
|
final OffsetDateTime date = OffsetDateTime.now(ZoneOffset.UTC);
|
||||||
final Tags tags = new Tags("myKey", "myValue");
|
final Tags tags = new Tags("myKey", "myValue");
|
||||||
|
|
||||||
final PdbFile newFileForTags = tagsToFile.getFile(date, tags);
|
final PdbFile newFileForTags = tagsToFile.getFile(date, tags);
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package org.lucares.performance.db;
|
package org.lucares.performance.db;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.testng.Assert;
|
import org.testng.Assert;
|
||||||
@@ -15,10 +17,10 @@ public class TimeRangeTest {
|
|||||||
Object[][] providerIntersect() {
|
Object[][] providerIntersect() {
|
||||||
final List<Object[]> result = new ArrayList<>();
|
final List<Object[]> result = new ArrayList<>();
|
||||||
|
|
||||||
final Date a = new Date(1000);
|
final OffsetDateTime a = Instant.ofEpochMilli(1000).atOffset(ZoneOffset.UTC);
|
||||||
final Date b = new Date(2000);
|
final OffsetDateTime b = Instant.ofEpochMilli(2000).atOffset(ZoneOffset.UTC);
|
||||||
final Date c = new Date(3000);
|
final OffsetDateTime c = Instant.ofEpochMilli(3000).atOffset(ZoneOffset.UTC);
|
||||||
final Date d = new Date(4000);
|
final OffsetDateTime d = Instant.ofEpochMilli(4000).atOffset(ZoneOffset.UTC);
|
||||||
|
|
||||||
result.add(new Object[] { new TimeRange(a, b), new TimeRange(c, d), false });
|
result.add(new Object[] { new TimeRange(a, b), new TimeRange(c, d), false });
|
||||||
result.add(new Object[] { new TimeRange(a, c), new TimeRange(b, d), true });
|
result.add(new Object[] { new TimeRange(a, c), new TimeRange(b, d), true });
|
||||||
@@ -34,4 +36,5 @@ public class TimeRangeTest {
|
|||||||
Assert.assertEquals(a.intersect(b), expected, a + " intersects " + b);
|
Assert.assertEquals(a.intersect(b), expected, a + " intersects " + b);
|
||||||
Assert.assertEquals(b.intersect(a), expected, a + " intersects " + b);
|
Assert.assertEquals(b.intersect(a), expected, a + " intersects " + b);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
5
recommind-logs/.gitignore
vendored
Normal file
5
recommind-logs/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/bin/
|
||||||
|
/test-output/
|
||||||
|
/.settings/
|
||||||
|
/.classpath
|
||||||
|
/.project
|
||||||
6
recommind-logs/build.gradle
Normal file
6
recommind-logs/build.gradle
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':performanceDb')
|
||||||
|
compile "io.thekraken:grok:0.1.5"
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package org.lucares.recommind.logs;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.lucares.performance.db.Entry;
|
||||||
|
|
||||||
|
import io.thekraken.grok.api.Grok;
|
||||||
|
import io.thekraken.grok.api.Match;
|
||||||
|
|
||||||
|
public class LogReader implements Iterable<Entry> {
|
||||||
|
|
||||||
|
private final Grok grok;
|
||||||
|
|
||||||
|
public LogReader(final Grok grok) {
|
||||||
|
super();
|
||||||
|
this.grok = grok;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Entry> iterator() {
|
||||||
|
|
||||||
|
// Grok grok = Grok.create("patterns/patterns");
|
||||||
|
|
||||||
|
/** Grok pattern to compile, here httpd logs */
|
||||||
|
// grok.compile("%{COMBINEDAPACHELOG}");
|
||||||
|
|
||||||
|
/** Line of log to match */
|
||||||
|
final String log = "112.169.19.192 - - [06/Mar/2013:01:36:30 +0900] \"GET / HTTP/1.1\" 200 44346 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.152 Safari/537.22\"";
|
||||||
|
|
||||||
|
final Match gm = grok.match(log);
|
||||||
|
gm.captures();
|
||||||
|
gm.toMap();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.lucares.recommind.logs;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
|
||||||
|
import org.lucares.performance.db.Entry;
|
||||||
|
import org.lucares.performance.db.PerformanceDb;
|
||||||
|
import org.lucares.performance.db.Tags;
|
||||||
|
|
||||||
|
public class PerformanceLogs {
|
||||||
|
|
||||||
|
public void ingest(final PerformanceDb db, final File performanceLog, final Tags tags) {
|
||||||
|
|
||||||
|
final ArrayBlockingQueue<Entry> queue = new ArrayBlockingQueue<>(10);
|
||||||
|
|
||||||
|
db.put(queue, tags);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user