|
16 | 16 | */
|
17 | 17 | package org.apache.activemq.artemis.core.paging.impl;
|
18 | 18 |
|
| 19 | +import java.lang.invoke.MethodHandles; |
| 20 | +import java.util.ArrayList; |
19 | 21 | import java.util.LinkedList;
|
20 | 22 | import java.util.List;
|
| 23 | +import java.util.Queue; |
| 24 | +import java.util.concurrent.ConcurrentLinkedQueue; |
21 | 25 | import java.util.concurrent.Executor;
|
22 | 26 | import java.util.concurrent.ScheduledExecutorService;
|
23 | 27 | import java.util.concurrent.TimeUnit;
|
24 | 28 |
|
25 | 29 | import org.apache.activemq.artemis.api.core.ActiveMQExceptionType;
|
| 30 | +import org.apache.activemq.artemis.core.paging.PagedMessage; |
26 | 31 | import org.apache.activemq.artemis.core.paging.PagingStore;
|
27 | 32 | import org.apache.activemq.artemis.core.persistence.OperationContext;
|
28 | 33 | import org.apache.activemq.artemis.core.server.ActiveMQScheduledComponent;
|
| 34 | +import org.apache.activemq.artemis.core.server.RouteContextList; |
| 35 | +import org.apache.activemq.artemis.core.transaction.Transaction; |
| 36 | +import org.slf4j.Logger; |
| 37 | +import org.slf4j.LoggerFactory; |
29 | 38 |
|
30 | 39 | /**
|
| 40 | + * |
| 41 | + * TODO: remove this |
31 | 42 | * This will batch multiple calls waiting to perform a sync in a single call.
|
32 | 43 | */
|
33 | 44 | final class PageSyncTimer extends ActiveMQScheduledComponent {
|
34 | 45 |
|
| 46 | + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); |
35 | 47 |
|
| 48 | + private final PagingStoreImpl store; |
36 | 49 |
|
37 |
| - private final PagingStore store; |
38 | 50 |
|
39 |
| - private final ScheduledExecutorService scheduledExecutor; |
| 51 | + protected final List<PageEvent> pageEvents = new ArrayList<>(); |
40 | 52 |
|
41 |
| - private boolean pendingSync; |
| 53 | + public boolean hasPendingIO() { |
| 54 | + return !pageEvents.isEmpty(); |
| 55 | + } |
42 | 56 |
|
43 |
| - private final long timeSync; |
44 | 57 |
|
45 |
| - private final Runnable runnable = this::tick; |
| 58 | + public static class PageEvent { |
| 59 | + PageEvent(OperationContext context, PagedMessage message, Transaction tx, RouteContextList listCtx) { |
| 60 | + this.context = context; |
| 61 | + this.message = message; |
| 62 | + this.listCtx = listCtx; |
| 63 | + this.tx = tx; |
| 64 | + } |
46 | 65 |
|
47 |
| - private final List<OperationContext> syncOperations = new LinkedList<>(); |
| 66 | + PagedMessage message; |
| 67 | + OperationContext context; |
| 68 | + RouteContextList listCtx; |
| 69 | + Transaction tx; |
| 70 | + } |
48 | 71 |
|
49 | 72 |
|
50 |
| - PageSyncTimer(PagingStore store, ScheduledExecutorService scheduledExecutor, Executor executor, long timeSync) { |
| 73 | + PageSyncTimer(PagingStoreImpl store, ScheduledExecutorService scheduledExecutor, Executor executor, long timeSync) { |
51 | 74 | super(scheduledExecutor, executor, timeSync, TimeUnit.NANOSECONDS, true);
|
52 | 75 | this.store = store;
|
53 |
| - this.scheduledExecutor = scheduledExecutor; |
54 |
| - this.timeSync = timeSync; |
55 | 76 | }
|
56 | 77 |
|
57 | 78 |
|
58 |
| - synchronized void addSync(OperationContext ctx) { |
59 |
| - ctx.pageSyncLineUp(); |
60 |
| - if (!pendingSync) { |
61 |
| - pendingSync = true; |
62 |
| - |
63 |
| - delay(); |
64 |
| - } |
65 |
| - syncOperations.add(ctx); |
| 79 | + public synchronized void addTask(OperationContext context, PagedMessage message, Transaction tx, RouteContextList listCtx) { |
| 80 | + PageEvent event = new PageEvent(context, message, tx, listCtx); |
| 81 | + context.storeLineUp(); |
| 82 | + this.pageEvents.add(event); |
| 83 | + delay(); |
66 | 84 | }
|
67 | 85 |
|
| 86 | + |
68 | 87 | @Override
|
69 | 88 | public void run() {
|
70 | 89 | tick();
|
71 | 90 | }
|
72 | 91 |
|
73 |
| - private void tick() { |
74 |
| - OperationContext[] pendingSyncsArray; |
| 92 | + private PageEvent[] extractPendingEvents() { |
75 | 93 | synchronized (this) {
|
| 94 | + if (pageEvents.isEmpty()) { |
| 95 | + return null; |
| 96 | + } |
| 97 | + PageEvent[] pendingsWrites = new PageEvent[pageEvents.size()]; |
| 98 | + pendingsWrites = pageEvents.toArray(pendingsWrites); |
| 99 | + pageEvents.clear(); |
| 100 | + return pendingsWrites; |
| 101 | + } |
| 102 | + } |
76 | 103 |
|
77 |
| - pendingSync = false; |
78 |
| - pendingSyncsArray = new OperationContext[syncOperations.size()]; |
79 |
| - pendingSyncsArray = syncOperations.toArray(pendingSyncsArray); |
80 |
| - syncOperations.clear(); |
| 104 | + private void tick() { |
| 105 | + PageEvent[] pendingEvents = extractPendingEvents(); |
| 106 | + if (pendingEvents == null) { |
| 107 | + return; |
81 | 108 | }
|
82 | 109 |
|
83 | 110 | try {
|
84 |
| - if (pendingSyncsArray.length != 0) { |
| 111 | + |
| 112 | + for (PageEvent event : pendingEvents) { |
| 113 | + store.writePageCallback(event.message, event.tx, event.listCtx); |
| 114 | + } |
| 115 | + |
| 116 | + try { |
85 | 117 | store.ioSync();
|
| 118 | + } catch (Exception e) { |
| 119 | + // TODO - do not merge this TODO - critical error here, server should shutdown |
| 120 | + logger.warn(e.getMessage(), e); |
86 | 121 | }
|
| 122 | + |
| 123 | + |
87 | 124 | } catch (Exception e) {
|
88 |
| - for (OperationContext ctx : pendingSyncsArray) { |
89 |
| - ctx.onError(ActiveMQExceptionType.IO_ERROR.getCode(), e.getClass() + " during ioSync for paging on " + store.getStoreName() + ": " + e.getMessage()); |
| 125 | + for (PageEvent event : pendingEvents) { |
| 126 | + event.context.onError(ActiveMQExceptionType.IO_ERROR.getCode(), e.getClass() + " during ioSync for paging on " + store.getStoreName() + ": " + e.getMessage()); |
90 | 127 | }
|
91 | 128 | } finally {
|
92 | 129 | // In case of failure, The context should propagate an exception to the client
|
93 | 130 | // We send an exception to the client even on the case of a failure
|
94 | 131 | // to avoid possible locks and the client not getting the exception back
|
95 |
| - for (OperationContext ctx : pendingSyncsArray) { |
96 |
| - ctx.pageSyncDone(); |
| 132 | + for (PageEvent event : pendingEvents) { |
| 133 | + event.context.done(); |
97 | 134 | }
|
98 | 135 | }
|
99 | 136 | }
|
|
0 commit comments