1 // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2 package org.rocksdb.util;
3 
4 import org.rocksdb.RocksDBException;
5 import org.rocksdb.WriteBatch;
6 
7 import java.util.ArrayList;
8 import java.util.Arrays;
9 import java.util.List;
10 import java.util.Objects;
11 
12 /**
13  * A simple WriteBatch Handler which adds a record
14  * of each event that it receives to a list
15  */
16 public class CapturingWriteBatchHandler extends WriteBatch.Handler {
17 
18   private final List<Event> events = new ArrayList<>();
19 
20   /**
21    * Returns a copy of the current events list
22    *
23    * @return a list of the events which have happened upto now
24    */
getEvents()25   public List<Event> getEvents() {
26     return new ArrayList<>(events);
27   }
28 
29   @Override
put(final int columnFamilyId, final byte[] key, final byte[] value)30   public void put(final int columnFamilyId, final byte[] key,
31                   final byte[] value) {
32     events.add(new Event(Action.PUT, columnFamilyId, key, value));
33   }
34 
35   @Override
put(final byte[] key, final byte[] value)36   public void put(final byte[] key, final byte[] value) {
37     events.add(new Event(Action.PUT, key, value));
38   }
39 
40   @Override
merge(final int columnFamilyId, final byte[] key, final byte[] value)41   public void merge(final int columnFamilyId, final byte[] key,
42                     final byte[] value) {
43     events.add(new Event(Action.MERGE, columnFamilyId, key, value));
44   }
45 
46   @Override
merge(final byte[] key, final byte[] value)47   public void merge(final byte[] key, final byte[] value) {
48     events.add(new Event(Action.MERGE, key, value));
49   }
50 
51   @Override
delete(final int columnFamilyId, final byte[] key)52   public void delete(final int columnFamilyId, final byte[] key) {
53     events.add(new Event(Action.DELETE, columnFamilyId, key, (byte[])null));
54   }
55 
56   @Override
delete(final byte[] key)57   public void delete(final byte[] key) {
58     events.add(new Event(Action.DELETE, key, (byte[])null));
59   }
60 
61   @Override
singleDelete(final int columnFamilyId, final byte[] key)62   public void singleDelete(final int columnFamilyId, final byte[] key) {
63     events.add(new Event(Action.SINGLE_DELETE,
64         columnFamilyId, key, (byte[])null));
65   }
66 
67   @Override
singleDelete(final byte[] key)68   public void singleDelete(final byte[] key) {
69     events.add(new Event(Action.SINGLE_DELETE, key, (byte[])null));
70   }
71 
72   @Override
deleteRange(final int columnFamilyId, final byte[] beginKey, final byte[] endKey)73   public void deleteRange(final int columnFamilyId, final byte[] beginKey,
74                           final byte[] endKey) {
75     events.add(new Event(Action.DELETE_RANGE, columnFamilyId, beginKey,
76         endKey));
77   }
78 
79   @Override
deleteRange(final byte[] beginKey, final byte[] endKey)80   public void deleteRange(final byte[] beginKey, final byte[] endKey) {
81     events.add(new Event(Action.DELETE_RANGE, beginKey, endKey));
82   }
83 
84   @Override
logData(final byte[] blob)85   public void logData(final byte[] blob) {
86     events.add(new Event(Action.LOG, (byte[])null, blob));
87   }
88 
89   @Override
putBlobIndex(final int columnFamilyId, final byte[] key, final byte[] value)90   public void putBlobIndex(final int columnFamilyId, final byte[] key,
91                            final byte[] value) {
92     events.add(new Event(Action.PUT_BLOB_INDEX, key, value));
93   }
94 
95   @Override
markBeginPrepare()96   public void markBeginPrepare() throws RocksDBException {
97     events.add(new Event(Action.MARK_BEGIN_PREPARE, (byte[])null,
98         (byte[])null));
99   }
100 
101   @Override
markEndPrepare(final byte[] xid)102   public void markEndPrepare(final byte[] xid) throws RocksDBException {
103     events.add(new Event(Action.MARK_END_PREPARE, (byte[])null,
104         (byte[])null));
105   }
106 
107   @Override
markNoop(final boolean emptyBatch)108   public void markNoop(final boolean emptyBatch) throws RocksDBException {
109     events.add(new Event(Action.MARK_NOOP, (byte[])null, (byte[])null));
110   }
111 
112   @Override
markRollback(final byte[] xid)113   public void markRollback(final byte[] xid) throws RocksDBException {
114     events.add(new Event(Action.MARK_ROLLBACK, (byte[])null, (byte[])null));
115   }
116 
117   @Override
markCommit(final byte[] xid)118   public void markCommit(final byte[] xid) throws RocksDBException {
119     events.add(new Event(Action.MARK_COMMIT, (byte[])null, (byte[])null));
120   }
121 
122   public static class Event {
123     public final Action action;
124     public final int columnFamilyId;
125     public final byte[] key;
126     public final byte[] value;
127 
Event(final Action action, final byte[] key, final byte[] value)128     public Event(final Action action, final byte[] key, final byte[] value) {
129       this(action, 0, key, value);
130     }
131 
Event(final Action action, final int columnFamilyId, final byte[] key, final byte[] value)132     public Event(final Action action, final int columnFamilyId, final byte[] key,
133         final byte[] value) {
134       this.action = action;
135       this.columnFamilyId = columnFamilyId;
136       this.key = key;
137       this.value = value;
138     }
139 
140     @Override
equals(final Object o)141     public boolean equals(final Object o) {
142       if (this == o) {
143         return true;
144       }
145       if (o == null || getClass() != o.getClass()) {
146         return false;
147       }
148       final Event event = (Event) o;
149       return columnFamilyId == event.columnFamilyId &&
150           action == event.action &&
151           ((key == null && event.key == null)
152               || Arrays.equals(key, event.key)) &&
153           ((value == null && event.value == null)
154               || Arrays.equals(value, event.value));
155     }
156 
157     @Override
hashCode()158     public int hashCode() {
159 
160       return Objects.hash(action, columnFamilyId, key, value);
161     }
162   }
163 
164   /**
165    * Enumeration of Write Batch
166    * event actions
167    */
168   public enum Action {
169     PUT, MERGE, DELETE, SINGLE_DELETE, DELETE_RANGE, LOG, PUT_BLOB_INDEX,
170     MARK_BEGIN_PREPARE, MARK_END_PREPARE, MARK_NOOP, MARK_COMMIT,
171     MARK_ROLLBACK }
172 }
173