1 /*
2 * Copyright (c) 1998-2002 The Jgroup Team.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 */
18
19 package jgroup.relacs.registry;
20
21 import java.rmi.NotBoundException;
22 import java.rmi.RemoteException;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26
27 import jgroup.core.MemberId;
28 import jgroup.core.VMID;
29 import jgroup.core.View;
30 import jgroup.relacs.gm.LeaseInfo;
31 import jgroup.util.IntList;
32
33 import org.apache.log4j.Logger;
34
35 /**
36 * This class implements the main data structure used to maintain
37 * the bindings stored in the registry.
38 *
39 * @author Alberto Montresor
40 * @author Hein Meling
41 * @since Jgroup 0.5
42 */
43 final class RegistryTable
44 {
45
46 ////////////////////////////////////////////////////////////////////////////////////////////
47 // Logger
48 ////////////////////////////////////////////////////////////////////////////////////////////
49
50 /** Obtain logger for this class */
51 private static final Logger log = Logger.getLogger(RegistryTable.class);
52
53
54 ////////////////////////////////////////////////////////////////////////////////////////////
55 // Fields
56 ////////////////////////////////////////////////////////////////////////////////////////////
57
58 /**
59 * This map associates VMIDs (virtual machine identifiers) to
60 * the <CODE>ServerData</CODE> data structure associated to them
61 */
62 private final Map<VMID, ServerData> servertable = new HashMap<VMID, ServerData>(51);
63
64 /**
65 * This map associates service names (constituted by string identifiers)
66 * to the <CODE>ServiceData</CODE> data structure associated to them
67 */
68 private final Map<String, ServiceData> servicetable = new HashMap<String, ServiceData>(51);
69
70 /** Last view installed */
71 private View view;
72
73
74 ////////////////////////////////////////////////////////////////////////////////////////////
75 // Constructor
76 ////////////////////////////////////////////////////////////////////////////////////////////
77
78 RegistryTable() { }
79
80
81 ////////////////////////////////////////////////////////////////////////////////////////////
82 // Methods
83 ////////////////////////////////////////////////////////////////////////////////////////////
84
85 /**
86 * Add a binding for the specified <CODE>VMID</CODE>.
87 *
88 * @param vmid
89 * the virtual machine identifier to which associate this binding
90 * @param binding
91 * the binding to be associated to the specified <CODE>VMID</CODE>
92 *
93 */
94 synchronized void add(VMID vmid, BindingList bl)
95 throws RemoteException
96 {
97 // Inserts in service table
98 ServiceData service = servicetable.get(bl.servicename);
99 if (service == null) {
100 service = new ServiceData(bl.serverClass, bl.servicename, bl.entry);
101 servicetable.put(bl.servicename, service);
102 }
103 service.add(bl);
104
105 // Insert in server table
106 ServerData server = get(vmid);
107 server.add(bl.key, bl);
108 }
109
110
111 /**
112 * Remove a binding associated to the specified <CODE>VMID</CODE>
113 * and identifier by the specified numeric progressive identifier.
114 *
115 * @param vmid
116 * the vmid associated to the binding to be removed
117 * @param key
118 * the identifier of the binding
119 */
120 synchronized void remove(VMID vmid, int key)
121 {
122 ServerData server = get(vmid);
123 BindingList binding = server.remove(key);
124 if (binding != null) {
125 ServiceData service = servicetable.get(binding.servicename);
126 if (service != null) {
127 service.remove(binding);
128 if (service.isEmpty())
129 servicetable.remove(binding.servicename);
130 }
131 }
132 }
133
134 /**
135 * Get a binding associated to the specified <CODE>VMID</CODE>
136 * and identifier by the specified numeric progressive identifier.
137 *
138 * @param vmid
139 * the vmid associated to the binding to be fetched
140 * @param key
141 * the identifier of the binding
142 * @return
143 * the BindingList node of the specified server
144 */
145 public BindingList lookup(VMID vmid, int key)
146 {
147 ServerData server = get(vmid);
148 BindingList binding = server.lookup(key);
149 return binding;
150 }
151
152 /**
153 * Returns the IIDs and timestamps for all servers
154 * registered under the given servicename, as well
155 * as returning the leasetime for the given service.
156 *
157 * @param servicename
158 * the name of the service
159 * @return
160 * datastructure containing IIDs, timestamps and
161 * leasetime for servers under the given servicename
162 */
163 public LeaseInfo getLookupInf(String servicename)
164 throws NotBoundException
165 {
166 ServiceData service = (ServiceData) servicetable.get(servicename);
167 if (service == null)
168 throw new NotBoundException();
169 List list = service.getLinkedList();
170 LeaseInfo leaseInfo = new LeaseInfo(list.size());
171
172 BindingList first = (BindingList) list.get(0);
173 leaseInfo.setLeasetime(first.leasetime);
174 leaseInfo.setTimeStamp(first.timestamp, 0);
175 leaseInfo.setIID(first.iid, 0);
176
177 for (int i = 1; i < list.size(); i++) {
178 BindingList bl = (BindingList) list.get(i);
179 leaseInfo.setTimeStamp(bl.timestamp, i);
180 leaseInfo.setIID(bl.iid, i);
181 }
182
183 return leaseInfo;
184 }
185
186
187 /**
188 *
189 */
190 synchronized void viewChange(View view)
191 {
192 this.view = view;
193 for (ServerData server : servertable.values()) {
194 server.viewChange(view);
195 }
196 }
197
198
199 /**
200 * Returns the list of all of the service names currently maintained
201 * by the registry.
202 */
203 synchronized String[] list()
204 {
205 String[] list = new String[servicetable.size()];
206 int j = 0;
207 for (String serviceName : servicetable.keySet())
208 list[j++] = serviceName;
209 return list;
210 }
211
212 /**
213 * Returns the service data for the given service name.
214 */
215 synchronized ServiceData getService(String serviceName)
216 throws NotBoundException
217 {
218 ServiceData service = servicetable.get(serviceName);
219 if (service==null)
220 throw new NotBoundException(serviceName);
221 return service;
222 }
223
224
225 /**
226 * Returns a <CODE>MergingData</CODE> object containing the
227 * information needed by the registry replicas contained in
228 * <CODE>dests</CODE> to merge their databases.
229 *
230 * @param dests the set of replicas to which the merging information
231 * is addressed.
232 * @param me identifier of the local replica, needed to identify
233 * the origin of the data.
234 */
235 synchronized MergingData getState(MemberId[] dests, MemberId me)
236 {
237 MergingData merging = new MergingData();
238 int size = servertable.size();
239
240 merging.vmids = new VMID[size];
241 merging.removed = new IntList[size];
242 merging.bindings = new BindingList[size][];
243
244 int j = 0;
245 for (ServerData server : servertable.values()) {
246 merging.vmids[j] = server.vmid;
247 merging.removed[j] = server.removed;
248 merging.bindings[j++] = server.getState(dests, me);
249 }
250 return merging;
251 }
252
253
254 /**
255 * Takes a <CODE>MergingData</CODE> object and inserts the data
256 * contained in it.
257 *
258 * @param merging the merging data sent by another replica
259 * @param dests the destination set of this merging data
260 */
261 synchronized void putState(MergingData merging, MemberId[] dests)
262 throws RemoteException, ClassNotFoundException
263 {
264 for (int i=0; i < merging.vmids.length; i++) {
265 if (log.isDebugEnabled())
266 log.debug("putState: merging.vmids["+i+"]: " + merging.vmids[i]);
267 ServerData server = get(merging.vmids[i]);
268 server.putState(servicetable, merging.removed[i], merging.bindings[i]);
269 }
270 }
271
272
273 ////////////////////////////////////////////////////////////////////////////////////////////
274 // Private methods
275 ////////////////////////////////////////////////////////////////////////////////////////////
276
277 /**
278 * Returns the <CODE>ServerData</CODE> object associated with the
279 * specified <CODE>VMID</CODE>, or creates a new one if not present.
280 */
281 private ServerData get(VMID vmid)
282 {
283 ServerData server = servertable.get(vmid);
284 if (server == null) {
285 server = new ServerData(vmid);
286 server.viewChange(view);
287 servertable.put(vmid, server);
288 }
289 return server;
290 }
291
292 } // END RegistryTable