Skip to content

Commit 052d716

Browse files
GH-2515 - Add a Noop bookmark manager.
Closes #2515.
1 parent 879355c commit 052d716

File tree

4 files changed

+109
-1
lines changed

4 files changed

+109
-1
lines changed

src/main/asciidoc/appendix/migrating.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ interface and its only implementation `org.springframework.data.neo4j.bookmark.C
141141
SDN uses bookmarks for all transactions, without configuration.
142142
You can remove the bean declaration of `CaffeineBookmarkManager` as well as the dependency to `com.github.ben-manes.caffeine:caffeine`.
143143

144+
If you absolutely must, you can disable the automatic bookmark management by following <<faq.bookmarks.noop, these instructions>>.
145+
144146
[[migrating.autoindex]]
145147
=== Automatic creation of constraints and indexes
146148

src/main/asciidoc/faq/faq.adoc

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ No, you don't.
458458
SDN uses Neo4j Causal Cluster bookmarks internally without any configuration on your side required.
459459
Transactions in the same thread or the same reactive stream following each other will be able to read their previously changed values as you would expect.
460460

461-
[[faq.bookmarks]]
461+
[[faq.bookmarks.seeding]]
462462
== Can I retrieve the latest Bookmarks or seed the transaction manager?
463463

464464
As mentioned briefly in <<migrating.bookmarks>>, there is no need to configure anything with regard to bookmarks.
@@ -498,6 +498,8 @@ import org.neo4j.driver.Driver;
498498
import org.springframework.context.annotation.Bean;
499499
import org.springframework.context.annotation.Configuration;
500500
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
501+
import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager;
502+
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
501503
import org.springframework.transaction.PlatformTransactionManager;
502504
503505
@Configuration
@@ -528,6 +530,46 @@ public class BookmarkSeedingConfig {
528530
WARNING: There is *no* need to do any of these things above, unless your application has the need to access or provide
529531
this data. If in doubt, don't do either.
530532

533+
[[faq.bookmarks.noop]]
534+
== Can I disable bookmark management?
535+
536+
We provide a Noop bookmark manager that effectively disables bookmark management.
537+
538+
WARNING: Use this bookmark manager at your own risk, it will effectively disable any bookmark management by dropping all
539+
bookmarks and never supplying any. In a cluster you will be at a high risk of experiencing stale reads. In a single
540+
instance it will most likely not make any difference.
541+
+
542+
In a cluster this can be a sensible approach only and if only you can tolerate stale reads and are not in danger of
543+
overwriting old data.
544+
545+
You need to provide the following configuration in your system and make sure that SDN uses the transaction manager:
546+
547+
[source,java,indent=0,tabsize=4]
548+
.BookmarksDisabledConfig.java
549+
----
550+
import org.neo4j.driver.Driver;
551+
import org.springframework.context.annotation.Bean;
552+
import org.springframework.context.annotation.Configuration;
553+
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
554+
import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager;
555+
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
556+
import org.springframework.transaction.PlatformTransactionManager;
557+
558+
@Configuration
559+
public class BookmarksDisabledConfig {
560+
561+
@Bean
562+
public PlatformTransactionManager transactionManager(
563+
Driver driver, DatabaseSelectionProvider databaseNameProvider) {
564+
565+
Neo4jBookmarkManager bookmarkManager = Neo4jBookmarkManager.noop(); // <.>
566+
return new Neo4jTransactionManager(
567+
driver, databaseNameProvider, bookmarkManager);
568+
}
569+
}
570+
----
571+
<.> Get an instance of the Noop bookmark manager
572+
531573
[[faq.annotations.specific]]
532574
== Do I need to use Neo4j specific annotations?
533575

src/main/java/org/springframework/data/neo4j/core/transaction/Neo4jBookmarkManager.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,24 @@ public static Neo4jBookmarkManager create(@Nullable Supplier<Set<Bookmark>> book
6060
return new Neo4jBookmarkManager(bookmarksSupplier);
6161
}
6262

63+
/**
64+
* Use this bookmark manager at your own risk, it will effectively disable any bookmark management by dropping all
65+
* bookmarks and never supplying any. In a cluster you will be at a high risk of experiencing stale reads. In a single
66+
* instance it will most likely not make any difference.
67+
* <p>
68+
* In a cluster this can be a sensible approach only and if only you can tolerate stale reads and are not in danger of
69+
* overwriting old data.
70+
*
71+
* @return A noop bookmark manager, dropping new bookmarks immediately, never supplying bookmarks.
72+
* @since 6.1.11
73+
*/
74+
@API(status = API.Status.STABLE, since = "6.1.11")
75+
public static Neo4jBookmarkManager noop() {
76+
return new Neo4jBookmarkManager(null, true);
77+
}
78+
79+
private final boolean noop;
80+
6381
private final Set<Bookmark> bookmarks = new HashSet<>();
6482

6583
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
@@ -72,11 +90,20 @@ public static Neo4jBookmarkManager create(@Nullable Supplier<Set<Bookmark>> book
7290
private ApplicationEventPublisher applicationEventPublisher;
7391

7492
private Neo4jBookmarkManager(@Nullable Supplier<Set<Bookmark>> bookmarksSupplier) {
93+
this(bookmarksSupplier, false);
94+
}
95+
96+
private Neo4jBookmarkManager(@Nullable Supplier<Set<Bookmark>> bookmarksSupplier, boolean noop) {
7597
this.bookmarksSupplier = bookmarksSupplier == null ? () -> Collections.emptySet() : bookmarksSupplier;
98+
this.noop = noop;
7699
}
77100

78101
Collection<Bookmark> getBookmarks() {
79102

103+
if (noop) {
104+
return Collections.emptyList();
105+
}
106+
80107
try {
81108
read.lock();
82109
HashSet<Bookmark> bookmarksToUse = new HashSet<>(this.bookmarks);
@@ -88,6 +115,11 @@ Collection<Bookmark> getBookmarks() {
88115
}
89116

90117
void updateBookmarks(Collection<Bookmark> usedBookmarks, Bookmark lastBookmark) {
118+
119+
if (noop) {
120+
return;
121+
}
122+
91123
try {
92124
write.lock();
93125
bookmarks.removeAll(usedBookmarks);

src/test/java/org/springframework/data/neo4j/core/transaction/Neo4jBookmarkManagerTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.Set;
2525
import java.util.concurrent.atomic.AtomicBoolean;
2626

27+
import org.junit.jupiter.api.Nested;
2728
import org.junit.jupiter.api.Test;
2829
import org.neo4j.driver.Bookmark;
2930

@@ -119,6 +120,37 @@ void updatesPreviouslyUnknownBookmarks() {
119120
assertThat(bookmarkManager.getBookmarks()).containsExactly(newBookmark);
120121
}
121122

123+
@Nested
124+
class NoopTests {
125+
126+
127+
@Test
128+
void shouldAlwaysReturnEmptyList() {
129+
130+
Neo4jBookmarkManager bookmarkManager = Neo4jBookmarkManager.noop();
131+
assertThat(bookmarkManager.getBookmarks())
132+
.isSameAs(Collections.emptyList()) // Might not be that sane to check that but alas
133+
.isEmpty();
134+
}
135+
136+
137+
@Test
138+
void shouldNeverAcceptBookmarks() {
139+
140+
BookmarkForTesting bookmark = new BookmarkForTesting(Collections.singleton("a"));
141+
AtomicBoolean asserted = new AtomicBoolean(false);
142+
143+
final Neo4jBookmarkManager bookmarkManager = Neo4jBookmarkManager.noop();
144+
bookmarkManager.setApplicationEventPublisher(event -> {
145+
assertThat(((Neo4jBookmarksUpdatedEvent) event).getBookmarks()).containsExactly(bookmark);
146+
asserted.set(true);
147+
});
148+
149+
bookmarkManager.updateBookmarks(new HashSet<>(), bookmark);
150+
assertThat(asserted).isFalse();
151+
}
152+
}
153+
122154
static private class BookmarkForTesting implements Bookmark {
123155
private final Set<String> values;
124156

0 commit comments

Comments
 (0)