[Demonstration 1]

[Buggy Method]
void receiveIndividualMessagesFromBatch(MessageMetadata msgMetadata, ByteBuf uncompressedPayload, MessageIdData messageId, ClientCnx cnx) {
    int batchSize = msgMetadata.getNumMessagesInBatch();
    // create ack tracker for entry aka batch
    BitSet bitSet = new BitSet(batchSize);
    MessageIdImpl batchMessage = new MessageIdImpl(messageId.getLedgerId(), messageId.getEntryId(), getPartitionIndex());
    bitSet.set(0, batchSize);
    if (log.isDebugEnabled()) {
        log.debug("[{}] [{}] added bit set for message {}, cardinality {}, length {}", subscription, consumerName, batchMessage, bitSet.cardinality(), bitSet.length());
    }
    batchMessageAckTracker.put(batchMessage, bitSet);
    unAckedMessageTracker.add(batchMessage);
    int skippedMessages = 0;
    try {
        for (int i = 0; i < batchSize; ++i) {
            if (log.isDebugEnabled()) {
                log.debug("[{}] [{}] processing message num - {} in batch", subscription, consumerName, i);
            }
            PulsarApi.SingleMessageMetadata.Builder singleMessageMetadataBuilder = PulsarApi.SingleMessageMetadata.newBuilder();
            ByteBuf singleMessagePayload = Commands.deSerializeSingleMessageInBatch(uncompressedPayload, singleMessageMetadataBuilder, i, batchSize);
            if (startMessageId != null && messageId.getLedgerId() == startMessageId.getLedgerId() && messageId.getEntryId() == startMessageId.getEntryId() && i <= startMessageId.getBatchIndex()) {
                // If we are receiving a batch message, we need to discard messages that were prior
                // to the startMessageId
                if (log.isDebugEnabled()) {
                    log.debug("[{}] [{}] Ignoring message from before the startMessageId", subscription, consumerName);
                }
                ++skippedMessages;
                continue;
            }
            BatchMessageIdImpl batchMessageIdImpl = new BatchMessageIdImpl(messageId.getLedgerId(), messageId.getEntryId(), getPartitionIndex(), i);
            final MessageImpl message = new MessageImpl(batchMessageIdImpl, msgMetadata, singleMessageMetadataBuilder.build(), singleMessagePayload, cnx);
            lock.readLock().lock();
            if (pendingReceives.isEmpty()) {
                incomingMessages.add(message);
            } else {
                notifyPendingReceivedCallback(message, null);
            }
            lock.readLock().unlock();
            singleMessagePayload.release();
            singleMessageMetadataBuilder.recycle();
        }
    } catch (IOException e) {
        //
        log.warn("[{}] [{}] unable to obtain message in batch", subscription, consumerName);
        batchMessageAckTracker.remove(batchMessage);
        discardCorruptedMessage(messageId, cnx, ValidationError.BatchDeSerializeError);
    }
    if (log.isDebugEnabled()) {
        log.debug("[{}] [{}] enqueued messages in batch. queue size - {}, available queue size - {}", subscription, consumerName, incomingMessages.size(), incomingMessages.remainingCapacity());
    }
    if (skippedMessages > 0) {
        increaseAvailablePermits(cnx, skippedMessages);
    }
}

[Buggy Hunk]
if (startMessageId != null

[Patch]
if (subscriptionMode == SubscriptionMode.NonDurable && startMessageId != null

[Demonstration 2]

[Buggy Method]
@Override
public void run() {
    while (!stopped) {
        Date now = new Date();
        try {
            List<RunSchedule> runSchedules = getRunSchedule();
            // calculate the subscriptions to run
            List<String> subscriptionsToRun = new ArrayList<String>();
            for (RunSchedule schedule : runSchedules) {
                // check if this schedule should be executed
                if (shouldRun(now, schedule.getNextRun(), schedule.getSchedule().getCurrentDelay())) {
                    subscriptionsToRun.add(schedule.getSchedule().getId());
                } else // otherwise stop executing
                {
                    break;
                }
            }
            if (!subscriptionsToRun.isEmpty()) {
                List<TaskExecutionHandle> result = parent.poll(subscriptionsToRun.toArray(new String[subscriptionsToRun.size()]));
                // we need to check for each subscription we ran if it found something and adjust the delays accordingly
                Set<String> subscriptionsTriggered = new HashSet<String>();
                for (TaskExecutionHandle handle : result) {
                    subscriptionsTriggered.add(handle.getSubscription().getId());
                }
                for (String subscription : subscriptionsToRun) {
                    schedules.get(subscription).pickup(subscriptionsTriggered.contains(subscription));
                }
                // we need to recalculate the schedules to get the correct sleep amount
                runSchedules = getRunSchedule();
            }
            // if there are no dates, wait for a while
            if (runSchedules.isEmpty()) {
                Thread.sleep(10000);
            } else // if there are, we need to sleep until the first one is available
            {
                long millis = runSchedules.get(0).getNextRun().getTime() - now.getTime();
                if (millis > 0) {
                    Thread.sleep(millis);
                }
            }
        } catch (InterruptedException e) {
            // clear the flag, it could be triggered for example when a new schedule is made
            Thread.interrupted();
        }
    }
}

[Buggy Hunk]
schedules.get(subscription).pickup(subscriptionsTriggered.contains(subscription));

[Patch]
schedules.get(subscription).pickup(subscriptionsTriggered.contains(subscription) || parent.isRunning(subscription));

[Demonstration 3]

[Buggy Method]
@Override
public void onUnsubscribed() {
    route.unsubscribe(subscriptionPointId, user.getId());
    btnSubscribe.setVisibility(View.VISIBLE);
    btnUnsubscribe.setVisibility(View.GONE);
    Intent data = new Intent();
    data.putExtra(Constants.Intents.EXTRA_ROUTE, route);
    setResult(RESULT_OK, data);
    finish();
}

[Buggy Hunk]
route.unsubscribe(subscriptionPointId, user.getId());

[Patch]
route.unsubscribe(subscriptionPointId, account.user().getId());