Skip to content

Commit 90b01d2

Browse files
authored
Merge pull request #376 from lutovich/1.4-multiple-bookmarks
Multiple bookmarks
2 parents 5708274 + 9bcd4b2 commit 90b01d2

23 files changed

+589
-91
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright (c) 2002-2017 "Neo Technology,"
3+
* Network Engine for Objects in Lund AB [http://neotechnology.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
package org.neo4j.driver.internal;
20+
21+
import java.util.Collections;
22+
import java.util.HashMap;
23+
import java.util.Iterator;
24+
import java.util.Map;
25+
26+
import org.neo4j.driver.v1.Value;
27+
28+
import static java.util.Collections.emptyMap;
29+
import static java.util.Collections.singleton;
30+
import static org.neo4j.driver.v1.Values.value;
31+
32+
public final class Bookmark
33+
{
34+
private static final String BOOKMARK_KEY = "bookmark";
35+
private static final String BOOKMARKS_KEY = "bookmarks";
36+
private static final String BOOKMARK_PREFIX = "neo4j:bookmark:v1:tx";
37+
38+
private static final long UNKNOWN_BOOKMARK_VALUE = -1;
39+
40+
private static final Bookmark EMPTY = new Bookmark( Collections.<String>emptySet() );
41+
42+
private final Iterable<String> values;
43+
private final String maxValue;
44+
45+
private Bookmark( Iterable<String> values )
46+
{
47+
this.values = values;
48+
this.maxValue = maxBookmark( values );
49+
}
50+
51+
public static Bookmark empty()
52+
{
53+
return EMPTY;
54+
}
55+
56+
public static Bookmark from( String value )
57+
{
58+
if ( value == null )
59+
{
60+
return empty();
61+
}
62+
return from( singleton( value ) );
63+
}
64+
65+
public static Bookmark from( Iterable<String> values )
66+
{
67+
if ( values == null )
68+
{
69+
return empty();
70+
}
71+
return new Bookmark( values );
72+
}
73+
74+
public boolean isEmpty()
75+
{
76+
return maxValue == null;
77+
}
78+
79+
public String maxBookmarkAsString()
80+
{
81+
return maxValue;
82+
}
83+
84+
public Map<String,Value> asBeginTransactionParameters()
85+
{
86+
if ( isEmpty() )
87+
{
88+
return emptyMap();
89+
}
90+
91+
// Driver sends {bookmark: "max", bookmarks: ["one", "two", "max"]} instead of simple
92+
// {bookmarks: ["one", "two", "max"]} for backwards compatibility reasons. Old servers can only accept single
93+
// bookmark that is why driver has to parse and compare given list of bookmarks. This functionality will
94+
// eventually be removed.
95+
Map<String,Value> parameters = new HashMap<>( 4 );
96+
parameters.put( BOOKMARK_KEY, value( maxValue ) );
97+
parameters.put( BOOKMARKS_KEY, value( values ) );
98+
return parameters;
99+
}
100+
101+
@Override
102+
public String toString()
103+
{
104+
return "Bookmark{values=" + values + "}";
105+
}
106+
107+
private static String maxBookmark( Iterable<String> bookmarks )
108+
{
109+
if ( bookmarks == null )
110+
{
111+
return null;
112+
}
113+
114+
Iterator<String> iterator = bookmarks.iterator();
115+
116+
if ( !iterator.hasNext() )
117+
{
118+
return null;
119+
}
120+
121+
String maxBookmark = iterator.next();
122+
long maxValue = bookmarkValue( maxBookmark );
123+
124+
while ( iterator.hasNext() )
125+
{
126+
String bookmark = iterator.next();
127+
long value = bookmarkValue( bookmark );
128+
129+
if ( value > maxValue )
130+
{
131+
maxBookmark = bookmark;
132+
maxValue = value;
133+
}
134+
}
135+
136+
return maxBookmark;
137+
}
138+
139+
private static long bookmarkValue( String value )
140+
{
141+
if ( value != null && value.startsWith( BOOKMARK_PREFIX ) )
142+
{
143+
try
144+
{
145+
return Long.parseLong( value.substring( BOOKMARK_PREFIX.length() ) );
146+
}
147+
catch ( NumberFormatException e )
148+
{
149+
return UNKNOWN_BOOKMARK_VALUE;
150+
}
151+
}
152+
return UNKNOWN_BOOKMARK_VALUE;
153+
}
154+
}

driver/src/main/java/org/neo4j/driver/internal/BookmarkCollector.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class BookmarkCollector extends NoOperationCollector
3030
}
3131

3232
@Override
33-
public void bookmark( String bookmark )
33+
public void bookmark( Bookmark bookmark )
3434
{
3535
transaction.setBookmark( bookmark );
3636
}

driver/src/main/java/org/neo4j/driver/internal/ExplicitTransaction.java

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434
import org.neo4j.driver.v1.exceptions.Neo4jException;
3535
import org.neo4j.driver.v1.types.TypeSystem;
3636

37-
import static java.util.Collections.emptyMap;
38-
import static java.util.Collections.singletonMap;
3937
import static org.neo4j.driver.v1.Values.ofValue;
4038
import static org.neo4j.driver.v1.Values.value;
4139

@@ -68,19 +66,19 @@ private enum State
6866
private final SessionResourcesHandler resourcesHandler;
6967
private final Connection conn;
7068

71-
private String bookmark = null;
69+
private Bookmark bookmark = Bookmark.empty();
7270
private State state = State.ACTIVE;
7371

7472
public ExplicitTransaction( Connection conn, SessionResourcesHandler resourcesHandler )
7573
{
76-
this( conn, resourcesHandler, null );
74+
this( conn, resourcesHandler, Bookmark.empty() );
7775
}
7876

79-
ExplicitTransaction( Connection conn, SessionResourcesHandler resourcesHandler, String bookmark )
77+
ExplicitTransaction( Connection conn, SessionResourcesHandler resourcesHandler, Bookmark initialBookmark )
8078
{
8179
this.conn = conn;
8280
this.resourcesHandler = resourcesHandler;
83-
runBeginStatement( conn, bookmark );
81+
runBeginStatement( conn, initialBookmark );
8482
}
8583

8684
@Override
@@ -238,32 +236,28 @@ public synchronized void markToClose()
238236
state = State.FAILED;
239237
}
240238

241-
public String bookmark()
239+
public Bookmark bookmark()
242240
{
243241
return bookmark;
244242
}
245243

246-
void setBookmark( String bookmark )
244+
void setBookmark( Bookmark bookmark )
247245
{
248-
this.bookmark = bookmark;
246+
if ( bookmark != null && !bookmark.isEmpty() )
247+
{
248+
this.bookmark = bookmark;
249+
}
249250
}
250251

251-
private static void runBeginStatement( Connection connection, String bookmark )
252+
private static void runBeginStatement( Connection connection, Bookmark bookmark )
252253
{
253-
Map<String,Value> parameters;
254-
if ( bookmark != null )
255-
{
256-
parameters = singletonMap( "bookmark", value( bookmark ) );
257-
}
258-
else
259-
{
260-
parameters = emptyMap();
261-
}
254+
Bookmark initialBookmark = bookmark == null ? Bookmark.empty() : bookmark;
255+
Map<String,Value> parameters = initialBookmark.asBeginTransactionParameters();
262256

263257
connection.run( "BEGIN", parameters, Collector.NO_OP );
264258
connection.pullAll( Collector.NO_OP );
265259

266-
if ( bookmark != null )
260+
if ( !initialBookmark.isEmpty() )
267261
{
268262
connection.sync();
269263
}

driver/src/main/java/org/neo4j/driver/internal/InternalDriver.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package org.neo4j.driver.internal;
2020

21+
import java.util.Collection;
2122
import java.util.concurrent.atomic.AtomicBoolean;
2223

2324
import org.neo4j.driver.internal.security.SecurityPlan;
@@ -62,7 +63,7 @@ public final Session session()
6263
@Override
6364
public final Session session( AccessMode mode )
6465
{
65-
return session( mode, null );
66+
return newSession( mode, Bookmark.empty() );
6667
}
6768

6869
@Override
@@ -73,6 +74,23 @@ public final Session session( String bookmark )
7374

7475
@Override
7576
public final Session session( AccessMode mode, String bookmark )
77+
{
78+
return newSession( mode, Bookmark.from( bookmark ) );
79+
}
80+
81+
@Override
82+
public Session session( Iterable<String> bookmarks )
83+
{
84+
return session( AccessMode.WRITE, bookmarks );
85+
}
86+
87+
@Override
88+
public Session session( AccessMode mode, Iterable<String> bookmarks )
89+
{
90+
return newSession( mode, Bookmark.from( bookmarks ) );
91+
}
92+
93+
private Session newSession( AccessMode mode, Bookmark bookmark )
7694
{
7795
assertOpen();
7896
Session session = sessionFactory.newInstance( mode, bookmark );

driver/src/main/java/org/neo4j/driver/internal/InternalStatementResult.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ public void notifications( List<Notification> notifications )
138138
}
139139

140140
@Override
141-
public void bookmark( String bookmark )
141+
public void bookmark( Bookmark bookmark )
142142
{
143143
if ( transaction != null )
144144
{

driver/src/main/java/org/neo4j/driver/internal/NetworkSession.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public class NetworkSession implements Session, SessionResourcesHandler
5353
private final RetryLogic retryLogic;
5454
protected final Logger logger;
5555

56-
private String bookmark;
56+
private Bookmark bookmark = Bookmark.empty();
5757
private PooledConnection currentConnection;
5858
private ExplicitTransaction currentTransaction;
5959

@@ -179,7 +179,7 @@ public synchronized Transaction beginTransaction()
179179
@Override
180180
public synchronized Transaction beginTransaction( String bookmark )
181181
{
182-
setBookmark( bookmark );
182+
setBookmark( Bookmark.from( bookmark ) );
183183
return beginTransaction();
184184
}
185185

@@ -195,12 +195,9 @@ public <T> T writeTransaction( TransactionWork<T> work )
195195
return transaction( AccessMode.WRITE, work );
196196
}
197197

198-
// Internal method for setting the bookmark explicitly, mainly for testing.
199-
// This method does not prevent setting the bookmark to null since that
200-
// is a valid requirement for some test scenarios.
201-
void setBookmark( String bookmark )
198+
void setBookmark( Bookmark bookmark )
202199
{
203-
if( bookmark != null )
200+
if ( bookmark != null && !bookmark.isEmpty() )
204201
{
205202
this.bookmark = bookmark;
206203
}
@@ -209,7 +206,7 @@ void setBookmark( String bookmark )
209206
@Override
210207
public String lastBookmark()
211208
{
212-
return bookmark;
209+
return bookmark == null ? null : bookmark.maxBookmarkAsString();
213210
}
214211

215212
@Override

driver/src/main/java/org/neo4j/driver/internal/SessionFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@
2323

2424
public interface SessionFactory extends AutoCloseable
2525
{
26-
Session newInstance( AccessMode mode, String bookmark );
26+
Session newInstance( AccessMode mode, Bookmark bookmark );
2727
}

driver/src/main/java/org/neo4j/driver/internal/SessionFactoryImpl.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727

2828
public class SessionFactoryImpl implements SessionFactory
2929
{
30-
protected final ConnectionProvider connectionProvider;
31-
protected final RetryLogic retryLogic;
32-
protected final Logging logging;
33-
protected final boolean leakedSessionsLoggingEnabled;
30+
private final ConnectionProvider connectionProvider;
31+
private final RetryLogic retryLogic;
32+
private final Logging logging;
33+
private final boolean leakedSessionsLoggingEnabled;
3434

3535
SessionFactoryImpl( ConnectionProvider connectionProvider, RetryLogic retryLogic, Config config )
3636
{
@@ -41,23 +41,23 @@ public class SessionFactoryImpl implements SessionFactory
4141
}
4242

4343
@Override
44-
public Session newInstance( AccessMode mode, String bookmark )
44+
public final Session newInstance( AccessMode mode, Bookmark bookmark )
4545
{
46-
NetworkSession session;
47-
if ( leakedSessionsLoggingEnabled )
48-
{
49-
session = new LeakLoggingNetworkSession( connectionProvider, mode, retryLogic, logging );
50-
}
51-
else
52-
{
53-
session = new NetworkSession( connectionProvider, mode, retryLogic, logging );
54-
}
46+
NetworkSession session = createSession( connectionProvider, retryLogic, mode, logging );
5547
session.setBookmark( bookmark );
5648
return session;
5749
}
5850

51+
protected NetworkSession createSession( ConnectionProvider connectionProvider, RetryLogic retryLogic,
52+
AccessMode mode, Logging logging )
53+
{
54+
return leakedSessionsLoggingEnabled ?
55+
new LeakLoggingNetworkSession( connectionProvider, mode, retryLogic, logging ) :
56+
new NetworkSession( connectionProvider, mode, retryLogic, logging );
57+
}
58+
5959
@Override
60-
public void close() throws Exception
60+
public final void close() throws Exception
6161
{
6262
connectionProvider.close();
6363
}
@@ -69,7 +69,7 @@ public void close() throws Exception
6969
*
7070
* @return the connection provider used by this factory.
7171
*/
72-
public ConnectionProvider getConnectionProvider()
72+
public final ConnectionProvider getConnectionProvider()
7373
{
7474
return connectionProvider;
7575
}

0 commit comments

Comments
 (0)