View Javadoc

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