mirror of https://github.com/apache/kafka.git
KAFKA-18918: Correcting releasing of locks on exception (#19091)
The PR corrects the way the locks are released on exception. As `partitionsAcquired` can be a reference to `topicPartitionData`, hence the locks should released prior clearing `partitionsAcquired`. Reviewers: Abhinav Dixit <adixit@confluent.io>, Andrew Schofield <aschofield@confluent.io>
This commit is contained in:
parent
c2014c02b1
commit
c1fc59fc23
|
@ -277,9 +277,9 @@ public class DelayedShareFetch extends DelayedOperation {
|
||||||
return false;
|
return false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error processing delayed share fetch request", e);
|
log.error("Error processing delayed share fetch request", e);
|
||||||
|
releasePartitionLocks(topicPartitionData.keySet());
|
||||||
partitionsAcquired.clear();
|
partitionsAcquired.clear();
|
||||||
partitionsAlreadyFetched.clear();
|
partitionsAlreadyFetched.clear();
|
||||||
releasePartitionLocks(topicPartitionData.keySet());
|
|
||||||
return forceComplete();
|
return forceComplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
|
@ -725,6 +726,7 @@ public class DelayedShareFetchTest {
|
||||||
Mockito.verify(replicaManager, times(1)).readFromLog(
|
Mockito.verify(replicaManager, times(1)).readFromLog(
|
||||||
any(), any(), any(ReplicaQuota.class), anyBoolean());
|
any(), any(), any(ReplicaQuota.class), anyBoolean());
|
||||||
Mockito.verify(delayedShareFetch, times(1)).releasePartitionLocks(any());
|
Mockito.verify(delayedShareFetch, times(1)).releasePartitionLocks(any());
|
||||||
|
Mockito.verify(sp0, times(1)).releaseFetchLock();
|
||||||
|
|
||||||
// Force complete the request as it's still pending. Return false from the share partition lock acquire.
|
// Force complete the request as it's still pending. Return false from the share partition lock acquire.
|
||||||
when(sp0.maybeAcquireFetchLock()).thenReturn(false);
|
when(sp0.maybeAcquireFetchLock()).thenReturn(false);
|
||||||
|
@ -747,6 +749,44 @@ public class DelayedShareFetchTest {
|
||||||
Mockito.verify(exceptionHandler, times(1)).accept(any(), any());
|
Mockito.verify(exceptionHandler, times(1)).accept(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTryCompleteLocksReleasedOnCompleteException() {
|
||||||
|
ReplicaManager replicaManager = mock(ReplicaManager.class);
|
||||||
|
TopicIdPartition tp0 = new TopicIdPartition(Uuid.randomUuid(), new TopicPartition("foo", 0));
|
||||||
|
LinkedHashMap<TopicIdPartition, Integer> partitionMaxBytes = orderedMap(PARTITION_MAX_BYTES, tp0);
|
||||||
|
|
||||||
|
SharePartition sp0 = mock(SharePartition.class);
|
||||||
|
when(sp0.maybeAcquireFetchLock()).thenReturn(true);
|
||||||
|
when(sp0.canAcquireRecords()).thenReturn(true);
|
||||||
|
when(sp0.fetchOffsetMetadata(anyLong())).thenReturn(Optional.of(new LogOffsetMetadata(0, 1, 0)));
|
||||||
|
|
||||||
|
LinkedHashMap<TopicIdPartition, SharePartition> sharePartitions = new LinkedHashMap<>();
|
||||||
|
sharePartitions.put(tp0, sp0);
|
||||||
|
|
||||||
|
ShareFetch shareFetch = new ShareFetch(FETCH_PARAMS, "grp", Uuid.randomUuid().toString(),
|
||||||
|
new CompletableFuture<>(), partitionMaxBytes, BATCH_SIZE, MAX_FETCH_RECORDS,
|
||||||
|
BROKER_TOPIC_STATS);
|
||||||
|
|
||||||
|
doAnswer(invocation -> buildLogReadResult(Collections.singleton(tp0))).when(replicaManager).readFromLog(any(), any(), any(ReplicaQuota.class), anyBoolean());
|
||||||
|
mockTopicIdPartitionToReturnDataEqualToMinBytes(replicaManager, tp0, 1);
|
||||||
|
|
||||||
|
PartitionMaxBytesStrategy partitionMaxBytesStrategy = mockPartitionMaxBytes(Collections.singleton(tp0));
|
||||||
|
DelayedShareFetch delayedShareFetch = spy(DelayedShareFetchBuilder.builder()
|
||||||
|
.withShareFetchData(shareFetch)
|
||||||
|
.withSharePartitions(sharePartitions)
|
||||||
|
.withReplicaManager(replicaManager)
|
||||||
|
.withPartitionMaxBytesStrategy(partitionMaxBytesStrategy)
|
||||||
|
.build());
|
||||||
|
assertFalse(delayedShareFetch.isCompleted());
|
||||||
|
// Throw exception for onComplete.
|
||||||
|
doThrow(new RuntimeException()).when(delayedShareFetch).onComplete();
|
||||||
|
// Try to complete the request.
|
||||||
|
assertFalse(delayedShareFetch.tryComplete());
|
||||||
|
|
||||||
|
Mockito.verify(delayedShareFetch, times(1)).releasePartitionLocks(any());
|
||||||
|
Mockito.verify(sp0, times(1)).releaseFetchLock();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocksReleasedForCompletedFetch() {
|
public void testLocksReleasedForCompletedFetch() {
|
||||||
String groupId = "grp";
|
String groupId = "grp";
|
||||||
|
|
Loading…
Reference in New Issue