View Javadoc

1   package org.apache.helix;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.TreeMap;
26  
27  import org.apache.helix.ZNRecordDelta.MergeOperation;
28  import org.apache.log4j.Logger;
29  import org.codehaus.jackson.annotate.JsonCreator;
30  import org.codehaus.jackson.annotate.JsonIgnore;
31  import org.codehaus.jackson.annotate.JsonIgnoreProperties;
32  import org.codehaus.jackson.annotate.JsonProperty;
33  
34  
35  /**
36   * Generic Record Format to store data at a Node This can be used to store
37   * simpleFields mapFields listFields
38   */
39  @JsonIgnoreProperties(ignoreUnknown = true)
40  public class ZNRecord
41  {
42    static Logger _logger = Logger.getLogger(ZNRecord.class);
43    private final String id;
44  
45    @JsonIgnore(true)
46    public static final String LIST_FIELD_BOUND = "listField.bound";
47  
48    @JsonIgnore(true)
49    public static final int SIZE_LIMIT = 1000 * 1024;  // leave a margin out of 1M
50  
51    // We don't want the _deltaList to be serialized and deserialized
52    private List<ZNRecordDelta> _deltaList = new ArrayList<ZNRecordDelta>();
53  
54    private Map<String, String> simpleFields;
55    private Map<String, Map<String, String>> mapFields;
56    private Map<String, List<String>> listFields;
57  
58    // the version field of zookeeper Stat
59    private int _version;
60  
61    private long _creationTime;
62  
63    private long _modifiedTime;
64  
65    @JsonCreator
66    public ZNRecord(@JsonProperty("id") String id)
67    {
68      this.id = id;
69      simpleFields = new TreeMap<String, String>();
70      mapFields = new TreeMap<String, Map<String, String>>();
71      listFields = new TreeMap<String, List<String>>();
72    }
73  
74    public ZNRecord(ZNRecord record)
75    {
76      this(record, record.getId());
77    }
78  
79    public ZNRecord(ZNRecord record, String id)
80    {
81      this(id);
82      simpleFields.putAll(record.getSimpleFields());
83      mapFields.putAll(record.getMapFields());
84      listFields.putAll(record.getListFields());
85      _version = record.getVersion();
86      _creationTime = record.getCreationTime();
87      _modifiedTime = record.getModifiedTime();
88    }
89  
90    public ZNRecord(ZNRecord record, int version)
91    {
92      this(record);
93      _version = version;
94    }
95  
96    @JsonIgnore(true)
97    public void setDeltaList(List<ZNRecordDelta> deltaList)
98    {
99      _deltaList = deltaList;
100   }
101 
102   @JsonIgnore(true)
103   public List<ZNRecordDelta> getDeltaList()
104   {
105     return _deltaList;
106   }
107 
108   @JsonProperty
109   public Map<String, String> getSimpleFields()
110   {
111     return simpleFields;
112   }
113 
114   @JsonProperty
115   public void setSimpleFields(Map<String, String> simpleFields)
116   {
117     this.simpleFields = simpleFields;
118   }
119 
120   @JsonProperty
121   public Map<String, Map<String, String>> getMapFields()
122   {
123     return mapFields;
124   }
125 
126   @JsonProperty
127   public void setMapFields(Map<String, Map<String, String>> mapFields)
128   {
129     this.mapFields = mapFields;
130   }
131 
132   @JsonProperty
133   public Map<String, List<String>> getListFields()
134   {
135     return listFields;
136   }
137 
138   @JsonProperty
139   public void setListFields(Map<String, List<String>> listFields)
140   {
141     this.listFields = listFields;
142   }
143 
144   @JsonProperty
145   public void setSimpleField(String k, String v)
146   {
147     simpleFields.put(k, v);
148   }
149 
150   @JsonProperty
151   public String getId()
152   {
153     return id;
154   }
155 
156   public void setMapField(String k, Map<String, String> v)
157   {
158     mapFields.put(k, v);
159   }
160 
161   public void setListField(String k, List<String> v)
162   {
163     listFields.put(k, v);
164   }
165 
166   public String getSimpleField(String k)
167   {
168     return simpleFields.get(k);
169   }
170 
171   public Map<String, String> getMapField(String k)
172   {
173     return mapFields.get(k);
174   }
175 
176   public List<String> getListField(String k)
177   {
178     return listFields.get(k);
179   }
180 
181   @Override
182   public String toString()
183   {
184     StringBuffer sb = new StringBuffer();
185     sb.append(id + ", ");
186     if (simpleFields != null)
187     {
188       sb.append(simpleFields);
189     }
190     if (mapFields != null)
191     {
192       sb.append(mapFields);
193     }
194     if (listFields != null)
195     {
196       sb.append(listFields);
197     }
198     return sb.toString();
199   }
200 
201   /**
202    * merge functionality is used to merge multiple znrecord into a single one.
203    * This will make use of the id of each ZNRecord and append it to every key
204    * thus making key unique. This is needed to optimize on the watches.
205    *
206    * @param record
207    */
208   public void merge(ZNRecord record)
209   {
210     if (record == null)
211     {
212       return;
213     }
214 
215     if (record.getDeltaList().size() > 0)
216     {
217       _logger.info("Merging with delta list, recordId = " + id + " other:"
218           + record.getId());
219       merge(record.getDeltaList());
220       return;
221     }
222     simpleFields.putAll(record.simpleFields);
223     for (String key : record.mapFields.keySet())
224     {
225       Map<String, String> map = mapFields.get(key);
226       if (map != null)
227       {
228         map.putAll(record.mapFields.get(key));
229       } else
230       {
231         mapFields.put(key, record.mapFields.get(key));
232       }
233     }
234     for (String key : record.listFields.keySet())
235     {
236       List<String> list = listFields.get(key);
237       if (list != null)
238       {
239         list.addAll(record.listFields.get(key));
240       } else
241       {
242         listFields.put(key, record.listFields.get(key));
243       }
244     }
245   }
246 
247   void merge(ZNRecordDelta delta)
248   {
249     if (delta.getMergeOperation() == MergeOperation.ADD)
250     {
251       merge(delta.getRecord());
252     } else if (delta.getMergeOperation() == MergeOperation.SUBTRACT)
253     {
254       subtract(delta.getRecord());
255     }
256   }
257 
258   void merge(List<ZNRecordDelta> deltaList)
259   {
260     for (ZNRecordDelta delta : deltaList)
261     {
262       merge(delta);
263     }
264   }
265 
266   @Override
267   public boolean equals(Object obj)
268   {
269     if (!(obj instanceof ZNRecord))
270     {
271       return false;
272     }
273     ZNRecord that = (ZNRecord) obj;
274     if (this.getSimpleFields().size() != that.getSimpleFields().size())
275     {
276       return false;
277     }
278     if (this.getMapFields().size() != that.getMapFields().size())
279     {
280       return false;
281     }
282     if (this.getListFields().size() != that.getListFields().size())
283     {
284       return false;
285     }
286     if (!this.getSimpleFields().equals(that.getSimpleFields()))
287     {
288       return false;
289     }
290     if (!this.getMapFields().equals(that.getMapFields()))
291     {
292       return false;
293     }
294     if (!this.getListFields().equals(that.getListFields()))
295     {
296       return false;
297     }
298 
299     return true;
300   }
301 
302   /**
303    * Note: does not support subtract in each list in list fields or map in
304    * mapFields
305    */
306   public void subtract(ZNRecord value)
307   {
308     for (String key : value.getSimpleFields().keySet())
309     {
310       if (simpleFields.containsKey(key))
311       {
312         simpleFields.remove(key);
313       }
314     }
315 
316     for (String key : value.getListFields().keySet())
317     {
318       if (listFields.containsKey(key))
319       {
320         listFields.remove(key);
321       }
322     }
323 
324     for (String key : value.getMapFields().keySet())
325     {
326       if (mapFields.containsKey(key))
327       {
328         mapFields.remove(key);
329       }
330     }
331   }
332 
333   @JsonIgnore(true)
334   public int getVersion()
335   {
336     return _version;
337   }
338 
339   @JsonIgnore(true)
340   public void setVersion(int version)
341   {
342     _version = version;
343   }
344 
345   @JsonIgnore(true)
346   public long getCreationTime()
347   {
348     return _creationTime;
349   }
350 
351   @JsonIgnore(true)
352   public void setCreationTime(long creationTime)
353   {
354     _creationTime = creationTime;
355   }
356 
357   @JsonIgnore(true)
358   public long getModifiedTime()
359   {
360     return _modifiedTime;
361   }
362 
363   @JsonIgnore(true)
364   public void setModifiedTime(long modifiedTime)
365   {
366     _modifiedTime = modifiedTime;
367   }
368 }