1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.accumulo.server.master.balancer;
18
19 import static org.junit.Assert.assertEquals;
20
21 import java.net.InetSocketAddress;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Map.Entry;
28 import java.util.Set;
29 import java.util.SortedMap;
30 import java.util.TreeMap;
31
32 import org.apache.accumulo.core.data.KeyExtent;
33 import org.apache.accumulo.core.master.thrift.TableInfo;
34 import org.apache.accumulo.core.master.thrift.TabletServerStatus;
35 import org.apache.accumulo.core.security.thrift.ThriftSecurityException;
36 import org.apache.accumulo.core.tabletserver.thrift.TabletStats;
37 import org.apache.accumulo.core.util.AddressUtil;
38 import org.apache.accumulo.server.master.state.TServerInstance;
39 import org.apache.accumulo.server.master.state.TabletMigration;
40 import org.apache.hadoop.io.Text;
41 import org.apache.thrift.TException;
42 import org.junit.Test;
43
44 public class ChaoticLoadBalancerTest {
45
46 class FakeTServer {
47 List<KeyExtent> extents = new ArrayList<KeyExtent>();
48
49 TabletServerStatus getStatus(TServerInstance server) {
50 TabletServerStatus result = new TabletServerStatus();
51 result.tableMap = new HashMap<String,TableInfo>();
52 for (KeyExtent extent : extents) {
53 String table = extent.getTableId().toString();
54 TableInfo info = result.tableMap.get(table);
55 if (info == null)
56 result.tableMap.put(table, info = new TableInfo());
57 info.onlineTablets++;
58 info.recs = info.onlineTablets;
59 info.ingestRate = 123.;
60 info.queryRate = 456.;
61 }
62 return result;
63 }
64 }
65
66 Map<TServerInstance,FakeTServer> servers = new HashMap<TServerInstance,FakeTServer>();
67
68 class TestChaoticLoadBalancer extends ChaoticLoadBalancer {
69
70 @Override
71 public List<TabletStats> getOnlineTabletsForTable(TServerInstance tserver, String table) throws ThriftSecurityException, TException {
72 List<TabletStats> result = new ArrayList<TabletStats>();
73 for (KeyExtent extent : servers.get(tserver).extents) {
74 if (extent.getTableId().toString().equals(table)) {
75 result.add(new TabletStats(extent.toThrift(), null, null, null, 0l, 0., 0., 0));
76 }
77 }
78 return result;
79 }
80 }
81
82 @Test
83 public void testAssignMigrations() {
84 servers.clear();
85 servers.put(new TServerInstance(AddressUtil.parseAddress("127.0.0.1", 1234), "a"), new FakeTServer());
86 servers.put(new TServerInstance(AddressUtil.parseAddress("127.0.0.1", 1235), "b"), new FakeTServer());
87 servers.put(new TServerInstance(AddressUtil.parseAddress("127.0.0.1", 1236), "c"), new FakeTServer());
88 Map<KeyExtent,TServerInstance> metadataTable = new TreeMap<KeyExtent,TServerInstance>();
89 String table = "t1";
90 metadataTable.put(makeExtent(table, null, null), null);
91 table = "t2";
92 metadataTable.put(makeExtent(table, "a", null), null);
93 metadataTable.put(makeExtent(table, null, "a"), null);
94 table = "t3";
95 metadataTable.put(makeExtent(table, "a", null), null);
96 metadataTable.put(makeExtent(table, "b", "a"), null);
97 metadataTable.put(makeExtent(table, "c", "b"), null);
98 metadataTable.put(makeExtent(table, "d", "c"), null);
99 metadataTable.put(makeExtent(table, "e", "d"), null);
100 metadataTable.put(makeExtent(table, null, "e"), null);
101
102 TestChaoticLoadBalancer balancer = new TestChaoticLoadBalancer();
103
104 SortedMap<TServerInstance,TabletServerStatus> current = new TreeMap<TServerInstance,TabletServerStatus>();
105 for (Entry<TServerInstance,FakeTServer> entry : servers.entrySet()) {
106 current.put(entry.getKey(), entry.getValue().getStatus(entry.getKey()));
107 }
108
109 Map<KeyExtent, TServerInstance> assignments = new HashMap<KeyExtent, TServerInstance>();
110 balancer.getAssignments(getAssignments(servers), metadataTable, assignments);
111
112 assertEquals(assignments.size(), metadataTable.size());
113 }
114
115 SortedMap<TServerInstance,TabletServerStatus> getAssignments(Map<TServerInstance,FakeTServer> servers) {
116 SortedMap<TServerInstance,TabletServerStatus> result = new TreeMap<TServerInstance,TabletServerStatus>();
117 for (Entry<TServerInstance,FakeTServer> entry : servers.entrySet()) {
118 result.put(entry.getKey(), entry.getValue().getStatus(entry.getKey()));
119 }
120 return result;
121 }
122
123 @Test
124 public void testUnevenAssignment() {
125 servers.clear();
126 for (char c : "abcdefghijklmnopqrstuvwxyz".toCharArray()) {
127 String cString = Character.toString(c);
128 InetSocketAddress fakeAddress = AddressUtil.parseAddress("127.0.0.1", (int) c);
129 String fakeInstance = cString;
130 TServerInstance tsi = new TServerInstance(fakeAddress, fakeInstance);
131 FakeTServer fakeTServer = new FakeTServer();
132 servers.put(tsi, fakeTServer);
133 fakeTServer.extents.add(makeExtent(cString, null, null));
134 }
135
136 Entry<TServerInstance,FakeTServer> first = servers.entrySet().iterator().next();
137 first.getValue().extents.add(makeExtent("newTable", "a", null));
138 first.getValue().extents.add(makeExtent("newTable", "b", "a"));
139 first.getValue().extents.add(makeExtent("newTable", "c", "b"));
140 first.getValue().extents.add(makeExtent("newTable", "d", "c"));
141 first.getValue().extents.add(makeExtent("newTable", "e", "d"));
142 first.getValue().extents.add(makeExtent("newTable", "f", "e"));
143 first.getValue().extents.add(makeExtent("newTable", "g", "f"));
144 first.getValue().extents.add(makeExtent("newTable", "h", "g"));
145 first.getValue().extents.add(makeExtent("newTable", "i", null));
146 TestChaoticLoadBalancer balancer = new TestChaoticLoadBalancer();
147 Set<KeyExtent> migrations = Collections.emptySet();
148
149
150 List<TabletMigration> migrationsOut = new ArrayList<TabletMigration>();
151 while (migrationsOut.size() != 0) {
152 balancer.balance(getAssignments(servers), migrations, migrationsOut);
153 }
154 }
155
156 private static KeyExtent makeExtent(String table, String end, String prev) {
157 return new KeyExtent(new Text(table), toText(end), toText(prev));
158 }
159
160 private static Text toText(String value) {
161 if (value != null)
162 return new Text(value);
163 return null;
164 }
165
166 }