blob: b1f3befd1c1eaec07c011ec259c1169d2ae8014b [file] [log] [blame]
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -08001package net.onrc.onos.datastore.topology;
2
3import java.nio.ByteBuffer;
4import java.util.Arrays;
5import java.util.Collection;
6import java.util.Collections;
7import java.util.HashMap;
Yuta HIGUCHI10eebea2014-02-03 10:41:41 -08008import java.util.Iterator;
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -08009import java.util.Map;
10import java.util.Set;
11import java.util.TreeSet;
12
Yuta HIGUCHI1ca1afa2014-02-04 19:33:57 -080013import org.openflow.util.HexString;
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080014import org.slf4j.Logger;
15import org.slf4j.LoggerFactory;
16
17import com.esotericsoftware.kryo.Kryo;
18
Yuta HIGUCHI10eebea2014-02-03 10:41:41 -080019import edu.stanford.ramcloud.JRamCloud;
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080020import net.onrc.onos.datastore.RCObject;
21import net.onrc.onos.datastore.RCTable;
22import net.onrc.onos.datastore.utils.ByteArrayComparator;
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -080023import net.onrc.onos.datastore.utils.ByteArrayUtil;
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080024
25public class RCPort extends RCObject {
26 private static final Logger log = LoggerFactory.getLogger(RCPort.class);
27
28 private static final ThreadLocal<Kryo> portKryo = new ThreadLocal<Kryo>() {
29 @Override
30 protected Kryo initialValue() {
31 Kryo kryo = new Kryo();
32 kryo.setRegistrationRequired(true);
33 kryo.setReferences(false);
34 kryo.register(byte[].class);
35 kryo.register(byte[][].class);
36 kryo.register(HashMap.class);
37 // TODO check if we should explicitly specify EnumSerializer
38 kryo.register(STATUS.class);
39 return kryo;
40 }
41 };
42
43 public static final String GLOBAL_PORT_TABLE_NAME = "G:Port";
44
45 // FIXME these should be Enum or some number, not String
46 private static final String PROP_DPID = "dpid";
47 private static final String PROP_NUMBER = "number";
48 private static final String PROP_STATUS = "status";
49 private static final String PROP_LINK_IDS = "link-ids";
50 private static final String PROP_DEVICE_IDS = "device-ids";
51
52 // must not re-order enum members, ordinal will be sent over wire
53 public enum STATUS {
54 INACTIVE, ACTIVE;
55 }
56
57 private final Long dpid;
58 private final Long number;
59
60 private STATUS status;
61 // XXX These 2 set of Ids can be removed from DataStore, if In-Memory cache
62 // build the indexing info from Link.
Yuta HIGUCHI58c10962014-02-03 19:14:13 -080063 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080064 private TreeSet<byte[]> linkIds;
Yuta HIGUCHI58c10962014-02-03 19:14:13 -080065 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080066 transient boolean isLinkIdsModified;
Yuta HIGUCHI58c10962014-02-03 19:14:13 -080067 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080068 private TreeSet<byte[]> deviceIds;
Yuta HIGUCHI58c10962014-02-03 19:14:13 -080069 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080070 transient boolean isDeviceIdsModified;
71
72 public static final int PORTID_BYTES = RCSwitch.SWITCHID_BYTES + 2 + 8;
73
74 public static byte[] getPortID(Long dpid, Long number) {
75 if (dpid == null) {
76 throw new IllegalArgumentException("dpid cannot be null");
77 }
78 if (number == null) {
79 throw new IllegalArgumentException("number cannot be null");
80 }
81 return ByteBuffer.allocate(PORTID_BYTES).putChar('S').putLong(dpid)
82 .putChar('P').putLong(number).array();
83 }
84
Yuta HIGUCHI1ca1afa2014-02-04 19:33:57 -080085 public static StringBuilder keysToSB(Collection<byte[]> keys) {
86 StringBuilder sb = new StringBuilder();
87 sb.append("[");
88 boolean hasWritten = false;
89 for (byte[] key : keys) {
90 if (hasWritten) {
91 sb.append(", ");
92 }
93 sb.append(keyToString(key));
94 hasWritten = true;
95 }
96 sb.append("]");
97 return sb;
98 }
99
100 public static String keyToString(byte[] key) {
101 // For debug log
102 long[] pair = getPortPairFromKey(key);
103 return "S" + HexString.toHexString(pair[0]) + "P" + pair[1];
104 }
105
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -0800106 public static long[] getPortPairFromKey(byte[] key) {
107 return getPortPairFromKey(ByteBuffer.wrap(key));
108
109 }
110
111 public static long[] getPortPairFromKey(ByteBuffer keyBuf) {
112 long[] pair = new long[2];
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800113 if (keyBuf.getChar() != 'S') {
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -0800114 throw new IllegalArgumentException("Invalid Port key:" + keyBuf
115 + " "
116 + ByteArrayUtil.toHexStringBuffer(keyBuf.array(), ":"));
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800117 }
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -0800118 pair[0] = keyBuf.getLong();
119 if (keyBuf.getChar() != 'P') {
120 throw new IllegalArgumentException("Invalid Port key:" + keyBuf
121 + " "
122 + ByteArrayUtil.toHexStringBuffer(keyBuf.array(), ":"));
123 }
124 pair[1] = keyBuf.getLong();
125 return pair;
126
127 }
128
129 public static long getDpidFromKey(byte[] key) {
130 return getPortPairFromKey(key)[0];
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800131 }
132
133 public static long getNumberFromKey(byte[] key) {
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -0800134 return getPortPairFromKey(key)[1];
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800135 }
136
137 // FIXME specify DPID,number here, or Should caller specify the key it self?
138 // In other words, should layer above have the control of the ID?
139 public RCPort(Long dpid, Long number) {
140 super(RCTable.getTable(GLOBAL_PORT_TABLE_NAME), getPortID(dpid, number));
141
142 // TODO Auto-generated constructor stub
143
144 this.dpid = dpid;
145 this.number = number;
146 this.status = STATUS.INACTIVE;
147 this.linkIds = new TreeSet<>(ByteArrayComparator.BYTEARRAY_COMPARATOR);
148 this.isLinkIdsModified = true;
149 this.deviceIds = new TreeSet<>(ByteArrayComparator.BYTEARRAY_COMPARATOR);
150 this.isDeviceIdsModified = true;
151 }
152
Yuta HIGUCHI10eebea2014-02-03 10:41:41 -0800153 /**
154 * Get an instance from Key.
155 *
156 * @note You need to call `read()` to get the DB content.
157 * @param key
158 * @return RCPort instance
159 */
160 public static <P extends RCObject> P createFromKey(byte[] key) {
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -0800161 long[] pair = getPortPairFromKey(key);
Yuta HIGUCHI10eebea2014-02-03 10:41:41 -0800162 @SuppressWarnings("unchecked")
163 P p = (P) new RCPort(pair[0], pair[1]);
164 return p;
165 }
166
167 public static Iterable<RCPort> getAllPorts() {
168 return new PortEnumerator();
169 }
170
171 public static class PortEnumerator implements Iterable<RCPort> {
172
173 @Override
174 public Iterator<RCPort> iterator() {
175 return new PortIterator();
176 }
177 }
178
179 public static class PortIterator extends ObjectIterator<RCPort> {
180
181 public PortIterator() {
182 super(RCTable.getTable(GLOBAL_PORT_TABLE_NAME));
183 }
184
185 @Override
186 public RCPort next() {
187 JRamCloud.Object o = enumerator.next();
188 RCPort e = RCPort.createFromKey(o.key);
189 e.setValueAndDeserialize(o.value, o.version);
190 return e;
191 }
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800192 }
193
194 public STATUS getStatus() {
195 return status;
196 }
197
198 public void setStatus(STATUS status) {
199 this.status = status;
200 getObjectMap().put(PROP_STATUS, status);
201 }
202
203 public Long getDpid() {
204 return dpid;
205 }
206
207 public Long getNumber() {
208 return number;
209 }
210
211 public byte[] getId() {
212 return getKey();
213 }
214
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800215 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800216 public void addLinkId(byte[] linkId) {
217 isLinkIdsModified |= linkIds.add(linkId);
218 }
219
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800220 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800221 public void removeLinkId(byte[] linkId) {
222 isLinkIdsModified |= linkIds.remove(linkId);
223 }
224
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800225 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800226 public void emptyLinkIds() {
227 linkIds.clear();
228 isLinkIdsModified = true;
229 }
230
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800231 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800232 public void addAllToLinkIds(Collection<byte[]> linkIds) {
233 isLinkIdsModified |= this.linkIds.addAll(linkIds);
234 }
235
236 /**
237 *
238 * @return Unmodifiable Set view of all the LinkIds;
239 */
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800240 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800241 public Set<byte[]> getAllLinkIds() {
242 return Collections.unmodifiableSet(linkIds);
243 }
244
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800245 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800246 public void addDeviceId(byte[] deviceId) {
247 isDeviceIdsModified |= deviceIds.add(deviceId);
248 }
249
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800250 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800251 public void removeDeviceId(byte[] deviceId) {
252 isDeviceIdsModified |= deviceIds.remove(deviceId);
253 }
254
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800255 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800256 public void emptyDeviceIds() {
257 deviceIds.clear();
258 isDeviceIdsModified = true;
259 }
260
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800261 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800262 public void addAllToDeviceIds(Collection<byte[]> deviceIds) {
263 isDeviceIdsModified |= this.deviceIds.addAll(deviceIds);
264 }
265
266 /**
267 *
268 * @return Unmodifiable Set view of all the LinkIds;
269 */
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800270 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800271 public Set<byte[]> getAllDeviceIds() {
272 return Collections.unmodifiableSet(deviceIds);
273 }
274
275 @Override
276 public void serializeAndSetValue() {
277 Map<Object, Object> map = getObjectMap();
278
279 map.put(PROP_DPID, this.dpid);
280 map.put(PROP_NUMBER, this.number);
281 if (isLinkIdsModified) {
282 byte[] linkIdArray[] = new byte[linkIds.size()][];
283 map.put(PROP_LINK_IDS, linkIds.toArray(linkIdArray));
284 isLinkIdsModified = false;
285 }
286 if (isDeviceIdsModified) {
287 byte[] deviceIdArray[] = new byte[deviceIds.size()][];
288 map.put(PROP_DEVICE_IDS, deviceIds.toArray(deviceIdArray));
289 isDeviceIdsModified = false;
290 }
291 if (log.isWarnEnabled() && (linkIds.size() * deviceIds.size()) != 0) {
292 log.warn("Either #LinkIds:{} or #DeviceIds:{} is expected to be 0",
293 linkIds.size(), deviceIds.size());
294 }
295
296 serializeAndSetValue(portKryo.get(), map);
297 }
298
299 @Override
300 public Map<Object, Object> deserializeObjectFromValue() {
301 Map<Object, Object> map = deserializeObjectFromValue(portKryo.get());
302
303 this.status = (STATUS) map.get(PROP_STATUS);
304
305 if (this.linkIds == null) {
306 this.linkIds = new TreeSet<>(
307 ByteArrayComparator.BYTEARRAY_COMPARATOR);
308 }
309 byte[] linkIdArray[] = (byte[][]) map.get(PROP_LINK_IDS);
310 if (linkIdArray != null) {
311 this.linkIds.clear();
312 this.linkIds.addAll(Arrays.asList(linkIdArray));
313 isLinkIdsModified = false;
314 } else {
315 // trigger write on next serialize
316 isLinkIdsModified = true;
317 }
318
319 if (this.deviceIds == null) {
320 this.deviceIds = new TreeSet<>(
321 ByteArrayComparator.BYTEARRAY_COMPARATOR);
322 }
323 byte[] deviceIdArray[] = (byte[][]) map.get(PROP_DEVICE_IDS);
324 if (deviceIdArray != null) {
325 this.deviceIds.clear();
326 this.deviceIds.addAll(Arrays.asList(deviceIdArray));
327 isDeviceIdsModified = false;
328 } else {
329 // trigger write on next serialize
330 isDeviceIdsModified = true;
331 }
332
333 if (log.isWarnEnabled() && (linkIds.size() * deviceIds.size()) != 0) {
334 log.warn("Either #LinkIds:{} or #DeviceIds:{} is expected to be 0",
335 linkIds.size(), deviceIds.size());
336 }
337
338 return map;
339 }
340
341 @Override
342 public String toString() {
343 // TODO OUTPUT ALL?
344 return "[RCPort 0x" + Long.toHexString(dpid) + "@" + number
345 + " STATUS:" + status + "]";
346 }
347
348 public static void main(String[] args) {
349 // TODO Auto-generated method stub
350
351 }
352
353}