1919package org .apache .hudi .table .action .rollback ;
2020
2121import org .apache .hudi .avro .model .HoodieRollbackMetadata ;
22+ import org .apache .hudi .avro .model .HoodieRollbackPlan ;
2223import org .apache .hudi .client .heartbeat .HoodieHeartbeatClient ;
2324import org .apache .hudi .common .HoodieRollbackStat ;
2425import org .apache .hudi .common .bootstrap .index .BootstrapIndex ;
4344import org .apache .log4j .Logger ;
4445
4546import java .io .IOException ;
46- import java .io .Serializable ;
4747import java .util .Collections ;
4848import java .util .List ;
4949import java .util .Objects ;
@@ -53,11 +53,6 @@ public abstract class BaseRollbackActionExecutor<T extends HoodieRecordPayload,
5353
5454 private static final Logger LOG = LogManager .getLogger (BaseRollbackActionExecutor .class );
5555
56- interface RollbackStrategy extends Serializable {
57-
58- List <HoodieRollbackStat > execute (HoodieInstant instantToRollback );
59- }
60-
6156 protected final HoodieInstant instantToRollback ;
6257 protected final boolean deleteInstants ;
6358 protected final boolean skipTimelinePublish ;
@@ -92,30 +87,74 @@ public BaseRollbackActionExecutor(HoodieEngineContext context,
9287 }
9388 }
9489
95- protected abstract RollbackStrategy getRollbackStrategy ();
90+ /**
91+ * Execute actual rollback and fetch list of RollbackStats.
92+ * @param hoodieRollbackPlan instance of {@link HoodieRollbackPlan} that needs to be executed.
93+ * @return a list of {@link HoodieRollbackStat}s.
94+ * @throws IOException
95+ */
96+ protected abstract List <HoodieRollbackStat > executeRollback (HoodieRollbackPlan hoodieRollbackPlan ) throws IOException ;
97+
98+ private HoodieRollbackMetadata runRollback (HoodieTable <T , I , K , O > table , HoodieInstant rollbackInstant , HoodieRollbackPlan rollbackPlan ) {
99+ ValidationUtils .checkArgument (rollbackInstant .getState ().equals (HoodieInstant .State .REQUESTED )
100+ || rollbackInstant .getState ().equals (HoodieInstant .State .INFLIGHT ));
101+ try {
102+ final HoodieInstant inflightInstant ;
103+ final HoodieTimer timer = new HoodieTimer ();
104+ timer .startTimer ();
105+ if (rollbackInstant .isRequested ()) {
106+ inflightInstant = table .getActiveTimeline ().transitionRollbackRequestedToInflight (rollbackInstant ,
107+ TimelineMetadataUtils .serializeRollbackPlan (rollbackPlan ));
108+ } else {
109+ inflightInstant = rollbackInstant ;
110+ }
111+
112+ HoodieTimer rollbackTimer = new HoodieTimer ().startTimer ();
113+ List <HoodieRollbackStat > stats = doRollbackAndGetStats (rollbackPlan );
114+ HoodieRollbackMetadata rollbackMetadata = TimelineMetadataUtils .convertRollbackMetadata (
115+ instantTime ,
116+ Option .of (rollbackTimer .endTimer ()),
117+ Collections .singletonList (instantToRollback ),
118+ stats );
119+ if (!skipTimelinePublish ) {
120+ finishRollback (inflightInstant , rollbackMetadata );
121+ }
96122
97- protected abstract List <HoodieRollbackStat > executeRollback () throws IOException ;
123+ // Finally, remove the markers post rollback.
124+ WriteMarkersFactory .get (config .getMarkersType (), table , instantToRollback .getTimestamp ())
125+ .quietDeleteMarkerDir (context , config .getMarkersDeleteParallelism ());
98126
99- protected abstract List <HoodieRollbackStat > executeRollbackUsingFileListing (HoodieInstant instantToRollback );
127+ return rollbackMetadata ;
128+ } catch (IOException e ) {
129+ throw new HoodieIOException ("Failed to rollback commit " , e );
130+ }
131+ }
100132
101133 @ Override
102134 public HoodieRollbackMetadata execute () {
103- HoodieTimer rollbackTimer = new HoodieTimer ().startTimer ();
104- List <HoodieRollbackStat > stats = doRollbackAndGetStats ();
105- HoodieRollbackMetadata rollbackMetadata = TimelineMetadataUtils .convertRollbackMetadata (
106- instantTime ,
107- Option .of (rollbackTimer .endTimer ()),
108- Collections .singletonList (instantToRollback ),
109- stats );
110- if (!skipTimelinePublish ) {
111- finishRollback (rollbackMetadata );
135+ table .getMetaClient ().reloadActiveTimeline ();
136+ List <HoodieInstant > rollBackInstants = table .getRollbackTimeline ()
137+ .filterInflightsAndRequested ().getInstants ().collect (Collectors .toList ());
138+ if (rollBackInstants .isEmpty ()) {
139+ throw new HoodieRollbackException ("No Requested Rollback Instants found to execute rollback " );
140+ }
141+ HoodieInstant rollbackInstant = null ;
142+ for (HoodieInstant instant : rollBackInstants ) {
143+ if (instantTime .equals (instant .getTimestamp ())) {
144+ rollbackInstant = instant ;
145+ break ;
146+ }
147+ }
148+ if (rollbackInstant != null ) {
149+ try {
150+ HoodieRollbackPlan rollbackPlan = RollbackUtils .getRollbackPlan (table .getMetaClient (), rollbackInstant );
151+ return runRollback (table , rollBackInstants .get (0 ), rollbackPlan );
152+ } catch (IOException e ) {
153+ throw new HoodieIOException ("Failed to fetch rollback plan to rollback commit " + rollbackInstant .getTimestamp (), e );
154+ }
155+ } else {
156+ throw new HoodieIOException ("No inflight rollback instants found for commit time " + instantTime );
112157 }
113-
114- // Finally, remove the markers post rollback.
115- WriteMarkersFactory .get (config .getMarkersType (), table , instantToRollback .getTimestamp ())
116- .quietDeleteMarkerDir (context , config .getMarkersDeleteParallelism ());
117-
118- return rollbackMetadata ;
119158 }
120159
121160 private void validateSavepointRollbacks () {
@@ -173,7 +212,7 @@ private void rollBackIndex() {
173212 LOG .info ("Index rolled back for commits " + instantToRollback );
174213 }
175214
176- public List <HoodieRollbackStat > doRollbackAndGetStats () {
215+ public List <HoodieRollbackStat > doRollbackAndGetStats (HoodieRollbackPlan hoodieRollbackPlan ) {
177216 final String instantTimeToRollback = instantToRollback .getTimestamp ();
178217 final boolean isPendingCompaction = Objects .equals (HoodieTimeline .COMPACTION_ACTION , instantToRollback .getAction ())
179218 && !instantToRollback .isCompleted ();
@@ -186,7 +225,7 @@ public List<HoodieRollbackStat> doRollbackAndGetStats() {
186225 }
187226
188227 try {
189- List <HoodieRollbackStat > stats = executeRollback ();
228+ List <HoodieRollbackStat > stats = executeRollback (hoodieRollbackPlan );
190229 LOG .info ("Rolled back inflight instant " + instantTimeToRollback );
191230 if (!isPendingCompaction ) {
192231 rollBackIndex ();
@@ -197,12 +236,19 @@ public List<HoodieRollbackStat> doRollbackAndGetStats() {
197236 }
198237 }
199238
200- protected void finishRollback (HoodieRollbackMetadata rollbackMetadata ) throws HoodieIOException {
239+ /**
240+ * Execute rollback and fetch rollback stats.
241+ * @param instantToRollback instant to be rolled back.
242+ * @param rollbackPlan instance of {@link HoodieRollbackPlan} for which rollback needs to be executed.
243+ * @return list of {@link HoodieRollbackStat}s.
244+ */
245+ protected List <HoodieRollbackStat > executeRollback (HoodieInstant instantToRollback , HoodieRollbackPlan rollbackPlan ) {
246+ return new BaseRollbackHelper (table .getMetaClient (), config ).performRollback (context , instantToRollback , rollbackPlan .getRollbackRequests ());
247+ }
248+
249+ protected void finishRollback (HoodieInstant inflightInstant , HoodieRollbackMetadata rollbackMetadata ) throws HoodieIOException {
201250 try {
202- table .getActiveTimeline ().createNewInstant (
203- new HoodieInstant (HoodieInstant .State .INFLIGHT , HoodieTimeline .ROLLBACK_ACTION , instantTime ));
204- table .getActiveTimeline ().saveAsComplete (
205- new HoodieInstant (true , HoodieTimeline .ROLLBACK_ACTION , instantTime ),
251+ table .getActiveTimeline ().transitionRollbackInflightToComplete (inflightInstant ,
206252 TimelineMetadataUtils .serializeRollbackMetadata (rollbackMetadata ));
207253 LOG .info ("Rollback of Commits " + rollbackMetadata .getCommitsRollback () + " is complete" );
208254 } catch (IOException e ) {
0 commit comments