1717
1818package org .apache .ignite .internal .placementdriver ;
1919
20+ import static java .util .Collections .emptyMap ;
2021import static java .util .Objects .hash ;
2122import static java .util .Objects .requireNonNullElse ;
2223import static java .util .concurrent .CompletableFuture .completedFuture ;
24+ import static java .util .concurrent .TimeUnit .MILLISECONDS ;
2325import static org .apache .ignite .internal .hlc .HybridTimestamp .NULL_HYBRID_TIMESTAMP ;
2426import static org .apache .ignite .internal .metastorage .dsl .Conditions .notExists ;
2527import static org .apache .ignite .internal .metastorage .dsl .Conditions .or ;
2830import static org .apache .ignite .internal .metastorage .dsl .Operations .put ;
2931import static org .apache .ignite .internal .placementdriver .PlacementDriverManager .PLACEMENTDRIVER_LEASES_KEY ;
3032import static org .apache .ignite .internal .placementdriver .leases .Lease .emptyLease ;
33+ import static org .apache .ignite .internal .util .ArrayUtils .BYTE_EMPTY_ARRAY ;
3134import static org .apache .ignite .internal .util .CollectionUtils .union ;
3235import static org .apache .ignite .internal .util .CompletableFutures .nullCompletedFuture ;
3336import static org .apache .ignite .internal .util .ExceptionUtils .hasCause ;
37+ import static org .apache .ignite .internal .util .IgniteUtils .newHashMap ;
3438
3539import java .util .ArrayList ;
3640import java .util .Collection ;
@@ -135,6 +139,14 @@ public class LeaseUpdater {
135139
136140 private final Executor throttledLogExecutor ;
137141
142+ private CompletableFuture <?> leaseUpdateFuture = nullCompletedFuture ();
143+
144+ /**
145+ * Leases cache for updating leases via {@link MetaStorageManager#invoke}. It is renewed right before the lease update, because leases
146+ * in {@link LeaseTracker} may be stale a bit, which is critical for invoke.
147+ */
148+ private volatile Leases leases = new Leases (emptyMap (), BYTE_EMPTY_ARRAY );
149+
138150 /**
139151 * Constructor.
140152 *
@@ -388,6 +400,8 @@ public void run() {
388400
389401 try {
390402 if (active ()) {
403+ waitForInflight ();
404+
391405 updateLeaseBatchInternal ();
392406 }
393407 } catch (Throwable e ) {
@@ -408,6 +422,28 @@ public void run() {
408422 }
409423 }
410424
425+ private void waitForInflight () {
426+ try {
427+ leaseUpdateFuture .get (replicationConfiguration .leaseExpirationIntervalMillis ().value () / 2 , MILLISECONDS );
428+ } catch (Exception e ) {
429+ LOG .info ("Could not wait for the previous lease update to complete, proceeding with the next update attempt." , e );
430+ }
431+
432+ var entry = msManager .getLocally (PLACEMENTDRIVER_LEASES_KEY );
433+
434+ if (entry != null && entry .value () != null ) {
435+ LeaseBatch leaseBatch = LeaseBatch .fromBytes (entry .value ());
436+ Map <ReplicationGroupId , Lease > newLeasesMap = newHashMap (leaseBatch .leases ().size ());
437+ for (Lease lease : leaseBatch .leases ()) {
438+ newLeasesMap .put (lease .replicationGroupId (), lease );
439+ }
440+
441+ leases = new Leases (newLeasesMap , entry .value ());
442+ } else {
443+ leases = leaseTracker .leasesLatest ();
444+ }
445+ }
446+
411447 /** Updates leases in Meta storage. This method is supposed to be used in the busy lock. */
412448 private void updateLeaseBatchInternal () {
413449 HybridTimestamp currentTime = clockService .current ();
@@ -418,7 +454,7 @@ private void updateLeaseBatchInternal() {
418454
419455 HybridTimestamp newExpirationTimestamp = new HybridTimestamp (currentTime .getPhysical () + leaseExpirationInterval , 0 );
420456
421- Leases leasesCurrent = leaseTracker . leasesLatest () ;
457+ Leases leasesCurrent = leases ;
422458 Map <ReplicationGroupId , LeaseAgreement > toBeNegotiated = new HashMap <>();
423459 Map <ReplicationGroupId , Lease > renewedLeases = new HashMap <>(leasesCurrent .leaseByGroupId ().size ());
424460
@@ -505,11 +541,12 @@ private void updateLeaseBatchInternal() {
505541 // so we must start a negotiation round from the beginning; the same we do for the groups that don't have
506542 // leaseholders at all.
507543 if (isLeaseOutdated ) {
508- LOG .info ("Lease is expired, creating a new one [groupId={}, lease={}, candidate={}]" , grpId , lease , candidate );
509-
510544 // New lease is granted.
511545 Lease newLease = writeNewLease (grpId , candidate , renewedLeases );
512546
547+ LOG .info ("Lease is expired, creating a new one [groupId={}, oldLease={}, newLease={}, candidate={}]" ,
548+ grpId , lease , newLease , candidate );
549+
513550 boolean force = !lease .isProlongable () && lease .proposedCandidate () != null ;
514551
515552 toBeNegotiated .put (grpId , new LeaseAgreement (newLease , force ));
@@ -553,7 +590,7 @@ private void updateLeaseBatchInternal() {
553590
554591 byte [] renewedValue = new LeaseBatch (renewedLeases .values ()).bytes ();
555592
556- msManager .invoke (
593+ leaseUpdateFuture = msManager .invoke (
557594 or (notExists (key ), value (key ).eq (leasesCurrent .leasesBytes ())),
558595 put (key , renewedValue ),
559596 noop ()
0 commit comments