23
23
import java .util .ArrayList ;
24
24
import java .util .Collection ;
25
25
import java .util .HashMap ;
26
+ import java .util .HashSet ;
26
27
import java .util .List ;
27
28
import java .util .Map ;
28
29
import java .util .Objects ;
30
+ import java .util .Set ;
29
31
import java .util .TreeMap ;
30
32
import java .util .concurrent .atomic .AtomicBoolean ;
31
33
import java .util .concurrent .atomic .AtomicLong ;
32
34
33
35
import org .apache .accumulo .core .dataImpl .KeyExtent ;
36
+ import org .apache .accumulo .core .metadata .schema .Ample ;
34
37
import org .apache .accumulo .core .metadata .schema .TabletMetadata ;
35
38
import org .apache .accumulo .core .spi .compaction .CompactionJob ;
36
39
import org .apache .accumulo .core .spi .compaction .CompactorGroupId ;
37
40
import org .apache .accumulo .core .util .compaction .CompactionJobPrioritizer ;
41
+ import org .slf4j .Logger ;
42
+ import org .slf4j .LoggerFactory ;
38
43
39
44
import com .google .common .base .Preconditions ;
40
45
49
54
*/
50
55
public class CompactionJobPriorityQueue {
51
56
57
+ private static final Logger log = LoggerFactory .getLogger (CompactionJobPriorityQueue .class );
58
+
52
59
private final CompactorGroupId groupId ;
53
60
54
61
private class CjpqKey implements Comparable <CjpqKey > {
@@ -99,9 +106,19 @@ public boolean equals(Object o) {
99
106
private final AtomicLong rejectedJobs ;
100
107
private final AtomicLong dequeuedJobs ;
101
108
109
+ private static class TabletJobs {
110
+ final long generation ;
111
+ final HashSet <CjpqKey > jobs ;
112
+
113
+ private TabletJobs (long generation , HashSet <CjpqKey > jobs ) {
114
+ this .generation = generation ;
115
+ this .jobs = jobs ;
116
+ }
117
+ }
118
+
102
119
// This map tracks what jobs a tablet currently has in the queue. Its used to efficiently remove
103
120
// jobs in the queue when new jobs are queued for a tablet.
104
- private final Map <KeyExtent ,List < CjpqKey > > tabletJobs ;
121
+ private final Map <KeyExtent ,TabletJobs > tabletJobs ;
105
122
106
123
private final AtomicLong nextSeq = new AtomicLong (0 );
107
124
@@ -116,24 +133,46 @@ public CompactionJobPriorityQueue(CompactorGroupId groupId, int maxSize) {
116
133
this .dequeuedJobs = new AtomicLong (0 );
117
134
}
118
135
136
+ public synchronized void removeOlderGenerations (Ample .DataLevel level , long currGeneration ) {
137
+ if (closed .get ()) {
138
+ return ;
139
+ }
140
+
141
+ List <KeyExtent > removals = new ArrayList <>();
142
+
143
+ tabletJobs .forEach ((extent , jobs ) -> {
144
+ if (Ample .DataLevel .of (extent .tableId ()) == level && jobs .generation < currGeneration ) {
145
+ removals .add (extent );
146
+ }
147
+ });
148
+
149
+ if (!removals .isEmpty ()) {
150
+ log .trace ("Removed {} queued tablets that no longer need compaction for {} {}" ,
151
+ removals .size (), groupId , level );
152
+ }
153
+
154
+ removals .forEach (this ::removePreviousSubmissions );
155
+ }
156
+
119
157
/**
120
158
* @return the number of jobs added. If the queue is closed returns -1
121
159
*/
122
- public synchronized int add (TabletMetadata tabletMetadata , Collection <CompactionJob > jobs ) {
160
+ public synchronized int add (TabletMetadata tabletMetadata , Collection <CompactionJob > jobs ,
161
+ long generation ) {
123
162
Preconditions .checkArgument (jobs .stream ().allMatch (job -> job .getGroup ().equals (groupId )));
124
163
if (closed .get ()) {
125
164
return -1 ;
126
165
}
127
166
128
167
removePreviousSubmissions (tabletMetadata .getExtent ());
129
168
130
- List <CjpqKey > newEntries = new ArrayList <>(jobs .size ());
169
+ HashSet <CjpqKey > newEntries = new HashSet <>(jobs .size ());
131
170
132
171
int jobsAdded = 0 ;
133
172
for (CompactionJob job : jobs ) {
134
173
CjpqKey cjqpKey = addJobToQueue (tabletMetadata , job );
135
174
if (cjqpKey != null ) {
136
- newEntries .add (cjqpKey );
175
+ checkState ( newEntries .add (cjqpKey ) );
137
176
jobsAdded ++;
138
177
} else {
139
178
// The priority for this job was lower than all other priorities and not added
@@ -143,7 +182,8 @@ public synchronized int add(TabletMetadata tabletMetadata, Collection<Compaction
143
182
}
144
183
145
184
if (!newEntries .isEmpty ()) {
146
- checkState (tabletJobs .put (tabletMetadata .getExtent (), newEntries ) == null );
185
+ checkState (tabletJobs .put (tabletMetadata .getExtent (), new TabletJobs (generation , newEntries ))
186
+ == null );
147
187
}
148
188
149
189
return jobsAdded ;
@@ -178,7 +218,7 @@ public synchronized CompactionJobQueues.MetaJob poll() {
178
218
if (first != null ) {
179
219
dequeuedJobs .getAndIncrement ();
180
220
var extent = first .getValue ().getTabletMetadata ().getExtent ();
181
- List <CjpqKey > jobs = tabletJobs .get (extent );
221
+ Set <CjpqKey > jobs = tabletJobs .get (extent ). jobs ;
182
222
checkState (jobs .remove (first .getKey ()));
183
223
if (jobs .isEmpty ()) {
184
224
tabletJobs .remove (extent );
@@ -207,9 +247,9 @@ public synchronized boolean closeIfEmpty() {
207
247
}
208
248
209
249
private void removePreviousSubmissions (KeyExtent extent ) {
210
- List < CjpqKey > prevJobs = tabletJobs .get (extent );
250
+ TabletJobs prevJobs = tabletJobs .get (extent );
211
251
if (prevJobs != null ) {
212
- prevJobs .forEach (jobQueue ::remove );
252
+ prevJobs .jobs . forEach (jobQueue ::remove );
213
253
tabletJobs .remove (extent );
214
254
}
215
255
}
0 commit comments