blob: c0346c35d7c12f8b767681ef5bb26e06aa8d05fb [file] [log] [blame]
Yuta HIGUCHIa1e655a2014-01-23 17:43:11 -08001/* Copyright (c) 2013 Stanford University
2 *
3 * Permission to use, copy, modify, and distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
yoshi28bac132014-01-22 11:00:17 -080016package com.tinkerpop.blueprints.impls.ramcloud;
17
18import java.nio.BufferUnderflowException;
19import java.nio.ByteBuffer;
20import java.nio.ByteOrder;
21import java.util.Arrays;
22
23import org.slf4j.Logger;
24import org.slf4j.LoggerFactory;
25
26import com.sun.jersey.core.util.Base64;
27import com.tinkerpop.blueprints.Direction;
28import com.tinkerpop.blueprints.Edge;
29import com.tinkerpop.blueprints.Vertex;
30import com.tinkerpop.blueprints.util.ExceptionFactory;
31import com.tinkerpop.blueprints.impls.ramcloud.PerfMon;
32import edu.stanford.ramcloud.JRamCloud;
33
34public class RamCloudEdge extends RamCloudElement implements Edge {
35
36 private final static Logger log = LoggerFactory.getLogger(RamCloudGraph.class);
37 private RamCloudVertex outVertex;
38 private RamCloudVertex inVertex;
39 private String label;
40 private byte[] rcKey;
41 private RamCloudGraph graph;
42
43 public RamCloudEdge(RamCloudVertex outVertex, RamCloudVertex inVertex, String label, RamCloudGraph graph) {
44 super(edgeToRcKey(outVertex, inVertex, label), graph.edgePropTableId, graph);
45
46 this.outVertex = outVertex;
47 this.inVertex = inVertex;
48 this.label = label;
49 this.rcKey = edgeToRcKey(outVertex, inVertex, label);
50 this.graph = graph;
51 }
52
53 public RamCloudEdge(byte[] rcKey, RamCloudGraph graph) {
54 super(rcKey, graph.edgePropTableId, graph);
55
56 ByteBuffer edgeId = ByteBuffer.wrap(rcKey).order(ByteOrder.LITTLE_ENDIAN);
57 outVertex = new RamCloudVertex(edgeId.getLong(), graph);
58 inVertex = new RamCloudVertex(edgeId.getLong(), graph);
59 label = new String(rcKey, 16, rcKey.length - 16);
60
61 this.rcKey = rcKey;
62 this.graph = graph;
63 }
64
65 private static byte[] edgeToRcKey(RamCloudVertex outVertex, RamCloudVertex inVertex, String label) {
66 return ByteBuffer.allocate(16 + label.length()).order(ByteOrder.LITTLE_ENDIAN).putLong((Long) outVertex.getId()).putLong((Long) inVertex.getId()).put(label.getBytes()).array();
67 }
68
69 @Override
70 public Vertex getVertex(Direction direction) throws IllegalArgumentException {
71 if (direction.equals(Direction.OUT)) {
72 return outVertex;
73 } else if (direction.equals(Direction.IN)) {
74 return inVertex;
75 } else {
76 throw ExceptionFactory.bothIsNotSupported();
77 }
78 }
79
80 @Override
81 public String getLabel() {
82 return label;
83 }
84
85 public boolean isLoop() {
86 return outVertex.equals(inVertex);
87 }
88
89 public Vertex getNeighbor(Vertex vertex) {
90 if (outVertex.equals(vertex)) {
91 return inVertex;
92 } else if (inVertex.equals(vertex)) {
93 return outVertex;
94 } else {
95 return null;
96 }
97 }
98
99 @Override
100 public void remove() {
101 if (isLoop()) {
102 outVertex.removeEdgeFromAdjList(this);
103 } else {
104 outVertex.removeEdgeFromAdjList(this);
105 inVertex.removeEdgeFromAdjList(this);
106 }
107
108 super.remove();
109 }
110
111 void removeProperties() {
112 super.remove();
113 }
114
115 @Override
116 public Object getId() {
117 return new String(Base64.encode(rcKey));
118 }
119
120 public boolean exists() {
121 boolean edgePropTableEntryExists;
122 boolean outVertexEntryExists;
123 boolean inVertexEntryExists;
124
125 PerfMon pm = PerfMon.getInstance();
126 try {
127 JRamCloud edgeTable = graph.getRcClient();
128 pm.read_start("RamCloudEdge exists()");
129 edgeTable.read(graph.edgePropTableId, rcKey);
130 pm.read_end("RamCloudEdge exists()");
131 edgePropTableEntryExists = true;
132 } catch (Exception e) {
133 pm.read_end("RamCloudEdge exists()");
134 // Edge property table entry does not exist
135 edgePropTableEntryExists = false;
136 }
137
138 outVertexEntryExists = outVertex.getEdgeSet().contains(this);
139
140 if (!outVertex.equals(inVertex)) {
141 inVertexEntryExists = inVertex.getEdgeSet().contains(this);
142 } else {
143 inVertexEntryExists = outVertexEntryExists;
144 }
145
146 if (edgePropTableEntryExists && outVertexEntryExists && inVertexEntryExists) {
147 return true;
148 } else if (!edgePropTableEntryExists && !outVertexEntryExists && !inVertexEntryExists) {
149 return false;
150 } else {
151 log.warn("{}: Detected RamCloudGraph inconsistency: edgePropTableEntryExists={}, outVertexEntryExists={}, inVertexEntryExists={}.", this, edgePropTableEntryExists, outVertexEntryExists, inVertexEntryExists);
152 return true;
153 }
154 }
155
156 public void create() throws Exception {
157 // TODO: Existence check costs extra (presently 3 reads), could use option to turn on/off
158 if (!exists()) {
159 PerfMon pm = PerfMon.getInstance();
160 // create edge property table
161 JRamCloud edgeTable = graph.getRcClient();
162 pm.write_start("RamCloudEdge create()");
163 edgeTable.write(graph.edgePropTableId, rcKey, ByteBuffer.allocate(0).array());
164 pm.write_end("RamCloudEdge create()");
165
166 boolean addSucc = outVertex.addEdgeToAdjList(this);
167 if ( !addSucc ) {
168 edgeTable.remove(graph.edgePropTableId, rcKey);
169 throw ExceptionFactory.edgeWithIdAlreadyExist(rcKey);
170 }
171 if (!isLoop()) {
172 addSucc = inVertex.addEdgeToAdjList(this);
173 if ( !addSucc ) {
174 edgeTable.remove(graph.edgePropTableId, rcKey);
175 outVertex.removeEdgeFromAdjList(this);
176 throw ExceptionFactory.edgeWithIdAlreadyExist(rcKey);
177 }
178 }
179 } else {
180 throw ExceptionFactory.edgeWithIdAlreadyExist(rcKey);
181 }
182 }
183
184 public static boolean isValidEdgeId(byte[] id) {
185 if (id == null) {
186 return false;
187 }
188 if (id.length == 0) {
189 return false;
190 }
191
192 ByteBuffer edgeId = ByteBuffer.wrap(id);
193 try {
194 edgeId.getLong();
195 } catch (BufferUnderflowException e) {
196 return false;
197 }
198
199 try {
200 edgeId.getLong();
201 } catch (BufferUnderflowException e) {
202 return false;
203 }
204
205 if (edgeId.remaining() == 0) {
206 return false;
207 }
208
209 return true;
210 }
211
212 @Override
213 public int hashCode() {
214 return Arrays.hashCode(rcKey);
215 }
216
217 @Override
218 public boolean equals(Object obj) {
219 if (this == obj) {
220 return true;
221 }
222 if (obj == null) {
223 return false;
224 }
225 if (getClass() != obj.getClass()) {
226 return false;
227 }
228 RamCloudEdge other = (RamCloudEdge) obj;
229 return Arrays.equals(rcKey, other.rcKey);
230 }
231
232 @Override
233 public String toString() {
234 return "RamCloudEdge [outVertex=" + outVertex + ", inVertex=" + inVertex
235 + ", label=" + label + "]";
236 }
237}