blob: f1183c5e065266edb039494c444a3edb7da184ea [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.io.Serializable;
19import java.util.ArrayList;
20import java.util.Arrays;
21import java.util.Map;
22import java.util.HashMap;
23import java.util.Set;
24import java.util.TreeMap;
25
26import org.slf4j.Logger;
27import org.slf4j.LoggerFactory;
28
Yuta HIGUCHIdbd5a2f2014-01-23 19:01:13 -080029import com.esotericsoftware.kryo.Kryo;
30import com.esotericsoftware.kryo.io.ByteBufferInput;
31import com.esotericsoftware.kryo.io.Output;
yoshi28bac132014-01-22 11:00:17 -080032import com.tinkerpop.blueprints.Edge;
33import com.tinkerpop.blueprints.Element;
34import com.tinkerpop.blueprints.Vertex;
35import com.tinkerpop.blueprints.util.ExceptionFactory;
36import com.tinkerpop.blueprints.impls.ramcloud.PerfMon;
37
38import edu.stanford.ramcloud.JRamCloud;
39
40public class RamCloudElement implements Element, Serializable {
41
42 private final static Logger log = LoggerFactory.getLogger(RamCloudGraph.class);
43 private byte[] rcPropTableKey;
44 private long rcPropTableId;
45 private RamCloudGraph graph;
46
47 private static final ThreadLocal<Kryo> kryo = new ThreadLocal<Kryo>() {
48 @Override
49 protected Kryo initialValue() {
50 Kryo kryo = new Kryo();
51 kryo.setRegistrationRequired(true);
52 kryo.register(String.class);
53 kryo.register(Long.class);
54 kryo.register(Integer.class);
55 kryo.register(Short.class);
56 kryo.register(Byte.class);
57 kryo.register(TreeMap.class);
58 kryo.register(ArrayList.class);
59 kryo.setReferences(false);
60 return kryo;
61 }
62 };
63
64 public RamCloudElement() {
65 }
66
67 public RamCloudElement(byte[] rcPropTableKey, long rcPropTableId, RamCloudGraph graph) {
68 this.rcPropTableKey = rcPropTableKey;
69 this.rcPropTableId = rcPropTableId;
70 this.graph = graph;
71 }
72
73 protected Map<String, Object> getPropertyMap() {
74 JRamCloud.Object propTableEntry;
75
76 PerfMon pm = PerfMon.getInstance();
77 try {
78 JRamCloud vertTable = graph.getRcClient();
79 pm.read_start("RamCloudElement getPropertyMap()");
80 propTableEntry = vertTable.read(rcPropTableId, rcPropTableKey);
81 pm.read_end("RamCloudElement getPropertyMap()");
82 if (propTableEntry.value.length > 1024 * 1024 * 0.9) {
83 log.warn("Element[id={}] property map size is near 1MB limit!", new String(rcPropTableKey));
84 }
85 } catch (Exception e) {
86 pm.read_end("RamCloudElement getPropertyMap()");
87 log.warn("Element does not have a property table entry!");
88 return null;
89 }
90
91 return convertRcBytesToPropertyMap(propTableEntry.value);
92 }
93
94 public static Map<String, Object> convertRcBytesToPropertyMapEx(byte[] byteArray) {
95 if (byteArray == null) {
96 log.warn("Got a null byteArray argument");
97 return null;
98 } else if (byteArray.length != 0) {
99 PerfMon pm = PerfMon.getInstance();
100 pm.deser_start("RamCloudElement convertRcBytesToPropertyMapEx()");
101 ByteBufferInput input = new ByteBufferInput(byteArray);
102 TreeMap map = kryo.get().readObject(input, TreeMap.class);
103 pm.deser_end("RamCloudElement convertRcBytesToPropertyMapEx()");
104 return map;
105 } else {
106 return new TreeMap<String, Object>();
107 }
108 }
109
110 public Map<String, Object> convertRcBytesToPropertyMap(byte[] byteArray) {
111 if (byteArray == null) {
112 log.warn("Got a null byteArray argument");
113 return null;
114 } else if (byteArray.length != 0) {
115 PerfMon pm = PerfMon.getInstance();
116 long startTime = 0;
117 if(RamCloudGraph.measureSerializeTimeProp == 1) {
118 startTime = System.nanoTime();
119 }
120 pm.deser_start("RamCloudElement convertRcBytesToPropertyMap()");
121 ByteBufferInput input = new ByteBufferInput(byteArray);
122 TreeMap map = kryo.get().readObject(input, TreeMap.class);
123 pm.deser_end("RamCloudElement convertRcBytesToPropertyMap()");
124 if(RamCloudGraph.measureSerializeTimeProp == 1) {
125 long endTime = System.nanoTime();
126 log.error("Performance element kryo deserialization key {} {} size {}", this, endTime - startTime, byteArray.length);
127 }
128 return map;
129 } else {
130 return new TreeMap<String, Object>();
131 }
132 }
133
134 private void setPropertyMap(Map<String, Object> map) {
135 byte[] rcValue;
136 PerfMon pm = PerfMon.getInstance();
137
138 long startKryoTime = 0;
139 if(RamCloudGraph.measureSerializeTimeProp == 1) {
140 startKryoTime = System.nanoTime();
141 }
142 pm.ser_start("RamCloudElement setPropertyMap()");
143 byte[] rcTemp = new byte[1024*1024];
144 Output output = new Output(rcTemp);
145 kryo.get().writeObject(output, map);
146 long midKryoTime = 0;
147 if(RamCloudGraph.measureSerializeTimeProp == 1) {
148 midKryoTime = System.nanoTime();
149 }
150 rcValue = output.toBytes();
151 pm.ser_end("RamCloudElement setPropertyMap()");
152 if(RamCloudGraph.measureSerializeTimeProp == 1) {
153 long endKryoTime = System.nanoTime();
154 log.error("Performance element kryo serialization key {} mid {}, total {}, size {}", this, midKryoTime - startKryoTime, endKryoTime - startKryoTime, rcValue.length);
155 }
156
157 long startTime = 0;
158 JRamCloud vertTable = graph.getRcClient();
159 if (graph.measureRcTimeProp == 1) {
160 startTime = System.nanoTime();
161 }
162 pm.write_start("RamCloudElement setPropertyMap()");
163 vertTable.write(rcPropTableId, rcPropTableKey, rcValue);
164 pm.write_end("RamCloudElement setPropertyMap()");
165 if (graph.measureRcTimeProp == 1) {
166 long endTime = System.nanoTime();
167 log.error("Performance setPropertyMap write time key {} {}", this, endTime - startTime);
168 }
169 }
170
171 @Override
172 public <T> T getProperty(String key) {
173 Map<String, Object> map = getPropertyMap();
174 return (T) map.get(key);
175 }
176
177 @Override
178 public Set<String> getPropertyKeys() {
179 Map<String, Object> map = getPropertyMap();
180 return map.keySet();
181 }
182
183 public Map<String, Object> getProperties() {
184 return getPropertyMap();
185 }
186 public void setProperties(Map<String, Object> properties) {
187 Map<String, Object> map = getPropertyMap();
188 Map<String, Object> oldValueMap = new HashMap<String, Object>(map.size());
189 for (Map.Entry<String, Object> property : properties.entrySet()) {
190 String key = property.getKey();
191 if (key == null) {
192 throw ExceptionFactory.propertyKeyCanNotBeNull();
193 }
194
195 if (key.equals("")) {
196 throw ExceptionFactory.propertyKeyCanNotBeEmpty();
197 }
198
199 if (key.equals("id")) {
200 throw ExceptionFactory.propertyKeyIdIsReserved();
201 }
202
203 if (this instanceof RamCloudEdge && key.equals("label")) {
204 throw ExceptionFactory.propertyKeyLabelIsReservedForEdges();
205 }
206 Object value = property.getValue();
207 if (value == null) {
208 throw ExceptionFactory.propertyValueCanNotBeNull();
209 }
210
211 oldValueMap.put(key, map.put(key, value));
212
213 }
214 setPropertyMap(map);
215
216 // TODO use multi-write
217 for (Map.Entry<String, Object> oldProperty : oldValueMap.entrySet()) {
218 String key = oldProperty.getKey();
219 Object oldValue = oldProperty.getValue();
220 Object value = map.get(key);
221 if (this instanceof RamCloudVertex) {
222 RamCloudKeyIndex keyIndex = new RamCloudKeyIndex(graph.kidxVertTableId, key, value, graph, Vertex.class);
223 keyIndex.autoUpdate(key, value, oldValue, this);
224 } else {
225 RamCloudKeyIndex keyIndex = new RamCloudKeyIndex(graph.kidxVertTableId, key, value, graph, Edge.class);
226 keyIndex.autoUpdate(key, value, oldValue, this);
227 }
228 }
229 }
230
231 @Override
232 public void setProperty(String key, Object value) {
233 Object oldValue;
234 if (value == null) {
235 throw ExceptionFactory.propertyValueCanNotBeNull();
236 }
237
238 if (key == null) {
239 throw ExceptionFactory.propertyKeyCanNotBeNull();
240 }
241
242 if (key.equals("")) {
243 throw ExceptionFactory.propertyKeyCanNotBeEmpty();
244 }
245
246 if (key.equals("id")) {
247 throw ExceptionFactory.propertyKeyIdIsReserved();
248 }
249
250 if (this instanceof RamCloudEdge && key.equals("label")) {
251 throw ExceptionFactory.propertyKeyLabelIsReservedForEdges();
252 }
253
254 long startTime = 0;
255 if (graph.measureBPTimeProp == 1) {
256 startTime = System.nanoTime();
257 }
258
259 Map<String, Object> map = getPropertyMap();
260 oldValue = map.put(key, value);
261 setPropertyMap(map);
262
263 boolean ret = false;
264 if (this instanceof RamCloudVertex) {
265 RamCloudKeyIndex keyIndex = new RamCloudKeyIndex(graph.kidxVertTableId, key, value, graph, Vertex.class);
266 ret = keyIndex.autoUpdate(key, value, oldValue, this);
267 } else {
268 RamCloudKeyIndex keyIndex = new RamCloudKeyIndex(graph.kidxVertTableId, key, value, graph, Edge.class);
269 keyIndex.autoUpdate(key, value, oldValue, this);
270 }
271
272 if (graph.measureBPTimeProp == 1) {
273 long endTime = System.nanoTime();
274 if (ret) {
275 log.error("Performance vertex setProperty(key {}) which is index total time {}", key, endTime - startTime);
276 } else {
277 log.error("Performance vertex setProperty(key {}) does not index time {}", key, endTime - startTime);
278 }
279 }
280
281 }
282
283 @Override
284 public <T> T removeProperty(String key) {
285 Map<String, Object> map = getPropertyMap();
286 T retVal = (T) map.remove(key);
287 setPropertyMap(map);
288 if (this instanceof RamCloudVertex) {
289 RamCloudKeyIndex keyIndex = new RamCloudKeyIndex(graph.kidxVertTableId, key, retVal, graph, Vertex.class);
290 keyIndex.autoRemove(key, retVal.toString(), this);
291 } else {
292 RamCloudKeyIndex keyIndex = new RamCloudKeyIndex(graph.kidxVertTableId, key, retVal, graph, Edge.class);
293 keyIndex.autoRemove(key, retVal.toString(), this);
294 }
295
296 return retVal;
297 }
298
299 @Override
300 public void remove() {
301 graph.getRcClient().remove(rcPropTableId, rcPropTableKey);
302 }
303
304 @Override
305 public Object getId() {
306 // TODO Auto-generated method stub
307 return null;
308 }
309
310 @Override
311 public String toString() {
312 return "RamCloudElement [rcPropTableKey=" + Arrays.toString(rcPropTableKey)
313 + ", rcPropTableId=" + rcPropTableId + "]";
314 }
315}