blob: 1bbb3eb2921e854dee5cb9dfd2056d00b4e6ea67 [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
13import org.slf4j.Logger;
14import org.slf4j.LoggerFactory;
15
16import com.esotericsoftware.kryo.Kryo;
17
Yuta HIGUCHI10eebea2014-02-03 10:41:41 -080018import edu.stanford.ramcloud.JRamCloud;
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080019import net.onrc.onos.datastore.RCObject;
20import net.onrc.onos.datastore.RCTable;
21import net.onrc.onos.datastore.utils.ByteArrayComparator;
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -080022import net.onrc.onos.datastore.utils.ByteArrayUtil;
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080023
24public class RCPort extends RCObject {
25 private static final Logger log = LoggerFactory.getLogger(RCPort.class);
26
27 private static final ThreadLocal<Kryo> portKryo = new ThreadLocal<Kryo>() {
28 @Override
29 protected Kryo initialValue() {
30 Kryo kryo = new Kryo();
31 kryo.setRegistrationRequired(true);
32 kryo.setReferences(false);
33 kryo.register(byte[].class);
34 kryo.register(byte[][].class);
35 kryo.register(HashMap.class);
36 // TODO check if we should explicitly specify EnumSerializer
37 kryo.register(STATUS.class);
38 return kryo;
39 }
40 };
41
42 public static final String GLOBAL_PORT_TABLE_NAME = "G:Port";
43
44 // FIXME these should be Enum or some number, not String
45 private static final String PROP_DPID = "dpid";
46 private static final String PROP_NUMBER = "number";
47 private static final String PROP_STATUS = "status";
48 private static final String PROP_LINK_IDS = "link-ids";
49 private static final String PROP_DEVICE_IDS = "device-ids";
50
51 // must not re-order enum members, ordinal will be sent over wire
52 public enum STATUS {
53 INACTIVE, ACTIVE;
54 }
55
56 private final Long dpid;
57 private final Long number;
58
59 private STATUS status;
60 // XXX These 2 set of Ids can be removed from DataStore, if In-Memory cache
61 // build the indexing info from Link.
Yuta HIGUCHI58c10962014-02-03 19:14:13 -080062 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080063 private TreeSet<byte[]> linkIds;
Yuta HIGUCHI58c10962014-02-03 19:14:13 -080064 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080065 transient boolean isLinkIdsModified;
Yuta HIGUCHI58c10962014-02-03 19:14:13 -080066 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080067 private TreeSet<byte[]> deviceIds;
Yuta HIGUCHI58c10962014-02-03 19:14:13 -080068 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080069 transient boolean isDeviceIdsModified;
70
71 public static final int PORTID_BYTES = RCSwitch.SWITCHID_BYTES + 2 + 8;
72
73 public static byte[] getPortID(Long dpid, Long number) {
74 if (dpid == null) {
75 throw new IllegalArgumentException("dpid cannot be null");
76 }
77 if (number == null) {
78 throw new IllegalArgumentException("number cannot be null");
79 }
80 return ByteBuffer.allocate(PORTID_BYTES).putChar('S').putLong(dpid)
81 .putChar('P').putLong(number).array();
82 }
83
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -080084 public static long[] getPortPairFromKey(byte[] key) {
85 return getPortPairFromKey(ByteBuffer.wrap(key));
86
87 }
88
89 public static long[] getPortPairFromKey(ByteBuffer keyBuf) {
90 long[] pair = new long[2];
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080091 if (keyBuf.getChar() != 'S') {
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -080092 throw new IllegalArgumentException("Invalid Port key:" + keyBuf
93 + " "
94 + ByteArrayUtil.toHexStringBuffer(keyBuf.array(), ":"));
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -080095 }
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -080096 pair[0] = keyBuf.getLong();
97 if (keyBuf.getChar() != 'P') {
98 throw new IllegalArgumentException("Invalid Port key:" + keyBuf
99 + " "
100 + ByteArrayUtil.toHexStringBuffer(keyBuf.array(), ":"));
101 }
102 pair[1] = keyBuf.getLong();
103 return pair;
104
105 }
106
107 public static long getDpidFromKey(byte[] key) {
108 return getPortPairFromKey(key)[0];
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800109 }
110
111 public static long getNumberFromKey(byte[] key) {
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -0800112 return getPortPairFromKey(key)[1];
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800113 }
114
115 // FIXME specify DPID,number here, or Should caller specify the key it self?
116 // In other words, should layer above have the control of the ID?
117 public RCPort(Long dpid, Long number) {
118 super(RCTable.getTable(GLOBAL_PORT_TABLE_NAME), getPortID(dpid, number));
119
120 // TODO Auto-generated constructor stub
121
122 this.dpid = dpid;
123 this.number = number;
124 this.status = STATUS.INACTIVE;
125 this.linkIds = new TreeSet<>(ByteArrayComparator.BYTEARRAY_COMPARATOR);
126 this.isLinkIdsModified = true;
127 this.deviceIds = new TreeSet<>(ByteArrayComparator.BYTEARRAY_COMPARATOR);
128 this.isDeviceIdsModified = true;
129 }
130
Yuta HIGUCHI10eebea2014-02-03 10:41:41 -0800131 /**
132 * Get an instance from Key.
133 *
134 * @note You need to call `read()` to get the DB content.
135 * @param key
136 * @return RCPort instance
137 */
138 public static <P extends RCObject> P createFromKey(byte[] key) {
Yuta HIGUCHIc9d06ef2014-01-31 15:55:12 -0800139 long[] pair = getPortPairFromKey(key);
Yuta HIGUCHI10eebea2014-02-03 10:41:41 -0800140 @SuppressWarnings("unchecked")
141 P p = (P) new RCPort(pair[0], pair[1]);
142 return p;
143 }
144
145 public static Iterable<RCPort> getAllPorts() {
146 return new PortEnumerator();
147 }
148
149 public static class PortEnumerator implements Iterable<RCPort> {
150
151 @Override
152 public Iterator<RCPort> iterator() {
153 return new PortIterator();
154 }
155 }
156
157 public static class PortIterator extends ObjectIterator<RCPort> {
158
159 public PortIterator() {
160 super(RCTable.getTable(GLOBAL_PORT_TABLE_NAME));
161 }
162
163 @Override
164 public RCPort next() {
165 JRamCloud.Object o = enumerator.next();
166 RCPort e = RCPort.createFromKey(o.key);
167 e.setValueAndDeserialize(o.value, o.version);
168 return e;
169 }
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800170 }
171
172 public STATUS getStatus() {
173 return status;
174 }
175
176 public void setStatus(STATUS status) {
177 this.status = status;
178 getObjectMap().put(PROP_STATUS, status);
179 }
180
181 public Long getDpid() {
182 return dpid;
183 }
184
185 public Long getNumber() {
186 return number;
187 }
188
189 public byte[] getId() {
190 return getKey();
191 }
192
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800193 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800194 public void addLinkId(byte[] linkId) {
195 isLinkIdsModified |= linkIds.add(linkId);
196 }
197
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800198 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800199 public void removeLinkId(byte[] linkId) {
200 isLinkIdsModified |= linkIds.remove(linkId);
201 }
202
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800203 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800204 public void emptyLinkIds() {
205 linkIds.clear();
206 isLinkIdsModified = true;
207 }
208
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800209 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800210 public void addAllToLinkIds(Collection<byte[]> linkIds) {
211 isLinkIdsModified |= this.linkIds.addAll(linkIds);
212 }
213
214 /**
215 *
216 * @return Unmodifiable Set view of all the LinkIds;
217 */
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800218 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800219 public Set<byte[]> getAllLinkIds() {
220 return Collections.unmodifiableSet(linkIds);
221 }
222
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800223 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800224 public void addDeviceId(byte[] deviceId) {
225 isDeviceIdsModified |= deviceIds.add(deviceId);
226 }
227
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800228 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800229 public void removeDeviceId(byte[] deviceId) {
230 isDeviceIdsModified |= deviceIds.remove(deviceId);
231 }
232
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800233 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800234 public void emptyDeviceIds() {
235 deviceIds.clear();
236 isDeviceIdsModified = true;
237 }
238
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800239 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800240 public void addAllToDeviceIds(Collection<byte[]> deviceIds) {
241 isDeviceIdsModified |= this.deviceIds.addAll(deviceIds);
242 }
243
244 /**
245 *
246 * @return Unmodifiable Set view of all the LinkIds;
247 */
Yuta HIGUCHI58c10962014-02-03 19:14:13 -0800248 @Deprecated
Yuta HIGUCHI1ef85c42014-01-29 17:23:21 -0800249 public Set<byte[]> getAllDeviceIds() {
250 return Collections.unmodifiableSet(deviceIds);
251 }
252
253 @Override
254 public void serializeAndSetValue() {
255 Map<Object, Object> map = getObjectMap();
256
257 map.put(PROP_DPID, this.dpid);
258 map.put(PROP_NUMBER, this.number);
259 if (isLinkIdsModified) {
260 byte[] linkIdArray[] = new byte[linkIds.size()][];
261 map.put(PROP_LINK_IDS, linkIds.toArray(linkIdArray));
262 isLinkIdsModified = false;
263 }
264 if (isDeviceIdsModified) {
265 byte[] deviceIdArray[] = new byte[deviceIds.size()][];
266 map.put(PROP_DEVICE_IDS, deviceIds.toArray(deviceIdArray));
267 isDeviceIdsModified = false;
268 }
269 if (log.isWarnEnabled() && (linkIds.size() * deviceIds.size()) != 0) {
270 log.warn("Either #LinkIds:{} or #DeviceIds:{} is expected to be 0",
271 linkIds.size(), deviceIds.size());
272 }
273
274 serializeAndSetValue(portKryo.get(), map);
275 }
276
277 @Override
278 public Map<Object, Object> deserializeObjectFromValue() {
279 Map<Object, Object> map = deserializeObjectFromValue(portKryo.get());
280
281 this.status = (STATUS) map.get(PROP_STATUS);
282
283 if (this.linkIds == null) {
284 this.linkIds = new TreeSet<>(
285 ByteArrayComparator.BYTEARRAY_COMPARATOR);
286 }
287 byte[] linkIdArray[] = (byte[][]) map.get(PROP_LINK_IDS);
288 if (linkIdArray != null) {
289 this.linkIds.clear();
290 this.linkIds.addAll(Arrays.asList(linkIdArray));
291 isLinkIdsModified = false;
292 } else {
293 // trigger write on next serialize
294 isLinkIdsModified = true;
295 }
296
297 if (this.deviceIds == null) {
298 this.deviceIds = new TreeSet<>(
299 ByteArrayComparator.BYTEARRAY_COMPARATOR);
300 }
301 byte[] deviceIdArray[] = (byte[][]) map.get(PROP_DEVICE_IDS);
302 if (deviceIdArray != null) {
303 this.deviceIds.clear();
304 this.deviceIds.addAll(Arrays.asList(deviceIdArray));
305 isDeviceIdsModified = false;
306 } else {
307 // trigger write on next serialize
308 isDeviceIdsModified = true;
309 }
310
311 if (log.isWarnEnabled() && (linkIds.size() * deviceIds.size()) != 0) {
312 log.warn("Either #LinkIds:{} or #DeviceIds:{} is expected to be 0",
313 linkIds.size(), deviceIds.size());
314 }
315
316 return map;
317 }
318
319 @Override
320 public String toString() {
321 // TODO OUTPUT ALL?
322 return "[RCPort 0x" + Long.toHexString(dpid) + "@" + number
323 + " STATUS:" + status + "]";
324 }
325
326 public static void main(String[] args) {
327 // TODO Auto-generated method stub
328
329 }
330
331}