Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Only initialize BusinessCalendar caches when data is accessed and improve caching performance #5378

Merged
merged 57 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
bc97c74
Only initialize BusinessCalendar caches when data is accessed.
chipkent Apr 17, 2024
4e2e878
Move the calendar to lazy ConcurrentHashMap initialization plus start…
chipkent Apr 17, 2024
f3fadc9
Added a thread-safe lazily initialized summary data cache by month an…
chipkent Apr 18, 2024
d39dec7
Using advanced caching in the BusinessCalendar v1.
chipkent Apr 18, 2024
52a4521
Fix javadoc warnings.
chipkent Apr 18, 2024
ccd9025
Using advanced caching in the BusinessCalendar v2.
chipkent Apr 18, 2024
9f07d91
Using advanced caching in the BusinessCalendar v3.
chipkent Apr 18, 2024
01377ab
Using advanced caching in the Calendar v4. Fixed unit tests.
chipkent Apr 18, 2024
c9be433
Fixed exclusive/inclusive problems.
chipkent Apr 18, 2024
3accd32
Spotless.
chipkent Apr 19, 2024
32f5c57
Spotless.
chipkent Apr 19, 2024
d1d96df
Copyright header.
chipkent Apr 19, 2024
fa69016
Copyright header.
chipkent Apr 19, 2024
f5e1e5f
Copyright header.
chipkent Apr 19, 2024
bf54c0f
Copyright header.
chipkent Apr 19, 2024
94fa753
A generalized fast concurrent cache.
chipkent Apr 23, 2024
9a47feb
Incorporating generalized cache.
chipkent Apr 23, 2024
d50afa4
Incorporating generalized cache.
chipkent Apr 24, 2024
5b0fe54
Incorporating generalized cache.
chipkent Apr 24, 2024
d0cde5a
Incorporating generalized cache.
chipkent Apr 24, 2024
b12453d
Configs to control fast cache population.
chipkent Apr 24, 2024
9a28928
Spotless
chipkent Apr 24, 2024
51138c7
Add a missing volatile.
chipkent Apr 25, 2024
2399510
More perf tuning.
chipkent Apr 25, 2024
c8e9fff
Fixed some locking problems.
chipkent Apr 25, 2024
3d5e500
Spotless
chipkent Apr 26, 2024
11725d7
Fast cache implementation based on a stamped lock.
chipkent May 17, 2024
cc8e4dc
Removed cache population and clean up code.
chipkent May 17, 2024
75283e7
Code self review.
chipkent May 17, 2024
359dc05
Spotless
chipkent May 17, 2024
4da4729
Moved to a KeyedIntObjectHash.
chipkent May 17, 2024
8e92d1e
Moved to a IntFunction.
chipkent May 17, 2024
050defa
Spotless
chipkent May 17, 2024
64911da
Addressing code review.
chipkent May 24, 2024
46320db
Addressing code review.
chipkent May 24, 2024
166074c
Addressing code review.
chipkent May 24, 2024
3a1c412
Addressing code review.
chipkent May 24, 2024
55d43a8
Made cache clearing package private.
chipkent Jun 18, 2024
38f6c0f
Reduced CalendarDay memory usage.
chipkent Jun 18, 2024
d1f88ec
Move businessNanos calculation to the constructor for a calendar day.
chipkent Jun 18, 2024
99abd9b
Simplify cache key type definition.
chipkent Jun 18, 2024
ab00dfc
Rename cache getter.
chipkent Jun 18, 2024
431a244
Remove poorly designed cache methods
chipkent Jun 18, 2024
46ab5bf
Consolidate year-monty key calculation.
chipkent Jun 18, 2024
5888eee
Consolidate cache key calculations.
chipkent Jun 18, 2024
43e4724
Address review comments.
chipkent Jun 24, 2024
4b26109
Merge remote-tracking branch 'origin/main' into bus_cal_init_speed
chipkent Aug 20, 2024
03ba3bd
Improve method naming.
chipkent Aug 20, 2024
d3416ba
Addressing review
chipkent Oct 3, 2024
d989315
Addressing review
chipkent Oct 3, 2024
cde9ab0
Addressing review
chipkent Oct 3, 2024
130a785
Merge remote-tracking branch 'upstream/main' into bus_cal_init_speed
chipkent Oct 3, 2024
e057f00
Addressing review
chipkent Oct 3, 2024
04d21ba
Addressing review
chipkent Oct 3, 2024
502bce0
Fix broken unit tests
chipkent Oct 9, 2024
1c33f1e
Merge remote-tracking branch 'origin/main' into bus_cal_init_speed
chipkent Oct 9, 2024
e77fa84
Addressing review comments
chipkent Oct 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public InvalidDateException(final String message, final Throwable cause) {

// region Cache

private static class SummaryData extends ImmutableConcurrentCache.IntKeyedValue {
private static class SummaryData extends ReadOptimizedConcurrentCache.IntKeyedValue {
private final Instant startInstant;
private final LocalDate startDate;
private final Instant endInstant;
Expand Down Expand Up @@ -92,8 +92,8 @@ public SummaryData(
}
}

private final ImmutableConcurrentCache<ImmutableConcurrentCache.Pair<CalendarDay<Instant>>> schedulesCache =
new ImmutableConcurrentCache<>(10000, this::computeCalendarDay);
private final ReadOptimizedConcurrentCache<ReadOptimizedConcurrentCache.Pair<CalendarDay<Instant>>> schedulesCache =
new ReadOptimizedConcurrentCache<>(10000, this::computeCalendarDay);
private final YearMonthSummaryCache<SummaryData> summaryCache =
new YearMonthSummaryCache<>(this::computeMonthSummary, this::computeYearSummary);
private final int yearCacheStart;
Expand All @@ -112,26 +112,23 @@ private SummaryData summarize(final int key, final LocalDate startDate, final Lo

LocalDate date = startDate;
long businessTimeNanos = 0;
int days = 0;
int businessDays = 0;
int nonBusinessDays = 0;
final ArrayList<LocalDate> businessDates = new ArrayList<>();
final ArrayList<LocalDate> nonBusinessDates = new ArrayList<>();

while (date.isBefore(endDate)) {
final CalendarDay<Instant> bs = calendarDay(date);
final boolean ibd = bs.isBusinessDay();
days += 1;
businessDays += ibd ? 1 : 0;
nonBusinessDays += ibd ? 0 : 1;
businessTimeNanos += bs.businessNanos();

if (ibd) {
if (bs.isBusinessDay()) {
++businessDays;
businessDates.add(date);
} else {
++nonBusinessDays;
nonBusinessDates.add(date);
}

businessTimeNanos += bs.businessNanos();
date = date.plusDays(1);
}

Expand Down Expand Up @@ -228,7 +225,7 @@ static LocalDate schedulesCacheDateFromKey(final int key) {
return LocalDate.of(key / 10000, (key % 10000) / 100, key % 100);
}

private ImmutableConcurrentCache.Pair<CalendarDay<Instant>> computeCalendarDay(final int key) {
private ReadOptimizedConcurrentCache.Pair<CalendarDay<Instant>> computeCalendarDay(final int key) {
final LocalDate date = schedulesCacheDateFromKey(key);
final CalendarDay<Instant> h = holidays.get(date);
final CalendarDay<Instant> v;
Expand All @@ -241,7 +238,7 @@ private ImmutableConcurrentCache.Pair<CalendarDay<Instant>> computeCalendarDay(f
v = CalendarDay.toInstant(standardBusinessDay, date, timeZone());
}

return new ImmutableConcurrentCache.Pair<>(key, v);
return new ReadOptimizedConcurrentCache.Pair<>(key, v);
}

// endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class Calendar {

// region Cache

private static class SummaryData extends ImmutableConcurrentCache.IntKeyedValue {
private static class SummaryData extends ReadOptimizedConcurrentCache.IntKeyedValue {
final LocalDate startDate;
final LocalDate endDate; // exclusive
final List<LocalDate> dates;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
import java.util.function.IntFunction;

/**
* An immutable cache that is designed to be fast when accessed concurrently with read-heavy workloads. Values are
* populated from a function when they are not found in the cache. All values must be non-null.
* A cache that is designed to be fast when accessed concurrently with read-heavy workloads. Values are populated from a
* function when they are not found in the cache. All values must be non-null.
*
* @param <V> the value type
*/
class ImmutableConcurrentCache<V extends ImmutableConcurrentCache.IntKeyedValue> {
class ReadOptimizedConcurrentCache<V extends ReadOptimizedConcurrentCache.IntKeyedValue> {

/**
* A value that has an included integer key.
Expand Down Expand Up @@ -88,7 +88,7 @@ public int getIntKey(V v) {
* @param initialCapacity the initial capacity
* @param valueComputer computes the value for a key.
*/
public ImmutableConcurrentCache(final int initialCapacity, final IntFunction<V> valueComputer) {
public ReadOptimizedConcurrentCache(final int initialCapacity, final IntFunction<V> valueComputer) {
this.valueComputer = valueComputer;
this.cache = new KeyedIntObjectHash<>(initialCapacity, new KeyDef<>());
}
Expand All @@ -105,7 +105,7 @@ synchronized void clear() {
*
* @param key the key
* @return the value
* @throws IllegalArgumentException if the value is not found
* @throws NullPointerException if the value is not found
*/
public V computeIfAbsent(int key) {
V existing = cache.get(key);
Expand All @@ -117,10 +117,10 @@ public V computeIfAbsent(int key) {
final V newValue = valueComputer.apply(key);

if (newValue == null) {
throw new IllegalArgumentException("Computed a null value: key=" + key);
throw new NullPointerException("Computed a null value: key=" + key);
}

existing = cache.putIfAbsent(key, newValue);
existing = cache.put(key, newValue);
return existing == null ? newValue : existing;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
* @param <T> the type of the summary
*/
class YearMonthSummaryCache<T extends ImmutableConcurrentCache.IntKeyedValue> {
class YearMonthSummaryCache<T extends ReadOptimizedConcurrentCache.IntKeyedValue> {

/**
* Computes a year-month key for a year and month.
Expand Down Expand Up @@ -45,8 +45,8 @@ static int monthFromYearMonthKey(int key) {
return key % 100;
}

private final ImmutableConcurrentCache<T> monthCache;
private final ImmutableConcurrentCache<T> yearCache;
private final ReadOptimizedConcurrentCache<T> monthCache;
private final ReadOptimizedConcurrentCache<T> yearCache;

/**
* Creates a new cache.
Expand All @@ -55,8 +55,8 @@ static int monthFromYearMonthKey(int key) {
* @param computeYearSummary the function to compute a year summary
*/
YearMonthSummaryCache(IntFunction<T> computeMonthSummary, IntFunction<T> computeYearSummary) {
monthCache = new ImmutableConcurrentCache<>(12 * 50, computeMonthSummary);
yearCache = new ImmutableConcurrentCache<>(50, computeYearSummary);
monthCache = new ReadOptimizedConcurrentCache<>(12 * 50, computeMonthSummary);
yearCache = new ReadOptimizedConcurrentCache<>(50, computeYearSummary);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

import io.deephaven.base.testing.BaseArrayTestCase;

public class TestImmutableConcurrentCache extends BaseArrayTestCase {
public class TestReadOptimizedConcurrentCache extends BaseArrayTestCase {

private static class Value extends ImmutableConcurrentCache.Pair<String> {
private static class Value extends ReadOptimizedConcurrentCache.Pair<String> {
Value(int key, String value) {
super(key, value);
}
Expand All @@ -24,8 +24,8 @@ private static Value makeVal(Integer key) {
}

public void testCache() {
final ImmutableConcurrentCache<Value> cache =
new ImmutableConcurrentCache<>(10, TestImmutableConcurrentCache::makeVal);
final ReadOptimizedConcurrentCache<Value> cache =
new ReadOptimizedConcurrentCache<>(10, TestReadOptimizedConcurrentCache::makeVal);

assertEquals("A", cache.computeIfAbsent(0).getValue());
assertEquals("A", cache.computeIfAbsent(0).getValue());
Expand All @@ -37,7 +37,7 @@ public void testCache() {
try {
cache.computeIfAbsent(3);
fail("Expected exception");
} catch (final IllegalArgumentException e) {
} catch (final NullPointerException e) {
// pass
}

Expand All @@ -49,7 +49,7 @@ public void testCache() {
try {
cache.computeIfAbsent(3);
fail("Expected exception");
} catch (final IllegalArgumentException e) {
} catch (final NullPointerException e) {
// pass
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
@SuppressWarnings({"DataFlowIssue", "ConstantValue"})
public class TestYearMonthSummaryCache extends BaseArrayTestCase {

private static class Value extends ImmutableConcurrentCache.Pair<String> {
private static class Value extends ReadOptimizedConcurrentCache.Pair<String> {
Value(int key, String value) {
super(key, value);
}
Expand Down