Can't update objects in the index

70 views
Skip to first unread message

Clay Embry

unread,
Sep 1, 2021, 4:48:12 PM9/1/21
to cqengine-discuss
Hi. I've spent a couple of days trying to successfully update objects in an index. I've tried a few different approaches which I took from the documentation, but I've not had success. I have run into a variety of strange problems. The latest is a test I created that uses TransactionalIndexedCollection and simply adds an object to the index, creates another object which is identical to the first except for one changed field, retrieves the first object, and then uses index.update() to replace the first object with the new object.

When I run the test, the test never returns from the the index.update call. When I hook up a debugger and pause execution, it shows the thread stuck in park. So it seems like I'm hitting some kind of deadlock.

Here's my test method. Can anyone see anything glaringly wrong with what I'm attempting to do here?

```
@Test
void testUpdateTicket() {
// setup
final String ticketJiraId = "123456";

final Ticket existingTicket = Ticket.builder()
.jiraId(ticketJiraId)
.issueType(IssueType.builder()
.name("Ticket")
.build())
.status(RequestStatus.builder()
.text("Open")
.category(RequestStatusCategory.OPEN)
.build())
.summary("Existing Ticket")
.build();

ticketIndex.add(existingTicket);

final Ticket updatedTicket = existingTicket.toBuilder()
.summary("Updated Ticket")
.build();

final List<Ticket> ticketsToRemove = retrieveTicketsWithJiraId(ticketJiraId).stream()
.filter(ticketToRemove -> !ticketToRemove.equals(updatedTicket))
.collect(Collectors.toList());

// act
ticketIndex.update(ticketsToRemove, Collections.singletonList(updatedTicket));

// verify
final List<Ticket> shouldBeUpdatedTicketList = retrieveTicketsWithJiraId(ticketJiraId);
assertThat(shouldBeUpdatedTicketList).containsExactly(updatedTicket);
}
```

I'm going to work on paring this down into an even simpler self-contained test (it came from a real-world codebase), but I'm hoping to get a conversation started in the meantime. Thank you.
 - Clay

Niall Gallagher

unread,
Sep 1, 2021, 5:15:42 PM9/1/21
to cqengine...@googlegroups.com
Try closing the stream. When using the TransactionalIndexedCollection it is necessary to close the streams or ResultSets to let it know when you have finished reading it.

--
-- You received this message because you are subscribed to the "cqengine-discuss" group.
http://groups.google.com/group/cqengine-discuss
---
You received this message because you are subscribed to the Google Groups "cqengine-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cqengine-discu...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cqengine-discuss/6c1a9c9b-4b37-4db4-ada8-f3313485e3f8n%40googlegroups.com.

Clay Embry

unread,
Sep 1, 2021, 5:50:56 PM9/1/21
to cqengine-discuss
Oh my gosh. Thanks. My simple test is passing now. I know I saw that in the documentation at some point as well. Didn't manage to retain it when I needed it. I really appreciate the quick response.
 - Clay

Niall Gallagher

unread,
Sep 1, 2021, 6:30:36 PM9/1/21
to cqengine...@googlegroups.com

Clay Embry

unread,
Sep 1, 2021, 7:14:09 PM9/1/21
to cqengine-discuss
My test case works, but now I'm back to my original problem when I run my app. Instead of an updated object in the index, my queries end up returning duplicates of the object I was trying to update. One duplicate per update. And all the duplicates have the original object field data, not the updated field data. Can you think of anything that would cause that to happen? I'm still working on trying to create a reproducible test case. What I have in the test above is the same update code that my app uses. The main differences are the index size in my app is about 700 objects, the Ticket objects have more fields set, and the app has multiple request threads updating and querying the index. So I'm going to try to simulate all of those differences in my test. Thanks again for your help.

Clay Embry

unread,
Sep 1, 2021, 8:31:27 PM9/1/21
to cqengine-discuss
This is the crux of the problem when I run my app. Here is my update code where I added a bit of logging.

final List<Ticket> ticketsToRemove = retrieveTicketsWithJiraId(ticket.getJiraId()).stream()
     .filter(ticketToRemove -> !ticketToRemove.equals(ticket))
     .collect(Collectors.toList());
if (ticketsToRemove.size() == 1) {
     log.info("ticketIndex contains ticket that was just retrieved: " + ticketIndex.contains(ticketsToRemove.get(0)));
}
ticketIndex.update(ticketsToRemove, Collections.singletonList(ticket));

When I run that code in my app and trigger a Ticket update, I see this output:

00:19:47 INFO  [c.a.c.s.i.i.CollectionQueryTicketIndex] ticketIndex contains ticket that was just retrieved: false

So I think the reason that it doesn't remove the "old" version of the Ticket object is because it doesn't see that object in the Collection. Even though it just retrieved that object from the Collection. The next time I run my query for that object, I get two results back. The "old" and the "updated" version of the Ticket object. My Ticket object is immutable (all fields are final) and I have equals and hashCode implemented via Lombok @Data annotation. There is nothing else updating the ticketIndex while I run the update code above, but there are lots of queries going on at the same time.

I haven't yet been able to recreate the problem in a test, but it happens consistently when I have the app running. Any ideas what I could be doing wrong? Thanks.
 - Clay

Clay Embry

unread,
Sep 2, 2021, 12:13:32 PM9/2/21
to cqengine-discuss
Never mind. I found the deeply nested object in the Ticket fields that was, in fact, being mutated. Thanks again for your help.
Reply all
Reply to author
Forward
0 new messages