@@ -141,6 +141,8 @@ interface and its only implementation `org.springframework.data.neo4j.bookmark.C
|
||||
SDN uses bookmarks for all transactions, without configuration.
|
||||
You can remove the bean declaration of `CaffeineBookmarkManager` as well as the dependency to `com.github.ben-manes.caffeine:caffeine`.
|
||||
|
||||
If you absolutely must, you can disable the automatic bookmark management by following <<faq.bookmarks.noop, these instructions>>.
|
||||
|
||||
[[migrating.autoindex]]
|
||||
=== Automatic creation of constraints and indexes
|
||||
|
||||
|
||||
@@ -458,7 +458,7 @@ No, you don't.
|
||||
SDN uses Neo4j Causal Cluster bookmarks internally without any configuration on your side required.
|
||||
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.
|
||||
|
||||
[[faq.bookmarks]]
|
||||
[[faq.bookmarks.seeding]]
|
||||
== Can I retrieve the latest Bookmarks or seed the transaction manager?
|
||||
|
||||
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;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
|
||||
import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager;
|
||||
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
@Configuration
|
||||
@@ -528,6 +530,46 @@ public class BookmarkSeedingConfig {
|
||||
WARNING: There is *no* need to do any of these things above, unless your application has the need to access or provide
|
||||
this data. If in doubt, don't do either.
|
||||
|
||||
[[faq.bookmarks.noop]]
|
||||
== Can I disable bookmark management?
|
||||
|
||||
We provide a Noop bookmark manager that effectively disables bookmark management.
|
||||
|
||||
WARNING: Use this bookmark manager at your own risk, it will effectively disable any bookmark management by dropping all
|
||||
bookmarks and never supplying any. In a cluster you will be at a high risk of experiencing stale reads. In a single
|
||||
instance it will most likely not make any difference.
|
||||
+
|
||||
In a cluster this can be a sensible approach only and if only you can tolerate stale reads and are not in danger of
|
||||
overwriting old data.
|
||||
|
||||
You need to provide the following configuration in your system and make sure that SDN uses the transaction manager:
|
||||
|
||||
[source,java,indent=0,tabsize=4]
|
||||
.BookmarksDisabledConfig.java
|
||||
----
|
||||
import org.neo4j.driver.Driver;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
|
||||
import org.springframework.data.neo4j.core.transaction.Neo4jBookmarkManager;
|
||||
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
@Configuration
|
||||
public class BookmarksDisabledConfig {
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager(
|
||||
Driver driver, DatabaseSelectionProvider databaseNameProvider) {
|
||||
|
||||
Neo4jBookmarkManager bookmarkManager = Neo4jBookmarkManager.noop(); // <.>
|
||||
return new Neo4jTransactionManager(
|
||||
driver, databaseNameProvider, bookmarkManager);
|
||||
}
|
||||
}
|
||||
----
|
||||
<.> Get an instance of the Noop bookmark manager
|
||||
|
||||
[[faq.annotations.specific]]
|
||||
== Do I need to use Neo4j specific annotations?
|
||||
|
||||
|
||||
@@ -60,6 +60,24 @@ public final class Neo4jBookmarkManager {
|
||||
return new Neo4jBookmarkManager(bookmarksSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this bookmark manager at your own risk, it will effectively disable any bookmark management by dropping all
|
||||
* bookmarks and never supplying any. In a cluster you will be at a high risk of experiencing stale reads. In a single
|
||||
* instance it will most likely not make any difference.
|
||||
* <p>
|
||||
* In a cluster this can be a sensible approach only and if only you can tolerate stale reads and are not in danger of
|
||||
* overwriting old data.
|
||||
*
|
||||
* @return A noop bookmark manager, dropping new bookmarks immediately, never supplying bookmarks.
|
||||
* @since 6.1.11
|
||||
*/
|
||||
@API(status = API.Status.STABLE, since = "6.1.11")
|
||||
public static Neo4jBookmarkManager noop() {
|
||||
return new Neo4jBookmarkManager(null, true);
|
||||
}
|
||||
|
||||
private final boolean noop;
|
||||
|
||||
private final Set<Bookmark> bookmarks = new HashSet<>();
|
||||
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
@@ -72,11 +90,20 @@ public final class Neo4jBookmarkManager {
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
private Neo4jBookmarkManager(@Nullable Supplier<Set<Bookmark>> bookmarksSupplier) {
|
||||
this(bookmarksSupplier, false);
|
||||
}
|
||||
|
||||
private Neo4jBookmarkManager(@Nullable Supplier<Set<Bookmark>> bookmarksSupplier, boolean noop) {
|
||||
this.bookmarksSupplier = bookmarksSupplier == null ? () -> Collections.emptySet() : bookmarksSupplier;
|
||||
this.noop = noop;
|
||||
}
|
||||
|
||||
Collection<Bookmark> getBookmarks() {
|
||||
|
||||
if (noop) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
try {
|
||||
read.lock();
|
||||
HashSet<Bookmark> bookmarksToUse = new HashSet<>(this.bookmarks);
|
||||
@@ -88,6 +115,11 @@ public final class Neo4jBookmarkManager {
|
||||
}
|
||||
|
||||
void updateBookmarks(Collection<Bookmark> usedBookmarks, Bookmark lastBookmark) {
|
||||
|
||||
if (noop) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
write.lock();
|
||||
bookmarks.removeAll(usedBookmarks);
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.neo4j.driver.Bookmark;
|
||||
|
||||
@@ -119,6 +120,37 @@ class Neo4jBookmarkManagerTest {
|
||||
assertThat(bookmarkManager.getBookmarks()).containsExactly(newBookmark);
|
||||
}
|
||||
|
||||
@Nested
|
||||
class NoopTests {
|
||||
|
||||
|
||||
@Test
|
||||
void shouldAlwaysReturnEmptyList() {
|
||||
|
||||
Neo4jBookmarkManager bookmarkManager = Neo4jBookmarkManager.noop();
|
||||
assertThat(bookmarkManager.getBookmarks())
|
||||
.isSameAs(Collections.emptyList()) // Might not be that sane to check that but alas
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void shouldNeverAcceptBookmarks() {
|
||||
|
||||
BookmarkForTesting bookmark = new BookmarkForTesting(Collections.singleton("a"));
|
||||
AtomicBoolean asserted = new AtomicBoolean(false);
|
||||
|
||||
final Neo4jBookmarkManager bookmarkManager = Neo4jBookmarkManager.noop();
|
||||
bookmarkManager.setApplicationEventPublisher(event -> {
|
||||
assertThat(((Neo4jBookmarksUpdatedEvent) event).getBookmarks()).containsExactly(bookmark);
|
||||
asserted.set(true);
|
||||
});
|
||||
|
||||
bookmarkManager.updateBookmarks(new HashSet<>(), bookmark);
|
||||
assertThat(asserted).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
static private class BookmarkForTesting implements Bookmark {
|
||||
private final Set<String> values;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user