Fix KV Stores for same message in multiple groups (#8737)

* Fix KV Stores for same message in multiple groups

If same message is stored into different groups with the same KV store,
the removal of one group would lead to removal the message for the other one.

* Improve KV Store to save message with the key including a group id
* Respectively, refine the removal API to include group id into keys
* Also change the `MESSAGE_GROUP_KEY_PREFIX` for group records to `GROUP_OF_MESSAGES_`
since the `MESSAGE_` prefix includes group records as well for various operations
based on key pattern

* * Use `[^GROUP_]` in the pattern for messages count

**Cherry-pick to `6.1.x`**

* * Fix MongoDB MS for message removal logic

* * Bring back `GROUP_OF_MESSAGES_` prefix
to avoid complex regexp and don't bother for edge cases,
where even that regexp may fail
This commit is contained in:
Artem Bilan
2023-09-19 14:13:05 -04:00
committed by GitHub
parent 9ad2b8a8e2
commit 64f8ed5bab
7 changed files with 165 additions and 75 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2022 the original author or authors.
* Copyright 2013-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -101,7 +101,8 @@ public class ConfigurableMongoDbMessageStore extends AbstractConfigurableMongoDb
@Override
public Message<?> removeMessage(UUID id) {
Assert.notNull(id, "'id' must not be null");
Query query = Query.query(Criteria.where(MessageDocumentFields.MESSAGE_ID).is(id));
Query query = Query.query(Criteria.where(MessageDocumentFields.MESSAGE_ID).is(id)
.and(MessageDocumentFields.GROUP_ID).exists(false));
MessageDocument document = getMongoTemplate().findAndRemove(query, MessageDocument.class, this.collectionName);
return (document != null) ? document.getMessage() : null;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -258,14 +258,15 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
@Override
@ManagedAttribute
public long getMessageCount() {
return this.template.getCollection(this.collectionName).countDocuments();
Query query = Query.query(Criteria.where("headers.id").exists(true).and(GROUP_ID_KEY).exists(false));
return this.template.getCollection(this.collectionName).countDocuments(query.getQueryObject());
}
@Override
public Message<?> removeMessage(UUID id) {
Assert.notNull(id, "'id' must not be null");
MessageWrapper messageWrapper =
this.template.findAndRemove(whereMessageIdIs(id), MessageWrapper.class, this.collectionName);
Query query = Query.query(Criteria.where("headers.id").is(id).and(GROUP_ID_KEY).exists(false));
MessageWrapper messageWrapper = this.template.findAndRemove(query, MessageWrapper.class, this.collectionName);
return (messageWrapper != null ? messageWrapper.getMessage() : null);
}

View File

@@ -536,6 +536,28 @@ public abstract class AbstractMongoDbMessageGroupStoreTests implements MongoDbCo
.containsEntry("type", "channel");
}
@Test
public void removeMessageDoesntRemoveSameMessageInTheGroup() {
GenericMessage<String> testMessage = new GenericMessage<>("test data");
MessageGroupStore store = getMessageGroupStore();
store.addMessageToGroup("1", testMessage);
MessageStore messageStore = (MessageStore) store;
messageStore.removeMessage(testMessage.getHeaders().getId());
assertThat(messageStore.getMessageCount()).isEqualTo(0);
assertThat(store.getMessageCountForAllMessageGroups()).isEqualTo(1);
assertThat(store.messageGroupSize("1")).isEqualTo(1);
store.removeMessageGroup("1");
assertThat(store.getMessageCountForAllMessageGroups()).isEqualTo(0);
assertThat(store.messageGroupSize("1")).isEqualTo(0);
}
protected abstract MessageGroupStore getMessageGroupStore();
protected abstract MessageStore getMessageStore();