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.io.IOException;
23  import java.io.StringReader;
24  import java.io.StringWriter;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.List;
29  import java.util.Map;
30  
31  import org.apache.helix.ZNRecord;
32  import org.apache.helix.tools.IdealCalculatorByConsistentHashing;
33  import org.apache.helix.tools.IdealStateCalculatorByRush;
34  import org.apache.helix.tools.IdealStateCalculatorByShuffling;
35  import org.codehaus.jackson.JsonGenerationException;
36  import org.codehaus.jackson.map.JsonMappingException;
37  import org.codehaus.jackson.map.ObjectMapper;
38  import org.testng.Assert;
39  import org.testng.AssertJUnit;
40  import org.testng.annotations.Test;
41  
42  
43  public class TestShuffledIdealState
44  {
45    @Test ()
46    public void testInvocation() throws Exception
47    {
48      int partitions = 6, replicas = 2;
49      String dbName = "espressoDB1";
50      List<String> instanceNames = new ArrayList<String>();
51      instanceNames.add("localhost_1231");
52      instanceNames.add("localhost_1232");
53      instanceNames.add("localhost_1233");
54      instanceNames.add("localhost_1234");
55  
56      ZNRecord result = IdealStateCalculatorByShuffling.calculateIdealState(
57          instanceNames, partitions, replicas, dbName);
58      IdealCalculatorByConsistentHashing.printIdealStateStats(result, "MASTER");
59      IdealCalculatorByConsistentHashing.printIdealStateStats(result, "SLAVE");
60      
61      ZNRecord result2 = IdealStateCalculatorByRush.calculateIdealState(instanceNames, 1, partitions, replicas, dbName);
62  
63      ZNRecord result3 = IdealCalculatorByConsistentHashing.calculateIdealState(instanceNames, partitions, replicas, dbName, new IdealCalculatorByConsistentHashing.FnvHash());
64      IdealCalculatorByConsistentHashing.printIdealStateStats(result3, "MASTER");
65      IdealCalculatorByConsistentHashing.printIdealStateStats(result3, "SLAVE");
66      IdealCalculatorByConsistentHashing.printIdealStateStats(result3, "");
67      IdealCalculatorByConsistentHashing.printNodeOfflineOverhead(result3);
68  
69      // System.out.println(result);
70      ObjectMapper mapper = new ObjectMapper();
71  
72      // ByteArrayOutputStream baos = new ByteArrayOutputStream();
73      StringWriter sw = new StringWriter();
74      try
75      {
76        mapper.writeValue(sw, result);
77        // System.out.println(sw.toString());
78  
79        ZNRecord zn = mapper.readValue(new StringReader(sw.toString()),
80            ZNRecord.class);
81        System.out.println(result.toString());
82        System.out.println(zn.toString());
83        AssertJUnit.assertTrue(zn.toString().equalsIgnoreCase(result.toString()));
84        System.out.println();
85  
86        sw= new StringWriter();
87        mapper.writeValue(sw, result2);
88  
89        ZNRecord zn2 = mapper.readValue(new StringReader(sw.toString()),
90            ZNRecord.class);
91        System.out.println(result2.toString());
92        System.out.println(zn2.toString());
93        AssertJUnit.assertTrue(zn2.toString().equalsIgnoreCase(result2.toString()));
94  
95        sw= new StringWriter();
96        mapper.writeValue(sw, result3);
97        System.out.println();
98  
99        ZNRecord zn3 = mapper.readValue(new StringReader(sw.toString()),
100           ZNRecord.class);
101       System.out.println(result3.toString());
102       System.out.println(zn3.toString());
103       AssertJUnit.assertTrue(zn3.toString().equalsIgnoreCase(result3.toString()));
104       System.out.println();
105 
106     } catch (JsonGenerationException e)
107     {
108       // TODO Auto-generated catch block
109       e.printStackTrace();
110     } catch (JsonMappingException e)
111     {
112       // TODO Auto-generated catch block
113       e.printStackTrace();
114     } catch (IOException e)
115     {
116       // TODO Auto-generated catch block
117       e.printStackTrace();
118     }
119   }
120   
121   @Test
122   public void testShuffledIdealState()
123   {
124     // partitions is larger than nodes
125     int partitions = 6, replicas = 2, instances = 4;
126     String dbName = "espressoDB1";
127     List<String> instanceNames = new ArrayList<String>();
128     instanceNames.add("localhost_1231");
129     instanceNames.add("localhost_1232");
130     instanceNames.add("localhost_1233");
131     instanceNames.add("localhost_1234");
132 
133     ZNRecord result = IdealStateCalculatorByShuffling.calculateIdealState(
134         instanceNames, partitions, replicas, dbName);
135     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "MASTER");
136     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "SLAVE");
137     Assert.assertTrue(verify(result));
138     
139     // partition is less than nodes
140     instanceNames.clear();
141     partitions = 4; 
142     replicas = 3;
143     instances = 7;
144     
145     for(int i = 0; i<instances; i++)
146     {
147       instanceNames.add("localhost_" + (1231 + i));
148     }
149     result = IdealStateCalculatorByShuffling.calculateIdealState(
150         instanceNames, partitions, replicas, dbName);
151     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "MASTER");
152     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "SLAVE");
153     Assert.assertTrue(verify(result));
154     
155     // partitions is multiple of nodes
156     instanceNames.clear();
157     partitions = 14; 
158     replicas = 3;
159     instances = 7;
160     
161     for(int i = 0; i<instances; i++)
162     {
163       instanceNames.add("localhost_" + (1231 + i));
164     }
165     result = IdealStateCalculatorByShuffling.calculateIdealState(
166         instanceNames, partitions, replicas, dbName);
167     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "MASTER");
168     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "SLAVE");
169     Assert.assertTrue(verify(result));
170     
171     // nodes are multiple of partitions
172     instanceNames.clear();
173     partitions = 4; 
174     replicas = 3;
175     instances = 8;
176     
177     for(int i = 0; i<instances; i++)
178     {
179       instanceNames.add("localhost_" + (1231 + i));
180     }
181     result = IdealStateCalculatorByShuffling.calculateIdealState(
182         instanceNames, partitions, replicas, dbName);
183     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "MASTER");
184     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "SLAVE");
185     Assert.assertTrue(verify(result));
186     
187     // nodes are multiple of partitions
188     instanceNames.clear();
189     partitions = 4; 
190     replicas = 3;
191     instances = 12;
192     
193     for(int i = 0; i<instances; i++)
194     {
195       instanceNames.add("localhost_" + (1231 + i));
196     }
197     result = IdealStateCalculatorByShuffling.calculateIdealState(
198         instanceNames, partitions, replicas, dbName);
199     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "MASTER");
200     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "SLAVE");
201     Assert.assertTrue(verify(result));
202     
203     // Just fits
204     instanceNames.clear();
205     partitions = 4; 
206     replicas = 2;
207     instances = 12;
208     
209     for(int i = 0; i<instances; i++)
210     {
211       instanceNames.add("localhost_" + (1231 + i));
212     }
213     result = IdealStateCalculatorByShuffling.calculateIdealState(
214         instanceNames, partitions, replicas, dbName);
215     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "MASTER");
216     IdealCalculatorByConsistentHashing.printIdealStateStats(result, "SLAVE");
217     Assert.assertTrue(verify(result));
218   }
219   
220   boolean verify(ZNRecord result)
221   {
222     Map<String, Integer> masterPartitionCounts = new HashMap<String, Integer>();
223     Map<String, Integer> slavePartitionCounts = new HashMap<String, Integer>();
224     
225     for(String key : result.getMapFields().keySet())
226     {
227       Map<String, String> mapField = result.getMapField(key);
228       int masterCount = 0;
229       for(String host: mapField.keySet())
230       {
231         if(mapField.get(host).equals("MASTER"))
232         {
233           Assert.assertTrue(masterCount == 0);
234           masterCount ++;
235           if(!masterPartitionCounts.containsKey(host))
236           {
237             masterPartitionCounts.put(host, 0);
238           }
239           else
240           {
241             masterPartitionCounts.put(host, masterPartitionCounts.get(host) + 1);
242           }
243         }
244         else
245         {
246           if(!slavePartitionCounts.containsKey(host))
247           {
248             slavePartitionCounts.put(host, 0);
249           }
250           else
251           {
252             slavePartitionCounts.put(host, slavePartitionCounts.get(host) + 1);
253           }
254         }
255       }
256     }
257     
258     List<Integer> masterCounts = new ArrayList<Integer>();
259     List<Integer> slaveCounts = new ArrayList<Integer>();
260     masterCounts.addAll(masterPartitionCounts.values());
261     slaveCounts.addAll(slavePartitionCounts.values());
262     Collections.sort(masterCounts);
263     Collections.sort(slaveCounts);
264     
265     Assert.assertTrue(masterCounts.get(masterCounts.size() - 1 ) - masterCounts.get(0) <= 1);
266 
267     Assert.assertTrue(slaveCounts.get(slaveCounts.size() - 1 ) - slaveCounts.get(0) <= 2);
268     return true;
269   }
270 }