update platform and gradle

This commit is contained in:
Carsten Otto
2025-02-16 13:45:35 +01:00
parent c79f920d1a
commit 6a84e71532
12 changed files with 64 additions and 25 deletions

View File

@@ -22,6 +22,7 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import static de.cotto.lndmanagej.configuration.PickhardtPaymentsConfigurationSettings.LIQUIDITY_INFORMATION_MAX_AGE; import static de.cotto.lndmanagej.configuration.PickhardtPaymentsConfigurationSettings.LIQUIDITY_INFORMATION_MAX_AGE;
@@ -34,6 +35,7 @@ public class LiquidityBoundsService {
private static final Duration DEFAULT_MAX_AGE = Duration.of(10, ChronoUnit.MINUTES); private static final Duration DEFAULT_MAX_AGE = Duration.of(10, ChronoUnit.MINUTES);
private final MissionControlService missionControlService; private final MissionControlService missionControlService;
private final Map<TwoPubkeys, LiquidityBoundsWithTimestamp> entries; private final Map<TwoPubkeys, LiquidityBoundsWithTimestamp> entries;
private final ReentrantLock entriesLock = new ReentrantLock();
private final ConfigurationService configurationService; private final ConfigurationService configurationService;
private final LoadingCache<Object, Duration> maxAgeCache = new CacheBuilder() private final LoadingCache<Object, Duration> maxAgeCache = new CacheBuilder()
.withRefresh(Duration.ofSeconds(5)) .withRefresh(Duration.ofSeconds(5))
@@ -107,9 +109,12 @@ public class LiquidityBoundsService {
BiFunction<LiquidityBounds, Coins, Optional<LiquidityBounds>> function BiFunction<LiquidityBounds, Coins, Optional<LiquidityBounds>> function
) { ) {
TwoPubkeys twoPubkeys = new TwoPubkeys(source, target); TwoPubkeys twoPubkeys = new TwoPubkeys(source, target);
synchronized (this.entries) { entriesLock.lock();
try {
Optional<LiquidityBounds> updated = function.apply(getInfo(twoPubkeys), amount); Optional<LiquidityBounds> updated = function.apply(getInfo(twoPubkeys), amount);
updated.ifPresent(liquidityBounds -> setInfo(twoPubkeys, liquidityBounds)); updated.ifPresent(liquidityBounds -> setInfo(twoPubkeys, liquidityBounds));
} finally {
entriesLock.unlock();
} }
} }

View File

@@ -122,7 +122,7 @@ public class OnlinePeersService {
} }
private int getRoundedPercentage(Duration total, Duration offline) { private int getRoundedPercentage(Duration total, Duration offline) {
return (int) (offline.getSeconds() * 100.0 / total.getSeconds()); return (int) (offline.toSeconds() * 100.0 / total.toSeconds());
} }
private int getChangesWithoutCache(Pubkey pubkey) { private int getChangesWithoutCache(Pubkey pubkey) {

View File

@@ -84,7 +84,7 @@ class BalancesDaoImpl implements BalancesDao {
if (!first || open) { if (!first || open) {
long satoshis = balances.balanceInformation().localBalance().satoshis(); long satoshis = balances.balanceInformation().localBalance().satoshis();
Duration duration = Duration.between(timestamp, previous); Duration duration = Duration.between(timestamp, previous);
long minutes = duration.getSeconds() / 60; long minutes = duration.toSeconds() / 60;
totalSatoshis += satoshis * minutes; totalSatoshis += satoshis * minutes;
totalMinutes += minutes; totalMinutes += minutes;
} }

View File

@@ -8,7 +8,7 @@ repositories {
dependencies { dependencies {
implementation(platform("de.c-otto.lndmanagej:platform")) implementation(platform("de.c-otto.lndmanagej:platform"))
implementation("de.c-otto:java-conventions:2024.06.07") implementation("de.c-otto:java-conventions:2025.02.16")
implementation("org.springframework.boot:spring-boot-gradle-plugin") implementation("org.springframework.boot:spring-boot-gradle-plugin")
implementation("com.google.protobuf:protobuf-gradle-plugin") implementation("com.google.protobuf:protobuf-gradle-plugin")
} }

View File

@@ -54,6 +54,6 @@ public class ForwardingEventsDaoImpl implements ForwardingEventsDao {
} }
private long getAfterEpochMilliSeconds(Duration maxAge) { private long getAfterEpochMilliSeconds(Duration maxAge) {
return Instant.now().toEpochMilli() - maxAge.getSeconds() * 1_000; return Instant.now().toEpochMilli() - maxAge.toSeconds() * 1_000;
} }
} }

View File

@@ -24,5 +24,6 @@ dependencies {
api("io.grpc:grpc-stub:$grpcVersion") api("io.grpc:grpc-stub:$grpcVersion")
api("org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion") api("org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion")
api("io.vavr:vavr:0.10.4") api("io.vavr:vavr:0.10.4")
api("javax.annotation:javax.annotation-api:1.3.2")
} }
} }

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@@ -76,6 +76,6 @@ public class SettledInvoicesDaoImpl implements SettledInvoicesDao {
} }
private long getAfterEpochSeconds(Duration maxAge) { private long getAfterEpochSeconds(Duration maxAge) {
return Instant.now().toEpochMilli() / 1_000 - maxAge.getSeconds(); return Instant.now().toEpochMilli() / 1_000 - maxAge.toSeconds();
} }
} }

View File

@@ -9,12 +9,13 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.OptionalLong; import java.util.OptionalLong;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
@Component @Component
public class Payments { public class Payments {
private final GrpcPayments grpcPayments; private final GrpcPayments grpcPayments;
private final PaymentsDao dao; private final PaymentsDao dao;
private static final Object SAVE_PAYMENTS_LOCK = new Object(); private static final ReentrantLock SAVE_PAYMENTS_LOCK = new ReentrantLock();
public Payments(GrpcPayments grpcPayments, PaymentsDao dao) { public Payments(GrpcPayments grpcPayments, PaymentsDao dao) {
this.grpcPayments = grpcPayments; this.grpcPayments = grpcPayments;
@@ -25,9 +26,12 @@ public class Payments {
public void loadNewSettledPayments() { public void loadNewSettledPayments() {
List<Payment> payments; List<Payment> payments;
do { do {
synchronized (SAVE_PAYMENTS_LOCK) { SAVE_PAYMENTS_LOCK.lock();
try {
payments = grpcPayments.getCompletePaymentsAfter(dao.getIndexOffset()).orElse(List.of()); payments = grpcPayments.getCompletePaymentsAfter(dao.getIndexOffset()).orElse(List.of());
dao.save(payments); dao.save(payments);
} finally {
SAVE_PAYMENTS_LOCK.unlock();
} }
} while (payments.size() == grpcPayments.getLimit()); } while (payments.size() == grpcPayments.getLimit());
} }
@@ -37,7 +41,8 @@ public class Payments {
List<Optional<Payment>> paymentOptionals; List<Optional<Payment>> paymentOptionals;
OptionalLong maxIndex; OptionalLong maxIndex;
do { do {
synchronized (SAVE_PAYMENTS_LOCK) { SAVE_PAYMENTS_LOCK.lock();
try {
long offsetSettledPayments = dao.getAllSettledIndexOffset(); long offsetSettledPayments = dao.getAllSettledIndexOffset();
long offsetKnownPayments = dao.getIndexOffset(); long offsetKnownPayments = dao.getIndexOffset();
if (offsetKnownPayments == offsetSettledPayments) { if (offsetKnownPayments == offsetSettledPayments) {
@@ -48,6 +53,8 @@ public class Payments {
maxIndex = getMaxIndexAllSettled(paymentOptionals); maxIndex = getMaxIndexAllSettled(paymentOptionals);
dao.save(paymentOptionals.stream().flatMap(Optional::stream).toList()); dao.save(paymentOptionals.stream().flatMap(Optional::stream).toList());
maxIndex.ifPresent(dao::setAllSettledIndexOffset); maxIndex.ifPresent(dao::setAllSettledIndexOffset);
} finally {
SAVE_PAYMENTS_LOCK.unlock();
} }
} while (paymentOptionals.size() == grpcPayments.getLimit() && maxIndex.isPresent()); } while (paymentOptionals.size() == grpcPayments.getLimit() && maxIndex.isPresent());
} }

View File

@@ -15,6 +15,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
public class PaymentStatus extends Flux<InstantWithString> { public class PaymentStatus extends Flux<InstantWithString> {
private boolean success; private boolean success;
@@ -22,6 +23,7 @@ public class PaymentStatus extends Flux<InstantWithString> {
private int numberOfAttemptedRoutes; private int numberOfAttemptedRoutes;
private final List<InstantWithString> allMessages; private final List<InstantWithString> allMessages;
private final List<PaymentStatusSubscription> subscriptions; private final List<PaymentStatusSubscription> subscriptions;
private final ReentrantLock lock = new ReentrantLock();
public PaymentStatus() { public PaymentStatus() {
super(); super();
@@ -42,26 +44,35 @@ public class PaymentStatus extends Flux<InstantWithString> {
} }
public void settled() { public void settled() {
synchronized (this) { lock.lock();
try {
addMessage("Settled"); addMessage("Settled");
success = true; success = true;
subscriptions.forEach(PaymentStatusSubscription::onComplete); subscriptions.forEach(PaymentStatusSubscription::onComplete);
} finally {
lock.unlock();
} }
} }
public void failed(FailureCode failureCode) { public void failed(FailureCode failureCode) {
synchronized (this) { lock.lock();
try {
addMessage("Failed with " + failureCode.toString()); addMessage("Failed with " + failureCode.toString());
failure = true; failure = true;
subscriptions.forEach(PaymentStatusSubscription::onComplete); subscriptions.forEach(PaymentStatusSubscription::onComplete);
} finally {
lock.unlock();
} }
} }
public void failed(String message) { public void failed(String message) {
synchronized (this) { lock.lock();
try {
addMessage(message); addMessage(message);
failure = true; failure = true;
subscriptions.forEach(PaymentStatusSubscription::onComplete); subscriptions.forEach(PaymentStatusSubscription::onComplete);
} finally {
lock.unlock();
} }
} }
@@ -93,9 +104,12 @@ public class PaymentStatus extends Flux<InstantWithString> {
private void addMessage(String message) { private void addMessage(String message) {
InstantWithString messageWithTimestamp = new InstantWithString(message); InstantWithString messageWithTimestamp = new InstantWithString(message);
synchronized (this) { lock.lock();
try {
allMessages.add(messageWithTimestamp); allMessages.add(messageWithTimestamp);
subscriptions.forEach(paymentStatusSubscription -> paymentStatusSubscription.onNext(messageWithTimestamp)); subscriptions.forEach(paymentStatusSubscription -> paymentStatusSubscription.onNext(messageWithTimestamp));
} finally {
lock.unlock();
} }
} }
@@ -133,9 +147,12 @@ public class PaymentStatus extends Flux<InstantWithString> {
public void subscribe(@Nonnull CoreSubscriber<? super InstantWithString> subscriber) { public void subscribe(@Nonnull CoreSubscriber<? super InstantWithString> subscriber) {
PaymentStatusSubscription subscription = PaymentStatusSubscription subscription =
new PaymentStatusSubscription(subscriber, new ArrayList<>(allMessages)); new PaymentStatusSubscription(subscriber, new ArrayList<>(allMessages));
synchronized (this) { lock.lock();
try {
subscriber.onSubscribe(subscription); subscriber.onSubscribe(subscription);
subscriptions.add(subscription); subscriptions.add(subscription);
} finally {
lock.unlock();
} }
if (isFailure() || isSuccess()) { if (isFailure() || isSuccess()) {
subscription.onComplete(); subscription.onComplete();
@@ -164,6 +181,7 @@ public class PaymentStatus extends Flux<InstantWithString> {
} }
private class PaymentStatusSubscription implements Subscription { private class PaymentStatusSubscription implements Subscription {
private final ReentrantLock lock = new ReentrantLock();
private final Subscriber<? super InstantWithString> subscriber; private final Subscriber<? super InstantWithString> subscriber;
private final List<InstantWithString> messagesForSubscriber; private final List<InstantWithString> messagesForSubscriber;
private long requested; private long requested;
@@ -179,9 +197,12 @@ public class PaymentStatus extends Flux<InstantWithString> {
@Override @Override
public void request(long numberOfMessages) { public void request(long numberOfMessages) {
synchronized (this) { lock.lock();
try {
requested += numberOfMessages; requested += numberOfMessages;
sendRequestedMessages(); sendRequestedMessages();
} finally {
lock.unlock();
} }
} }
@@ -199,9 +220,12 @@ public class PaymentStatus extends Flux<InstantWithString> {
} }
public void onNext(InstantWithString message) { public void onNext(InstantWithString message) {
synchronized (this) { lock.lock();
try {
messagesForSubscriber.add(message); messagesForSubscriber.add(message);
sendRequestedMessages(); sendRequestedMessages();
} finally {
lock.unlock();
} }
} }

View File

@@ -14,6 +14,7 @@ import org.junit.jupiter.api.Test;
import java.time.Instant; import java.time.Instant;
import java.util.List; import java.util.List;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;
import static de.cotto.lndmanagej.ReactiveStreamReader.readAll; import static de.cotto.lndmanagej.ReactiveStreamReader.readAll;
import static de.cotto.lndmanagej.ReactiveStreamReader.readMessages; import static de.cotto.lndmanagej.ReactiveStreamReader.readMessages;
@@ -248,6 +249,10 @@ class PaymentStatusTest {
@Test @Test
void testEquals() { void testEquals() {
EqualsVerifier.simple().forClass(PaymentStatus.class).verify(); EqualsVerifier.simple()
.forClass(PaymentStatus.class)
.withPrefabValues(ReentrantLock.class, new ReentrantLock(), new ReentrantLock())
.withIgnoredFields("lock")
.verify();
} }
} }

View File

@@ -14,7 +14,8 @@ public record BalanceInformationModel(
) { ) {
private static final int TEN_PERCENT = 10; private static final int TEN_PERCENT = 10;
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("###"); private static final ThreadLocal<DecimalFormat> DECIMAL_FORMAT =
ThreadLocal.withInitial(() -> new DecimalFormat("###"));
public static final BalanceInformationModel EMPTY = createFromModel(BalanceInformation.EMPTY); public static final BalanceInformationModel EMPTY = createFromModel(BalanceInformation.EMPTY);
public static BalanceInformationModel createFromModel(BalanceInformation balanceInformation) { public static BalanceInformationModel createFromModel(BalanceInformation balanceInformation) {
@@ -44,15 +45,11 @@ public record BalanceInformationModel(
public String getOutboundPercentageLabel() { public String getOutboundPercentageLabel() {
double outbound = getOutboundPercentage(); double outbound = getOutboundPercentage();
synchronized (DECIMAL_FORMAT) { return outbound < TEN_PERCENT ? "" : DECIMAL_FORMAT.get().format(outbound) + "%";
return outbound < TEN_PERCENT ? "" : DECIMAL_FORMAT.format(outbound) + "%";
}
} }
public String getInboundPercentageLabel() { public String getInboundPercentageLabel() {
double inbound = getInboundPercentage(); double inbound = getInboundPercentage();
synchronized (DECIMAL_FORMAT) { return inbound < TEN_PERCENT ? "" : DECIMAL_FORMAT.get().format(inbound) + "%";
return inbound < TEN_PERCENT ? "" : DECIMAL_FORMAT.format(inbound) + "%";
}
} }
} }