1010import org .whispersystems .textsecuregcm .entities .MessageProtos ;
1111import org .whispersystems .textsecuregcm .storage .MessageStreamEntry ;
1212import org .whispersystems .textsecuregcm .util .Pair ;
13+ import org .whispersystems .textsecuregcm .util .UUIDUtil ;
1314import reactor .core .publisher .Flux ;
1415import reactor .core .publisher .FluxSink ;
1516
2526class FoundationDbMessagePublisher {
2627
2728 private final Database database ;
29+ private final MessageGuidCodec messageGuidCodec ;
2830 /// The maximum number of messages we will fetch per range query operation to avoid excessive memory consumption
2931 private final int maxMessagesPerScan ;
3032 /// The end key at which we stop reading messages. For finite publisher, this is just past the end-of-queue key at the
@@ -88,15 +90,18 @@ enum Event {
8890 private static final Logger LOGGER = LoggerFactory .getLogger (FoundationDbMessagePublisher .class );
8991
9092 FoundationDbMessagePublisher (
91- final KeySelector beginKeyInclusive ,
92- final KeySelector endKeyExclusive ,
93- final Database database ,
94- final int maxMessagesPerScan ,
95- @ Nullable final byte [] messagesAvailableWatchKey ,
96- @ Nullable final BiConsumer <State , State > stateChangeListener ) {
93+ final KeySelector beginKeyInclusive ,
94+ final KeySelector endKeyExclusive ,
95+ final Database database ,
96+ final MessageGuidCodec messageGuidCodec ,
97+ final int maxMessagesPerScan ,
98+ @ Nullable final byte [] messagesAvailableWatchKey ,
99+ @ Nullable final BiConsumer <State , State > stateChangeListener ) {
100+
97101 this .beginKeyCursor = beginKeyInclusive ;
98102 this .endKeyExclusive = endKeyExclusive ;
99103 this .database = database ;
104+ this .messageGuidCodec = messageGuidCodec ;
100105 this .maxMessagesPerScan = maxMessagesPerScan ;
101106 this .messagesAvailableWatchKey = messagesAvailableWatchKey ;
102107 this .terminateOnQueueEmpty = messagesAvailableWatchKey == null ;
@@ -116,8 +121,16 @@ public static FoundationDbMessagePublisher createFinitePublisher(
116121 final KeySelector beginKeyInclusive ,
117122 final KeySelector endKeyExclusive ,
118123 final Database database ,
124+ final MessageGuidCodec messageGuidCodec ,
119125 final int maxMessagesPerScan ) {
120- return new FoundationDbMessagePublisher (beginKeyInclusive , endKeyExclusive , database , maxMessagesPerScan , null , null );
126+
127+ return new FoundationDbMessagePublisher (beginKeyInclusive ,
128+ endKeyExclusive ,
129+ database ,
130+ messageGuidCodec ,
131+ maxMessagesPerScan ,
132+ null ,
133+ null );
121134 }
122135
123136 /// Creates a [FoundationDbMessagePublisher] that publishes a non-terminating stream of messages from a device queue.
@@ -127,9 +140,17 @@ public static FoundationDbMessagePublisher createInfinitePublisher(
127140 final KeySelector beginKeyInclusive ,
128141 final KeySelector endKeyExclusive ,
129142 final Database database ,
143+ final MessageGuidCodec messageGuidCodec ,
130144 final int maxMessagesPerScan ,
131145 final byte [] messagesAvailableWatchKey ) {
132- return new FoundationDbMessagePublisher (beginKeyInclusive , endKeyExclusive , database , maxMessagesPerScan , messagesAvailableWatchKey , null );
146+
147+ return new FoundationDbMessagePublisher (beginKeyInclusive ,
148+ endKeyExclusive ,
149+ database ,
150+ messageGuidCodec ,
151+ maxMessagesPerScan ,
152+ messagesAvailableWatchKey ,
153+ null );
133154 }
134155
135156 private synchronized void setState (final State newState , final Event event ) {
@@ -222,7 +243,7 @@ protected synchronized void transitionStateOnEvent(final Event event) {
222243 ///
223244 /// @return a future of a list of [MessageStreamEntry] with a max size of [#maxMessagesPerScan]
224245 private CompletableFuture <List <MessageStreamEntry .Envelope >> getMessagesBatch () {
225- return database .runAsync (transaction -> getItemsInRange (transaction , beginKeyCursor , endKeyExclusive , maxMessagesPerScan )
246+ return database .runAsync (transaction -> getItemsInRange (transaction , messageGuidCodec , beginKeyCursor , endKeyExclusive , maxMessagesPerScan )
226247 .thenApply (lastKeyReadAndItems -> {
227248 // Set our beginning key to just past the last key read so that we're ready for our next fetch
228249 lastKeyReadAndItems .first ().ifPresent (lastKeyRead -> beginKeyCursor = KeySelector .firstGreaterThan (lastKeyRead ));
@@ -248,6 +269,7 @@ private CompletableFuture<List<MessageStreamEntry.Envelope>> getMessagesBatch()
248269 /// @return the last key read (if there were non-zero number of messages read) and the list of messages read
249270 private static CompletableFuture <Pair <Optional <byte []>, List <MessageStreamEntry .Envelope >>> getItemsInRange (
250271 final Transaction transaction ,
272+ final MessageGuidCodec messageGuidCodec ,
251273 final KeySelector beginInclusive ,
252274 final KeySelector endExclusive ,
253275 final int maxMessagesPerScan ) {
@@ -259,7 +281,10 @@ private static CompletableFuture<Pair<Optional<byte[]>, List<MessageStreamEntry.
259281 final List <MessageStreamEntry .Envelope > messages = keyValues .stream ()
260282 .map (keyValue -> {
261283 try {
262- return new MessageStreamEntry .Envelope (MessageProtos .Envelope .parseFrom (keyValue .getValue ()));
284+ return new MessageStreamEntry .Envelope (MessageProtos .Envelope .parseFrom (keyValue .getValue ())
285+ .toBuilder ()
286+ .setServerGuidBinary (UUIDUtil .toByteString (messageGuidCodec .encodeMessageGuid (FoundationDbMessageStore .getVersionstamp (keyValue .getKey ()))))
287+ .build ());
263288 } catch (final InvalidProtocolBufferException e ) {
264289 throw new UncheckedIOException (e );
265290 }
0 commit comments