private void writeKVStateData() throws IOException, InterruptedException { byte[] previousKey = null; byte[] previousValue = null; List<Tuple2<RocksIterator, Integer>> kvStateIteratorsHandover = this.kvStateIterators; this.kvStateIterators = null; // Here we transfer ownership of RocksIterators to the RocksDBMergeIterator try (RocksDBMergeIterator mergeIterator = new RocksDBMergeIterator(kvStateIteratorsHandover, stateBackend.keyGroupPrefixBytes)) { // preamble: setup with first key-group as our lookahead if (mergeIterator.isValid()) { // begin first key-group by recording the offset keyGroupRangeOffsets.setKeyGroupOffset(mergeIterator.keyGroup(), outStream.getPos()); // write the k/v-state id as metadata // TODO this could be aware of keyGroupPrefixBytes and write only one byte if possible outputView.writeShort(mergeIterator.kvStateId()); previousKey = mergeIterator.key(); previousValue = mergeIterator.value(); mergeIterator.next(); } // main loop: write k/v pairs ordered by (key-group, kv-state), thereby tracking key-group // offsets. while (mergeIterator.isValid()) { assert (!hasMetaDataFollowsFlag(previousKey)); // set signal in first key byte that meta data will follow in the stream after this k/v // pair if (mergeIterator.isNewKeyGroup() || mergeIterator.isNewKeyValueState()) { // be cooperative and check for interruption from time to time in the hot loop checkInterrupted(); setMetaDataFollowsFlagInKey(previousKey); } writeKeyValuePair(previousKey, previousValue); // write meta data if we have to if (mergeIterator.isNewKeyGroup()) { // TODO this could be aware of keyGroupPrefixBytes and write only one byte if possible outputView.writeShort(END_OF_KEY_GROUP_MARK); // begin new key-group keyGroupRangeOffsets.setKeyGroupOffset(mergeIterator.keyGroup(), outStream.getPos()); // write the kev-state // TODO this could be aware of keyGroupPrefixBytes and write only one byte if possible outputView.writeShort(mergeIterator.kvStateId()); } else if (mergeIterator.isNewKeyValueState()) { // write the k/v-state // TODO this could be aware of keyGroupPrefixBytes and write only one byte if possible outputView.writeShort(mergeIterator.kvStateId()); } // request next k/v pair previousKey = mergeIterator.key(); previousValue = mergeIterator.value(); mergeIterator.next(); } } // epilogue: write last key-group if (previousKey != null) { assert (!hasMetaDataFollowsFlag(previousKey)); setMetaDataFollowsFlagInKey(previousKey); writeKeyValuePair(previousKey, previousValue); // TODO this could be aware of keyGroupPrefixBytes and write only one byte if possible outputView.writeShort(END_OF_KEY_GROUP_MARK); } }