-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
StoreAbstractRelationshipCursor.java
153 lines (138 loc) · 5.23 KB
/
StoreAbstractRelationshipCursor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
* Copyright (c) 2002-2017 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.api.store;
import org.neo4j.cursor.Cursor;
import org.neo4j.kernel.api.cursor.EntityItemHelper;
import org.neo4j.kernel.impl.locking.Lock;
import org.neo4j.kernel.impl.locking.LockService;
import org.neo4j.kernel.impl.store.RecordCursor;
import org.neo4j.kernel.impl.store.RecordCursors;
import org.neo4j.kernel.impl.store.record.Record;
import org.neo4j.kernel.impl.store.record.RelationshipRecord;
import org.neo4j.kernel.impl.util.InstanceCache;
import org.neo4j.storageengine.api.PropertyItem;
import org.neo4j.storageengine.api.RelationshipItem;
import static org.neo4j.kernel.impl.locking.LockService.NO_LOCK_SERVICE;
import static org.neo4j.kernel.impl.store.record.RecordLoad.FORCE;
/**
* Base cursor for relationships.
*/
public abstract class StoreAbstractRelationshipCursor extends EntityItemHelper implements Cursor<RelationshipItem>, RelationshipItem
{
protected final RelationshipRecord relationshipRecord;
final RecordCursor<RelationshipRecord> relationshipRecordCursor;
private final LockService lockService;
private final InstanceCache<StoreSinglePropertyCursor> singlePropertyCursor;
private final InstanceCache<StorePropertyCursor> allPropertyCursor;
StoreAbstractRelationshipCursor( RelationshipRecord relationshipRecord, RecordCursors cursors,
LockService lockService )
{
this.relationshipRecordCursor = cursors.relationship();
this.relationshipRecord = relationshipRecord;
this.lockService = lockService;
singlePropertyCursor = new InstanceCache<StoreSinglePropertyCursor>()
{
@Override
protected StoreSinglePropertyCursor create()
{
return new StoreSinglePropertyCursor( cursors, this );
}
};
allPropertyCursor = new InstanceCache<StorePropertyCursor>()
{
@Override
protected StorePropertyCursor create()
{
return new StorePropertyCursor( cursors, this );
}
};
}
@Override
public RelationshipItem get()
{
return this;
}
@Override
public long id()
{
return relationshipRecord.getId();
}
@Override
public int type()
{
return relationshipRecord.getType();
}
@Override
public long startNode()
{
return relationshipRecord.getFirstNode();
}
@Override
public long endNode()
{
return relationshipRecord.getSecondNode();
}
@Override
public long otherNode( long nodeId )
{
return relationshipRecord.getFirstNode() == nodeId ?
relationshipRecord.getSecondNode() : relationshipRecord.getFirstNode();
}
private Lock shortLivedReadLock()
{
Lock lock = lockService.acquireRelationshipLock( relationshipRecord.getId(), LockService.LockType.READ_LOCK );
if ( lockService != NO_LOCK_SERVICE )
{
boolean success = false;
try
{
// It's safer to re-read the relationship record here, specifically nextProp, after acquiring the lock
if ( !relationshipRecordCursor.next( relationshipRecord.getId(), relationshipRecord, FORCE ) )
{
// So it looks like the node has been deleted. The current behavior of RelationshipStore#fillRecord
// w/ FORCE is to only set the inUse field on loading an unused record. This should (and will)
// change to be more of a centralized behavior by the stores. Anyway, setting this pointer
// to the primitive equivalent of null the property cursor will just look empty from the
// outside and the releasing of the lock will be done as usual.
relationshipRecord.setNextProp( Record.NO_NEXT_PROPERTY.intValue() );
}
success = true;
}
finally
{
if ( !success )
{
lock.release();
}
}
}
return lock;
}
@Override
public Cursor<PropertyItem> properties()
{
return allPropertyCursor.get().init( relationshipRecord.getNextProp(), shortLivedReadLock() );
}
@Override
public Cursor<PropertyItem> property( int propertyKeyId )
{
return singlePropertyCursor.get().init( relationshipRecord.getNextProp(), propertyKeyId, shortLivedReadLock() );
}
}