blob: cdaf383c9c3df0f24e103feae966256326187886 [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;
8import java.util.Map;
9import java.util.Set;
10import java.util.TreeSet;
11
12import org.slf4j.Logger;
13import org.slf4j.LoggerFactory;
14
15import com.esotericsoftware.kryo.Kryo;
16
17import net.onrc.onos.datastore.RCObject;
18import net.onrc.onos.datastore.RCTable;
19import net.onrc.onos.datastore.utils.ByteArrayComparator;
20
21public class RCPort extends RCObject {
22 private static final Logger log = LoggerFactory.getLogger(RCPort.class);
23
24 private static final ThreadLocal<Kryo> portKryo = new ThreadLocal<Kryo>() {
25 @Override
26 protected Kryo initialValue() {
27 Kryo kryo = new Kryo();
28 kryo.setRegistrationRequired(true);
29 kryo.setReferences(false);
30 kryo.register(byte[].class);
31 kryo.register(byte[][].class);
32 kryo.register(HashMap.class);
33 // TODO check if we should explicitly specify EnumSerializer
34 kryo.register(STATUS.class);
35 return kryo;
36 }
37 };
38
39 public static final String GLOBAL_PORT_TABLE_NAME = "G:Port";
40
41 // FIXME these should be Enum or some number, not String
42 private static final String PROP_DPID = "dpid";
43 private static final String PROP_NUMBER = "number";
44 private static final String PROP_STATUS = "status";
45 private static final String PROP_LINK_IDS = "link-ids";
46 private static final String PROP_DEVICE_IDS = "device-ids";
47
48 // must not re-order enum members, ordinal will be sent over wire
49 public enum STATUS {
50 INACTIVE, ACTIVE;
51 }
52
53 private final Long dpid;
54 private final Long number;
55
56 private STATUS status;
57 // XXX These 2 set of Ids can be removed from DataStore, if In-Memory cache
58 // build the indexing info from Link.
59 private TreeSet<byte[]> linkIds;
60 transient boolean isLinkIdsModified;
61 private TreeSet<byte[]> deviceIds;
62 transient boolean isDeviceIdsModified;
63
64 public static final int PORTID_BYTES = RCSwitch.SWITCHID_BYTES + 2 + 8;
65
66 public static byte[] getPortID(Long dpid, Long number) {
67 if (dpid == null) {
68 throw new IllegalArgumentException("dpid cannot be null");
69 }
70 if (number == null) {
71 throw new IllegalArgumentException("number cannot be null");
72 }
73 return ByteBuffer.allocate(PORTID_BYTES).putChar('S').putLong(dpid)
74 .putChar('P').putLong(number).array();
75 }
76
77 public static long getDpidFromKey(byte[] key) {
78 ByteBuffer keyBuf = ByteBuffer.wrap(key);
79 if (keyBuf.getChar() != 'S') {
80 throw new IllegalArgumentException("Invalid Port key");
81 }
82 return keyBuf.getLong();
83 }
84
85 public static long getNumberFromKey(byte[] key) {
86 ByteBuffer keyBuf = ByteBuffer.wrap(key);
87 keyBuf.position(RCSwitch.SWITCHID_BYTES);
88 if (keyBuf.getChar() != 'P') {
89 throw new IllegalArgumentException("Invalid Port key");
90 }
91 return keyBuf.getLong();
92 }
93
94 // FIXME specify DPID,number here, or Should caller specify the key it self?
95 // In other words, should layer above have the control of the ID?
96 public RCPort(Long dpid, Long number) {
97 super(RCTable.getTable(GLOBAL_PORT_TABLE_NAME), getPortID(dpid, number));
98
99 // TODO Auto-generated constructor stub
100
101 this.dpid = dpid;
102 this.number = number;
103 this.status = STATUS.INACTIVE;
104 this.linkIds = new TreeSet<>(ByteArrayComparator.BYTEARRAY_COMPARATOR);
105 this.isLinkIdsModified = true;
106 this.deviceIds = new TreeSet<>(ByteArrayComparator.BYTEARRAY_COMPARATOR);
107 this.isDeviceIdsModified = true;
108 }
109
110 public static RCPort createFromKey(byte[] key) {
111 return new RCPort(getDpidFromKey(key), getNumberFromKey(key));
112 }
113
114 public STATUS getStatus() {
115 return status;
116 }
117
118 public void setStatus(STATUS status) {
119 this.status = status;
120 getObjectMap().put(PROP_STATUS, status);
121 }
122
123 public Long getDpid() {
124 return dpid;
125 }
126
127 public Long getNumber() {
128 return number;
129 }
130
131 public byte[] getId() {
132 return getKey();
133 }
134
135 public void addLinkId(byte[] linkId) {
136 isLinkIdsModified |= linkIds.add(linkId);
137 }
138
139 public void removeLinkId(byte[] linkId) {
140 isLinkIdsModified |= linkIds.remove(linkId);
141 }
142
143 public void emptyLinkIds() {
144 linkIds.clear();
145 isLinkIdsModified = true;
146 }
147
148 public void addAllToLinkIds(Collection<byte[]> linkIds) {
149 isLinkIdsModified |= this.linkIds.addAll(linkIds);
150 }
151
152 /**
153 *
154 * @return Unmodifiable Set view of all the LinkIds;
155 */
156 public Set<byte[]> getAllLinkIds() {
157 return Collections.unmodifiableSet(linkIds);
158 }
159
160 public void addDeviceId(byte[] deviceId) {
161 isDeviceIdsModified |= deviceIds.add(deviceId);
162 }
163
164 public void removeDeviceId(byte[] deviceId) {
165 isDeviceIdsModified |= deviceIds.remove(deviceId);
166 }
167
168 public void emptyDeviceIds() {
169 deviceIds.clear();
170 isDeviceIdsModified = true;
171 }
172
173 public void addAllToDeviceIds(Collection<byte[]> deviceIds) {
174 isDeviceIdsModified |= this.deviceIds.addAll(deviceIds);
175 }
176
177 /**
178 *
179 * @return Unmodifiable Set view of all the LinkIds;
180 */
181 public Set<byte[]> getAllDeviceIds() {
182 return Collections.unmodifiableSet(deviceIds);
183 }
184
185 @Override
186 public void serializeAndSetValue() {
187 Map<Object, Object> map = getObjectMap();
188
189 map.put(PROP_DPID, this.dpid);
190 map.put(PROP_NUMBER, this.number);
191 if (isLinkIdsModified) {
192 byte[] linkIdArray[] = new byte[linkIds.size()][];
193 map.put(PROP_LINK_IDS, linkIds.toArray(linkIdArray));
194 isLinkIdsModified = false;
195 }
196 if (isDeviceIdsModified) {
197 byte[] deviceIdArray[] = new byte[deviceIds.size()][];
198 map.put(PROP_DEVICE_IDS, deviceIds.toArray(deviceIdArray));
199 isDeviceIdsModified = false;
200 }
201 if (log.isWarnEnabled() && (linkIds.size() * deviceIds.size()) != 0) {
202 log.warn("Either #LinkIds:{} or #DeviceIds:{} is expected to be 0",
203 linkIds.size(), deviceIds.size());
204 }
205
206 serializeAndSetValue(portKryo.get(), map);
207 }
208
209 @Override
210 public Map<Object, Object> deserializeObjectFromValue() {
211 Map<Object, Object> map = deserializeObjectFromValue(portKryo.get());
212
213 this.status = (STATUS) map.get(PROP_STATUS);
214
215 if (this.linkIds == null) {
216 this.linkIds = new TreeSet<>(
217 ByteArrayComparator.BYTEARRAY_COMPARATOR);
218 }
219 byte[] linkIdArray[] = (byte[][]) map.get(PROP_LINK_IDS);
220 if (linkIdArray != null) {
221 this.linkIds.clear();
222 this.linkIds.addAll(Arrays.asList(linkIdArray));
223 isLinkIdsModified = false;
224 } else {
225 // trigger write on next serialize
226 isLinkIdsModified = true;
227 }
228
229 if (this.deviceIds == null) {
230 this.deviceIds = new TreeSet<>(
231 ByteArrayComparator.BYTEARRAY_COMPARATOR);
232 }
233 byte[] deviceIdArray[] = (byte[][]) map.get(PROP_DEVICE_IDS);
234 if (deviceIdArray != null) {
235 this.deviceIds.clear();
236 this.deviceIds.addAll(Arrays.asList(deviceIdArray));
237 isDeviceIdsModified = false;
238 } else {
239 // trigger write on next serialize
240 isDeviceIdsModified = true;
241 }
242
243 if (log.isWarnEnabled() && (linkIds.size() * deviceIds.size()) != 0) {
244 log.warn("Either #LinkIds:{} or #DeviceIds:{} is expected to be 0",
245 linkIds.size(), deviceIds.size());
246 }
247
248 return map;
249 }
250
251 @Override
252 public String toString() {
253 // TODO OUTPUT ALL?
254 return "[RCPort 0x" + Long.toHexString(dpid) + "@" + number
255 + " STATUS:" + status + "]";
256 }
257
258 public static void main(String[] args) {
259 // TODO Auto-generated method stub
260
261 }
262
263}