1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.regionserver;
20
21 import static org.apache.hadoop.hbase.executor.EventType.RS_ZK_REQUEST_REGION_SPLIT;
22 import static org.apache.hadoop.hbase.executor.EventType.RS_ZK_REGION_SPLIT;
23 import static org.apache.hadoop.hbase.executor.EventType.RS_ZK_REGION_SPLITTING;
24
25 import java.io.IOException;
26 import java.io.InterruptedIOException;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.ListIterator;
30 import java.util.Map;
31 import java.util.concurrent.Callable;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.Executors;
34 import java.util.concurrent.Future;
35 import java.util.concurrent.ThreadFactory;
36 import java.util.concurrent.ThreadPoolExecutor;
37 import java.util.concurrent.TimeUnit;
38
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41 import org.apache.hadoop.hbase.classification.InterfaceAudience;
42 import org.apache.hadoop.hbase.HConstants;
43 import org.apache.hadoop.hbase.HRegionInfo;
44 import org.apache.hadoop.hbase.RegionTransition;
45 import org.apache.hadoop.hbase.Server;
46 import org.apache.hadoop.hbase.ServerName;
47 import org.apache.hadoop.hbase.catalog.CatalogTracker;
48 import org.apache.hadoop.hbase.catalog.MetaEditor;
49 import org.apache.hadoop.hbase.client.Mutation;
50 import org.apache.hadoop.hbase.client.Put;
51 import org.apache.hadoop.hbase.executor.EventType;
52 import org.apache.hadoop.hbase.protobuf.generated.RegionServerStatusProtos.RegionTransition.TransitionCode;
53 import org.apache.hadoop.hbase.util.Bytes;
54 import org.apache.hadoop.hbase.util.CancelableProgressable;
55 import org.apache.hadoop.hbase.util.ConfigUtil;
56 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
57 import org.apache.hadoop.hbase.util.HasThread;
58 import org.apache.hadoop.hbase.util.PairOfSameType;
59 import org.apache.hadoop.hbase.zookeeper.ZKAssign;
60 import org.apache.hadoop.hbase.zookeeper.ZKUtil;
61 import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
62 import org.apache.zookeeper.KeeperException;
63 import org.apache.zookeeper.KeeperException.NodeExistsException;
64 import org.apache.zookeeper.data.Stat;
65
66 import com.google.common.util.concurrent.ThreadFactoryBuilder;
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 @InterfaceAudience.Private
92 public class SplitTransaction {
93 private static final Log LOG = LogFactory.getLog(SplitTransaction.class);
94
95
96
97
98 private final HRegion parent;
99 private HRegionInfo hri_a;
100 private HRegionInfo hri_b;
101 private long fileSplitTimeout = 30000;
102 private int znodeVersion = -1;
103 boolean useZKForAssignment;
104
105
106
107
108 private final byte [] splitrow;
109
110
111
112
113
114
115 enum JournalEntry {
116
117
118
119 SET_SPLITTING_IN_ZK,
120
121
122
123 CREATE_SPLIT_DIR,
124
125
126
127 CLOSED_PARENT_REGION,
128
129
130
131 OFFLINED_PARENT,
132
133
134
135 STARTED_REGION_A_CREATION,
136
137
138
139 STARTED_REGION_B_CREATION,
140
141
142
143
144
145 PONR
146 }
147
148
149
150
151 private final List<JournalEntry> journal = new ArrayList<JournalEntry>();
152
153
154
155
156
157
158 public SplitTransaction(final HRegion r, final byte [] splitrow) {
159 this.parent = r;
160 this.splitrow = splitrow;
161 }
162
163
164
165
166
167
168 public boolean prepare() {
169 if (!this.parent.isSplittable()) return false;
170
171 if (this.splitrow == null) return false;
172 HRegionInfo hri = this.parent.getRegionInfo();
173 parent.prepareToSplit();
174
175 byte [] startKey = hri.getStartKey();
176 byte [] endKey = hri.getEndKey();
177 if (Bytes.equals(startKey, splitrow) ||
178 !this.parent.getRegionInfo().containsRow(splitrow)) {
179 LOG.info("Split row is not inside region key range or is equal to " +
180 "startkey: " + Bytes.toStringBinary(this.splitrow));
181 return false;
182 }
183 long rid = getDaughterRegionIdTimestamp(hri);
184 this.hri_a = new HRegionInfo(hri.getTable(), startKey, this.splitrow, false, rid);
185 this.hri_b = new HRegionInfo(hri.getTable(), this.splitrow, endKey, false, rid);
186 return true;
187 }
188
189
190
191
192
193
194 private static long getDaughterRegionIdTimestamp(final HRegionInfo hri) {
195 long rid = EnvironmentEdgeManager.currentTimeMillis();
196
197
198 if (rid < hri.getRegionId()) {
199 LOG.warn("Clock skew; parent regions id is " + hri.getRegionId() +
200 " but current time here is " + rid);
201 rid = hri.getRegionId() + 1;
202 }
203 return rid;
204 }
205
206 private static IOException closedByOtherException = new IOException(
207 "Failed to close region: already closed by another thread");
208
209
210
211
212
213
214
215
216
217
218
219 final RegionServerServices services) throws IOException {
220 LOG.info("Starting split of region " + this.parent);
221 if ((server != null && server.isStopped()) ||
222 (services != null && services.isStopping())) {
223 throw new IOException("Server is stopped or stopping");
224 }
225 assert !this.parent.lock.writeLock().isHeldByCurrentThread():
226 "Unsafe to hold write lock while performing RPCs";
227
228
229 if (this.parent.getCoprocessorHost() != null) {
230 this.parent.getCoprocessorHost().preSplit();
231 }
232
233
234 if (this.parent.getCoprocessorHost() != null) {
235 this.parent.getCoprocessorHost().preSplit(this.splitrow);
236 }
237
238
239 boolean testing = server == null? true:
240 server.getConfiguration().getBoolean("hbase.testing.nocluster", false);
241 this.fileSplitTimeout = testing ? this.fileSplitTimeout :
242 server.getConfiguration().getLong("hbase.regionserver.fileSplitTimeout",
243 this.fileSplitTimeout);
244
245 PairOfSameType<HRegion> daughterRegions = stepsBeforePONR(server, services, testing);
246
247 List<Mutation> metaEntries = new ArrayList<Mutation>();
248 if (this.parent.getCoprocessorHost() != null) {
249 if (this.parent.getCoprocessorHost().
250 preSplitBeforePONR(this.splitrow, metaEntries)) {
251 throw new IOException("Coprocessor bypassing region "
252 + this.parent.getRegionNameAsString() + " split.");
253 }
254 try {
255 for (Mutation p : metaEntries) {
256 HRegionInfo.parseRegionName(p.getRow());
257 }
258 } catch (IOException e) {
259 LOG.error("Row key of mutation from coprossor is not parsable as region name."
260 + "Mutations from coprocessor should only for hbase:meta table.");
261 throw e;
262 }
263 }
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280 this.journal.add(JournalEntry.PONR);
281
282
283
284
285
286
287 if (!testing && useZKForAssignment) {
288 if (metaEntries == null || metaEntries.isEmpty()) {
289 MetaEditor.splitRegion(server.getCatalogTracker(), parent.getRegionInfo(), daughterRegions
290 .getFirst().getRegionInfo(), daughterRegions.getSecond().getRegionInfo(), server
291 .getServerName());
292 } else {
293 offlineParentInMetaAndputMetaEntries(server.getCatalogTracker(), parent.getRegionInfo(),
294 daughterRegions.getFirst().getRegionInfo(), daughterRegions.getSecond().getRegionInfo(),
295 server.getServerName(), metaEntries);
296 }
297 } else if (services != null && !useZKForAssignment) {
298 if (!services.reportRegionTransition(TransitionCode.SPLIT_PONR, parent.getRegionInfo(),
299 hri_a, hri_b)) {
300
301 throw new IOException("Failed to notify master that split passed PONR: "
302 + parent.getRegionInfo().getRegionNameAsString());
303 }
304 }
305 return daughterRegions;
306 }
307
308 public PairOfSameType<HRegion> stepsBeforePONR(final Server server,
309 final RegionServerServices services, boolean testing) throws IOException {
310
311
312 if (server != null && server.getZooKeeper() != null && useZKForAssignment) {
313 try {
314 createNodeSplitting(server.getZooKeeper(),
315 parent.getRegionInfo(), server.getServerName(), hri_a, hri_b);
316 } catch (KeeperException e) {
317 throw new IOException("Failed creating PENDING_SPLIT znode on " +
318 this.parent.getRegionNameAsString(), e);
319 }
320 } else if (services != null && !useZKForAssignment) {
321 if (!services.reportRegionTransition(TransitionCode.READY_TO_SPLIT,
322 parent.getRegionInfo(), hri_a, hri_b)) {
323 throw new IOException("Failed to get ok from master to split "
324 + parent.getRegionNameAsString());
325 }
326 }
327 this.journal.add(JournalEntry.SET_SPLITTING_IN_ZK);
328 if (server != null && server.getZooKeeper() != null && useZKForAssignment) {
329
330
331
332 znodeVersion = getZKNode(server, services);
333 }
334
335 this.parent.getRegionFileSystem().createSplitsDir();
336 this.journal.add(JournalEntry.CREATE_SPLIT_DIR);
337
338 Map<byte[], List<StoreFile>> hstoreFilesToSplit = null;
339 Exception exceptionToThrow = null;
340 try{
341 hstoreFilesToSplit = this.parent.close(false);
342 } catch (Exception e) {
343 exceptionToThrow = e;
344 }
345 if (exceptionToThrow == null && hstoreFilesToSplit == null) {
346
347
348
349
350
351 exceptionToThrow = closedByOtherException;
352 }
353 if (exceptionToThrow != closedByOtherException) {
354 this.journal.add(JournalEntry.CLOSED_PARENT_REGION);
355 }
356 if (exceptionToThrow != null) {
357 if (exceptionToThrow instanceof IOException) throw (IOException)exceptionToThrow;
358 throw new IOException(exceptionToThrow);
359 }
360 if (!testing) {
361 services.removeFromOnlineRegions(this.parent, null);
362 }
363 this.journal.add(JournalEntry.OFFLINED_PARENT);
364
365
366
367
368
369
370
371 splitStoreFiles(hstoreFilesToSplit);
372
373
374
375
376
377 this.journal.add(JournalEntry.STARTED_REGION_A_CREATION);
378 HRegion a = this.parent.createDaughterRegionFromSplits(this.hri_a);
379
380
381 this.journal.add(JournalEntry.STARTED_REGION_B_CREATION);
382 HRegion b = this.parent.createDaughterRegionFromSplits(this.hri_b);
383 return new PairOfSameType<HRegion>(a, b);
384 }
385
386
387
388
389
390
391
392
393
394
395
396
397 final RegionServerServices services, HRegion a, HRegion b)
398 throws IOException {
399 boolean stopped = server != null && server.isStopped();
400 boolean stopping = services != null && services.isStopping();
401
402 if (stopped || stopping) {
403 LOG.info("Not opening daughters " +
404 b.getRegionInfo().getRegionNameAsString() +
405 " and " +
406 a.getRegionInfo().getRegionNameAsString() +
407 " because stopping=" + stopping + ", stopped=" + stopped);
408 } else {
409
410 DaughterOpener aOpener = new DaughterOpener(server, a);
411 DaughterOpener bOpener = new DaughterOpener(server, b);
412 aOpener.start();
413 bOpener.start();
414 try {
415 aOpener.join();
416 bOpener.join();
417 } catch (InterruptedException e) {
418 throw (InterruptedIOException)new InterruptedIOException().initCause(e);
419 }
420 if (aOpener.getException() != null) {
421 throw new IOException("Failed " +
422 aOpener.getName(), aOpener.getException());
423 }
424 if (bOpener.getException() != null) {
425 throw new IOException("Failed " +
426 bOpener.getName(), bOpener.getException());
427 }
428 if (services != null) {
429 try {
430 if (useZKForAssignment) {
431
432 services.postOpenDeployTasks(b, server.getCatalogTracker());
433 } else if (!services.reportRegionTransition(TransitionCode.SPLIT,
434 parent.getRegionInfo(), hri_a, hri_b)) {
435 throw new IOException("Failed to report split region to master: "
436 + parent.getRegionInfo().getShortNameToLog());
437 }
438
439 services.addToOnlineRegions(b);
440 if (useZKForAssignment) {
441 services.postOpenDeployTasks(a, server.getCatalogTracker());
442 }
443 services.addToOnlineRegions(a);
444 } catch (KeeperException ke) {
445 throw new IOException(ke);
446 }
447 }
448 }
449 }
450
451
452
453
454
455
456
457
458
459
460
461
462 final RegionServerServices services, HRegion a, HRegion b)
463 throws IOException {
464
465 if (server != null && server.getZooKeeper() != null) {
466 try {
467 this.znodeVersion = transitionSplittingNode(server.getZooKeeper(),
468 parent.getRegionInfo(), a.getRegionInfo(), b.getRegionInfo(),
469 server.getServerName(), this.znodeVersion,
470 RS_ZK_REGION_SPLITTING, RS_ZK_REGION_SPLIT);
471
472 int spins = 0;
473
474
475
476 do {
477 if (spins % 10 == 0) {
478 LOG.debug("Still waiting on the master to process the split for " +
479 this.parent.getRegionInfo().getEncodedName());
480 }
481 Thread.sleep(100);
482
483 this.znodeVersion = transitionSplittingNode(server.getZooKeeper(),
484 parent.getRegionInfo(), a.getRegionInfo(), b.getRegionInfo(),
485 server.getServerName(), this.znodeVersion,
486 RS_ZK_REGION_SPLIT, RS_ZK_REGION_SPLIT);
487 spins++;
488 } while (this.znodeVersion != -1 && !server.isStopped()
489 && !services.isStopping());
490 } catch (Exception e) {
491 if (e instanceof InterruptedException) {
492 Thread.currentThread().interrupt();
493 }
494 throw new IOException("Failed telling master about split", e);
495 }
496 }
497
498
499
500
501
502
503 }
504
505
506
507
508
509
510
511
512
513 private int getZKNode(final Server server,
514 final RegionServerServices services) throws IOException {
515
516 try {
517 int spins = 0;
518 Stat stat = new Stat();
519 ZooKeeperWatcher zkw = server.getZooKeeper();
520 ServerName expectedServer = server.getServerName();
521 String node = parent.getRegionInfo().getEncodedName();
522 while (!(server.isStopped() || services.isStopping())) {
523 if (spins % 5 == 0) {
524 LOG.debug("Still waiting for master to process "
525 + "the pending_split for " + node);
526 transitionSplittingNode(zkw, parent.getRegionInfo(),
527 hri_a, hri_b, expectedServer, -1, RS_ZK_REQUEST_REGION_SPLIT,
528 RS_ZK_REQUEST_REGION_SPLIT);
529 }
530 Thread.sleep(100);
531 spins++;
532 byte [] data = ZKAssign.getDataNoWatch(zkw, node, stat);
533 if (data == null) {
534 throw new IOException("Data is null, splitting node "
535 + node + " no longer exists");
536 }
537 RegionTransition rt = RegionTransition.parseFrom(data);
538 EventType et = rt.getEventType();
539 if (et == RS_ZK_REGION_SPLITTING) {
540 ServerName serverName = rt.getServerName();
541 if (!serverName.equals(expectedServer)) {
542 throw new IOException("Splitting node " + node + " is for "
543 + serverName + ", not us " + expectedServer);
544 }
545 byte [] payloadOfSplitting = rt.getPayload();
546 List<HRegionInfo> splittingRegions = HRegionInfo.parseDelimitedFrom(
547 payloadOfSplitting, 0, payloadOfSplitting.length);
548 assert splittingRegions.size() == 2;
549 HRegionInfo a = splittingRegions.get(0);
550 HRegionInfo b = splittingRegions.get(1);
551 if (!(hri_a.equals(a) && hri_b.equals(b))) {
552 throw new IOException("Splitting node " + node + " is for " + a + ", "
553 + b + ", not expected daughters: " + hri_a + ", " + hri_b);
554 }
555
556 return stat.getVersion();
557 }
558 if (et != RS_ZK_REQUEST_REGION_SPLIT) {
559 throw new IOException("Splitting node " + node
560 + " moved out of splitting to " + et);
561 }
562 }
563
564 throw new IOException("Server is "
565 + (services.isStopping() ? "stopping" : "stopped"));
566 } catch (Exception e) {
567 if (e instanceof InterruptedException) {
568 Thread.currentThread().interrupt();
569 }
570 throw new IOException("Failed getting SPLITTING znode on "
571 + parent.getRegionNameAsString(), e);
572 }
573 }
574
575
576
577
578
579
580
581
582
583
584
585
586 public PairOfSameType<HRegion> execute(final Server server,
587 final RegionServerServices services)
588 throws IOException {
589 useZKForAssignment =
590 server == null ? true : ConfigUtil.useZKForAssignment(server.getConfiguration());
591 PairOfSameType<HRegion> regions = createDaughters(server, services);
592 if (this.parent.getCoprocessorHost() != null) {
593 this.parent.getCoprocessorHost().preSplitAfterPONR();
594 }
595 return stepsAfterPONR(server, services, regions);
596 }
597
598 public PairOfSameType<HRegion> stepsAfterPONR(final Server server,
599 final RegionServerServices services, PairOfSameType<HRegion> regions)
600 throws IOException {
601 openDaughters(server, services, regions.getFirst(), regions.getSecond());
602 if (server != null && server.getZooKeeper() != null && useZKForAssignment) {
603 transitionZKNode(server, services, regions.getFirst(), regions.getSecond());
604 }
605
606 if (this.parent.getCoprocessorHost() != null) {
607 this.parent.getCoprocessorHost().postSplit(regions.getFirst(), regions.getSecond());
608 }
609 return regions;
610 }
611
612 private void offlineParentInMetaAndputMetaEntries(CatalogTracker catalogTracker,
613 HRegionInfo parent, HRegionInfo splitA, HRegionInfo splitB,
614 ServerName serverName, List<Mutation> metaEntries) throws IOException {
615 List<Mutation> mutations = metaEntries;
616 HRegionInfo copyOfParent = new HRegionInfo(parent);
617 copyOfParent.setOffline(true);
618 copyOfParent.setSplit(true);
619
620
621 Put putParent = MetaEditor.makePutFromRegionInfo(copyOfParent);
622 MetaEditor.addDaughtersToPut(putParent, splitA, splitB);
623 mutations.add(putParent);
624
625
626 Put putA = MetaEditor.makePutFromRegionInfo(splitA);
627 Put putB = MetaEditor.makePutFromRegionInfo(splitB);
628
629 addLocation(putA, serverName, 1);
630 addLocation(putB, serverName, 1);
631 mutations.add(putA);
632 mutations.add(putB);
633 MetaEditor.mutateMetaTable(catalogTracker, mutations);
634 }
635
636 public Put addLocation(final Put p, final ServerName sn, long openSeqNum) {
637 p.addImmutable(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER,
638 Bytes.toBytes(sn.getHostAndPort()));
639 p.addImmutable(HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER,
640 Bytes.toBytes(sn.getStartcode()));
641 p.addImmutable(HConstants.CATALOG_FAMILY, HConstants.SEQNUM_QUALIFIER,
642 Bytes.toBytes(openSeqNum));
643 return p;
644 }
645
646
647
648
649
650 class DaughterOpener extends HasThread {
651 private final Server server;
652 private final HRegion r;
653 private Throwable t = null;
654
655 DaughterOpener(final Server s, final HRegion r) {
656 super((s == null? "null-services": s.getServerName()) +
657 "-daughterOpener=" + r.getRegionInfo().getEncodedName());
658 setDaemon(true);
659 this.server = s;
660 this.r = r;
661 }
662
663
664
665
666
667 Throwable getException() {
668 return this.t;
669 }
670
671 @Override
672 public void run() {
673 try {
674 openDaughterRegion(this.server, r);
675 } catch (Throwable t) {
676 this.t = t;
677 }
678 }
679 }
680
681
682
683
684
685
686
687
688 void openDaughterRegion(final Server server, final HRegion daughter)
689 throws IOException, KeeperException {
690 HRegionInfo hri = daughter.getRegionInfo();
691 LoggingProgressable reporter = server == null ? null
692 : new LoggingProgressable(hri, server.getConfiguration().getLong(
693 "hbase.regionserver.split.daughter.open.log.interval", 10000));
694 daughter.openHRegion(reporter);
695 }
696
697 static class LoggingProgressable implements CancelableProgressable {
698 private final HRegionInfo hri;
699 private long lastLog = -1;
700 private final long interval;
701
702 LoggingProgressable(final HRegionInfo hri, final long interval) {
703 this.hri = hri;
704 this.interval = interval;
705 }
706
707 @Override
708 public boolean progress() {
709 long now = System.currentTimeMillis();
710 if (now - lastLog > this.interval) {
711 LOG.info("Opening " + this.hri.getRegionNameAsString());
712 this.lastLog = now;
713 }
714 return true;
715 }
716 }
717
718 private void splitStoreFiles(final Map<byte[], List<StoreFile>> hstoreFilesToSplit)
719 throws IOException {
720 if (hstoreFilesToSplit == null) {
721
722 throw new IOException("Close returned empty list of StoreFiles");
723 }
724
725
726
727 int nbFiles = hstoreFilesToSplit.size();
728 if (nbFiles == 0) {
729
730 return;
731 }
732 ThreadFactoryBuilder builder = new ThreadFactoryBuilder();
733 builder.setNameFormat("StoreFileSplitter-%1$d");
734 ThreadFactory factory = builder.build();
735 ThreadPoolExecutor threadPool =
736 (ThreadPoolExecutor) Executors.newFixedThreadPool(nbFiles, factory);
737 List<Future<Void>> futures = new ArrayList<Future<Void>>(nbFiles);
738
739
740 for (Map.Entry<byte[], List<StoreFile>> entry: hstoreFilesToSplit.entrySet()) {
741 for (StoreFile sf: entry.getValue()) {
742 StoreFileSplitter sfs = new StoreFileSplitter(entry.getKey(), sf);
743 futures.add(threadPool.submit(sfs));
744 }
745 }
746
747 threadPool.shutdown();
748
749
750 try {
751 boolean stillRunning = !threadPool.awaitTermination(
752 this.fileSplitTimeout, TimeUnit.MILLISECONDS);
753 if (stillRunning) {
754 threadPool.shutdownNow();
755
756 while (!threadPool.isTerminated()) {
757 Thread.sleep(50);
758 }
759 throw new IOException("Took too long to split the" +
760 " files and create the references, aborting split");
761 }
762 } catch (InterruptedException e) {
763 throw (InterruptedIOException)new InterruptedIOException().initCause(e);
764 }
765
766
767 for (Future<Void> future: futures) {
768 try {
769 future.get();
770 } catch (InterruptedException e) {
771 throw (InterruptedIOException)new InterruptedIOException().initCause(e);
772 } catch (ExecutionException e) {
773 throw new IOException(e);
774 }
775 }
776 }
777
778 private void splitStoreFile(final byte[] family, final StoreFile sf) throws IOException {
779 HRegionFileSystem fs = this.parent.getRegionFileSystem();
780 String familyName = Bytes.toString(family);
781 fs.splitStoreFile(this.hri_a, familyName, sf, this.splitrow, false);
782 fs.splitStoreFile(this.hri_b, familyName, sf, this.splitrow, true);
783 }
784
785
786
787
788
789 class StoreFileSplitter implements Callable<Void> {
790 private final byte[] family;
791 private final StoreFile sf;
792
793
794
795
796
797
798 public StoreFileSplitter(final byte[] family, final StoreFile sf) {
799 this.sf = sf;
800 this.family = family;
801 }
802
803 public Void call() throws IOException {
804 splitStoreFile(family, sf);
805 return null;
806 }
807 }
808
809
810
811
812
813
814
815
816 @SuppressWarnings("deprecation")
817 public boolean rollback(final Server server, final RegionServerServices services)
818 throws IOException {
819
820 if (this.parent.getCoprocessorHost() != null) {
821 this.parent.getCoprocessorHost().preRollBackSplit();
822 }
823
824 boolean result = true;
825 ListIterator<JournalEntry> iterator =
826 this.journal.listIterator(this.journal.size());
827
828 while (iterator.hasPrevious()) {
829 JournalEntry je = iterator.previous();
830 switch(je) {
831
832 case SET_SPLITTING_IN_ZK:
833 if (server != null && server.getZooKeeper() != null && useZKForAssignment) {
834 cleanZK(server, this.parent.getRegionInfo());
835 } else if (services != null
836 && !useZKForAssignment
837 && !services.reportRegionTransition(TransitionCode.SPLIT_REVERTED,
838 parent.getRegionInfo(), hri_a, hri_b)) {
839 return false;
840 }
841 break;
842
843 case CREATE_SPLIT_DIR:
844 this.parent.writestate.writesEnabled = true;
845 this.parent.getRegionFileSystem().cleanupSplitsDir();
846 break;
847
848 case CLOSED_PARENT_REGION:
849 try {
850
851
852
853
854
855 this.parent.initialize();
856 } catch (IOException e) {
857 LOG.error("Failed rollbacking CLOSED_PARENT_REGION of region " +
858 this.parent.getRegionNameAsString(), e);
859 throw new RuntimeException(e);
860 }
861 break;
862
863 case STARTED_REGION_A_CREATION:
864 this.parent.getRegionFileSystem().cleanupDaughterRegion(this.hri_a);
865 break;
866
867 case STARTED_REGION_B_CREATION:
868 this.parent.getRegionFileSystem().cleanupDaughterRegion(this.hri_b);
869 break;
870
871 case OFFLINED_PARENT:
872 if (services != null) services.addToOnlineRegions(this.parent);
873 break;
874
875 case PONR:
876
877
878
879
880 return false;
881
882 default:
883 throw new RuntimeException("Unhandled journal entry: " + je);
884 }
885 }
886
887 if (this.parent.getCoprocessorHost() != null) {
888 this.parent.getCoprocessorHost().postRollBackSplit();
889 }
890 return result;
891 }
892
893 HRegionInfo getFirstDaughter() {
894 return hri_a;
895 }
896
897 HRegionInfo getSecondDaughter() {
898 return hri_b;
899 }
900
901 private static void cleanZK(final Server server, final HRegionInfo hri) {
902 try {
903
904 if (!ZKAssign.deleteNode(server.getZooKeeper(), hri.getEncodedName(),
905 RS_ZK_REQUEST_REGION_SPLIT, server.getServerName())) {
906 ZKAssign.deleteNode(server.getZooKeeper(), hri.getEncodedName(),
907 RS_ZK_REGION_SPLITTING, server.getServerName());
908 }
909 } catch (KeeperException.NoNodeException e) {
910 LOG.info("Failed cleanup zk node of " + hri.getRegionNameAsString(), e);
911 } catch (KeeperException e) {
912 server.abort("Failed cleanup of " + hri.getRegionNameAsString(), e);
913 }
914 }
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929 public static void createNodeSplitting(final ZooKeeperWatcher zkw, final HRegionInfo region,
930 final ServerName serverName, final HRegionInfo a,
931 final HRegionInfo b) throws KeeperException, IOException {
932 LOG.debug(zkw.prefix("Creating ephemeral node for " +
933 region.getEncodedName() + " in PENDING_SPLIT state"));
934 byte [] payload = HRegionInfo.toDelimitedByteArray(a, b);
935 RegionTransition rt = RegionTransition.createRegionTransition(
936 RS_ZK_REQUEST_REGION_SPLIT, region.getRegionName(), serverName, payload);
937 String node = ZKAssign.getNodeName(zkw, region.getEncodedName());
938 if (!ZKUtil.createEphemeralNodeAndWatch(zkw, node, rt.toByteArray())) {
939 throw new IOException("Failed create of ephemeral " + node);
940 }
941 }
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977 public static int transitionSplittingNode(ZooKeeperWatcher zkw,
978 HRegionInfo parent, HRegionInfo a, HRegionInfo b, ServerName serverName,
979 final int znodeVersion, final EventType beginState,
980 final EventType endState) throws KeeperException, IOException {
981 byte [] payload = HRegionInfo.toDelimitedByteArray(a, b);
982 return ZKAssign.transitionNode(zkw, parent, serverName,
983 beginState, endState, znodeVersion, payload);
984 }
985 }