Main2.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. package me.yoqi.servermanager;
  2. import java.io.BufferedReader;
  3. import java.io.BufferedWriter;
  4. import java.io.ByteArrayInputStream;
  5. import java.io.File;
  6. import java.io.FileInputStream;
  7. import java.io.FileReader;
  8. import java.io.FileWriter;
  9. import java.io.IOException;
  10. import java.io.InputStream;
  11. import java.io.InputStreamReader;
  12. import java.util.ArrayList;
  13. import java.util.HashMap;
  14. import java.util.List;
  15. import java.util.Map;
  16. import com.google.common.base.Charsets;
  17. /**默认不迁移,初始代码。跑a数据分数6148
  18. * Created by mou.sunm on 2018/07/02.
  19. */
  20. public class Main2 {
  21. // 参数
  22. public static final double alpha = 10.;
  23. public static final double beta = 0.5;
  24. public static final int T = 98;
  25. public static final int EXEC_LIMIT = 100000;
  26. // 静态数据
  27. private int num_app; // app数 9338
  28. private int num_inst; // inst数 68219
  29. private int num_mac; // machine数 6000
  30. private int num_k; // 资源种类 200
  31. private List<Integer> cpuIter; // [0, 1, 2, ... 97]
  32. private Map<String, Integer> appIndex; // app_1,app_2字符串用0,1等数字替换,{app_1=0,
  33. // app_2=1,...,app_4=3}
  34. private Map<String, Integer> machineIndex;// {machine_1=0, machine_2=1,
  35. private List<Integer> machinePriorIndex=new ArrayList<Integer>();
  36. private String[] apps; // [app_1, app_2, app_3, app_4,
  37. private String[] machines;// [machine_1, machine_2, machine_3, machine_4,
  38. private Map<String, Integer> inst2AppIndex;// {inst_157=49}
  39. private double[][] appResources;// app 9338*200
  40. private double[][] machineResources;// 主机 6000*200
  41. private Map<Integer, Integer>[] appInterference;// 9338 限制条件[{}, {},
  42. // {3517=2}, {}, {5600=1,
  43. // 6747=2, 7707=2, 4830=2},
  44. // 动态数据
  45. private Map<String, Integer> inst2Machine;// 部署 {inst_33717=5456,
  46. // 这个数据类型和Map<String, Integer>有点区别,加上list会保存顺序
  47. private List<String> deployResult = new ArrayList<String>(); // [inst_33717,5456
  48. private List<String> instUnDelpoy = new ArrayList<String>();// 未部署的实例
  49. private Map<String, Integer> inst2MachineDefaultConflict = new HashMap<String, Integer>();;// 记录初始部署冲突的实例和主机
  50. private double[][] machineResourcesUsed;// 6000*200
  51. private Map<Integer, Integer>[] machineHasApp;// 6000 [{}, {},{6004=1,
  52. // 9126=1, 1598=1}, {}, {},
  53. // {},
  54. /**
  55. * 先对disk排序,然后first fit
  56. *
  57. * @throws IOException
  58. * 写文件异常
  59. */
  60. private void run() throws IOException {
  61. // 主机优先顺序,使用过的主机在前,目的紧凑;然后大主机在前。做一个主机优先部署序列
  62. // 对默认实例有冲突的进行迁移
  63. String tmp_Res;
  64. String inst_tmp = null;
  65. int machineIt_tmp = 0;
  66. for (Map.Entry<String, Integer> entry : inst2MachineDefaultConflict.entrySet()) {
  67. // 将实例先迁移出来,释放资源
  68. pickInstance(entry.getKey());
  69. for (Map.Entry<String, Integer> entry2 : machineIndex.entrySet()) {
  70. inst_tmp = entry.getKey();
  71. machineIt_tmp = entry2.getValue();
  72. tmp_Res = toMachine(inst_tmp, machineIt_tmp);
  73. if (tmp_Res == "success") {
  74. deployResult.add(inst_tmp + "," + "machine_" + (machineIt_tmp + 1));
  75. break;
  76. }
  77. }
  78. }
  79. System.out.println("默认冲突数:" + inst2MachineDefaultConflict.size());
  80. System.out.println("剩余未部署:" + instUnDelpoy.size());
  81. //对剩余未部署的实例进行部署
  82. for (int i = 0; i < instUnDelpoy.size(); i++) {
  83. for (Map.Entry<String, Integer> entry2 : machineIndex.entrySet()) {
  84. inst_tmp = instUnDelpoy.get(i);
  85. machineIt_tmp = entry2.getValue();
  86. tmp_Res = toMachine(inst_tmp, machineIt_tmp);
  87. if (tmp_Res == "success") {
  88. deployResult.add(inst_tmp + "," + "machine_" + (machineIt_tmp + 1));
  89. break;
  90. }
  91. }
  92. }
  93. saveResult(deployResult);
  94. }
  95. private void sortInstanceByDisk(ArrayList<Integer> instance) {
  96. for (int i = 0; i < instance.size(); i++) {
  97. inst2AppIndex.get(i);
  98. }
  99. }
  100. private void sort(ArrayList<Integer> list) {
  101. }
  102. // 读取数据
  103. protected void init(BufferedReader bufferedReader) throws IOException {
  104. cpuIter = new ArrayList<Integer>();
  105. for (int i = 0; i < T; i++)
  106. cpuIter.add(i);
  107. /** Read app_resources */
  108. num_app = Integer.parseInt(bufferedReader.readLine());// 9338
  109. apps = new String[num_app];
  110. for (int i = 0; i < num_app; i++) {// 循环app表每一行
  111. // appId,resources
  112. String line = bufferedReader.readLine();
  113. String[] parts = line.split(",", -1);
  114. List<Double> resources = new ArrayList<Double>();
  115. for (String x : parts[1].split("\\|", -1))// cpu
  116. resources.add(Double.parseDouble(x));
  117. for (String x : parts[2].split("\\|", -1))// mem
  118. resources.add(Double.parseDouble(x));
  119. for (int j = 3; j < parts.length; j++) // disk/P/M/PM
  120. resources.add(Double.parseDouble(parts[j]));
  121. if (i == 0) {
  122. num_k = resources.size();
  123. appIndex = new HashMap<String, Integer>();
  124. appResources = new double[num_app][num_k];
  125. }
  126. if (num_k != resources.size())
  127. throw new IOException("[DEBUG 2]Invaild problem");
  128. if (appIndex.containsKey(parts[0]))
  129. throw new IOException("[DEBUG 3]Invaild problem");
  130. appIndex.put(parts[0], i);
  131. apps[i] = parts[0];// [app_1, app_2, app_3, app_4]
  132. for (int j = 0; j < num_k; j++)
  133. appResources[i][j] = resources.get(j);
  134. }
  135. /** Read machine_resources */
  136. num_mac = Integer.parseInt(bufferedReader.readLine());// 6000
  137. machineResources = new double[num_mac][num_k];
  138. machineResourcesUsed = new double[num_mac][num_k];
  139. machineIndex = new HashMap<String, Integer>();// {machine_3791=3790,
  140. machineHasApp = new Map[num_mac];
  141. machines = new String[num_mac];
  142. for (int i = 0; i < num_mac; i++) {
  143. // machineId,resources
  144. String line = bufferedReader.readLine();
  145. String[] parts = line.split(",", -1);
  146. if (machineIndex.containsKey(parts[0]))
  147. throw new IOException("[DEBUG 4]Invaild problem");
  148. machineIndex.put(parts[0], i);
  149. machines[i] = parts[0];
  150. machineHasApp[i] = new HashMap<Integer, Integer>();
  151. double cpu = Double.parseDouble(parts[1]);
  152. double mem = Double.parseDouble(parts[2]);
  153. for (int j = 0; j < T; j++) {
  154. machineResources[i][j] = cpu;
  155. machineResources[i][T + j] = mem;
  156. }
  157. for (int j = 3; j < parts.length; j++)
  158. machineResources[i][2 * T + j - 3] = Double.parseDouble(parts[j]);
  159. for (int j = 0; j < num_k; j++)
  160. machineResourcesUsed[i][j] = 0.;
  161. }
  162. // // 倒序排列,大主机在前面
  163. // List<Map.Entry<String, Integer>> list_tmp = new ArrayList<>();
  164. // for (Map.Entry<String, Integer> entry : machineIndex.entrySet()) {
  165. // list_tmp.add(entry); // 将map中的元素放入list中
  166. // }
  167. // list_tmp.sort(new Comparator<Map.Entry<String, Integer>>() {
  168. // @Override
  169. // public int compare(Map.Entry<String, Integer> o1, Map.Entry<String,
  170. // Integer> o2) {
  171. // return o2.getValue() - o1.getValue();
  172. // }
  173. // // 逆序(从大到小)排列,正序为“return o1.getValue()-o2.getValue”
  174. // });
  175. // machineIndex.clear();
  176. // for (Map.Entry<String, Integer> entry : list_tmp) {
  177. // machineIndex.put(entry.getKey(), entry.getValue());
  178. // }
  179. /** Read app_interference */
  180. int icnt = Integer.parseInt(bufferedReader.readLine());// 35242
  181. appInterference = new Map[num_app];
  182. for (int i = 0; i < num_app; i++)
  183. appInterference[i] = new HashMap<Integer, Integer>();
  184. for (int i = 0; i < icnt; i++) {
  185. String line = bufferedReader.readLine();
  186. String[] parts = line.split(",", -1);
  187. if (!appIndex.containsKey(parts[0]) || !appIndex.containsKey(parts[1]))
  188. throw new IOException("[DEBUG 8]Invaild problem");
  189. int app1 = appIndex.get(parts[0]);
  190. int app2 = appIndex.get(parts[1]);
  191. int limit = Integer.parseInt(parts[2]);
  192. Map<Integer, Integer> inter = appInterference[app1];
  193. if (inter.containsKey(app2))
  194. throw new IOException("[DEBUG 9]Invaild problem");
  195. if (app1 == app2)
  196. limit += 1; // self-interference +1 here
  197. inter.put(app2, limit);
  198. }
  199. /** Read instance_deploy */
  200. num_inst = Integer.parseInt(bufferedReader.readLine());// 68219
  201. inst2AppIndex = new HashMap<String, Integer>();// 68219*2
  202. // {inst_33717=8766,
  203. // inst_33718=2956}
  204. inst2Machine = new HashMap<String, Integer>();// {inst_33717=5456,
  205. for (int i = 0; i < num_inst; i++) {
  206. String line = bufferedReader.readLine();
  207. String[] parts = line.split(",", -1);
  208. if (inst2AppIndex.containsKey(parts[0]))
  209. throw new IOException("[DEBUG 5]Invaild problem");
  210. if (!appIndex.containsKey(parts[1]))
  211. throw new IOException("[DEBUG 6]Invaild problem");
  212. inst2AppIndex.put(parts[0], appIndex.get(parts[1]));
  213. if (!"".equals(parts[2])) {
  214. if (!machineIndex.containsKey(parts[2]))
  215. throw new IOException("[DEBUG 7]Invaild problem");
  216. toMachineDefault(parts[0], machineIndex.get(parts[2]));
  217. } else {
  218. instUnDelpoy.add(parts[0]);
  219. }
  220. }
  221. System.out.println("finish init");
  222. }
  223. private String toMachineDefault(String inst, int machineIt) {
  224. int appIt = inst2AppIndex.get(inst);
  225. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  226. String res_tmp = doCheck(inst, machineIt);
  227. if (res_tmp != "success") {
  228. inst2MachineDefaultConflict.put(inst, machineIt);
  229. }
  230. // 将inst放入新的machine
  231. inst2Machine.put(inst, machineIt);
  232. if (!hasApp.containsKey(appIt))
  233. hasApp.put(appIt, 0);
  234. hasApp.put(appIt, hasApp.get(appIt) + 1);
  235. for (int i = 0; i < num_k; i++)
  236. machineResourcesUsed[machineIt][i] += appResources[appIt][i];
  237. return "success";
  238. }
  239. private String toMachine(String inst, int machineIt) {
  240. return toMachine(inst, machineIt, true);
  241. }
  242. private String doCheck(String inst, int machineIt) {
  243. int appIt = inst2AppIndex.get(inst);
  244. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  245. // 检查互斥规则,初始数据这里有冲突
  246. int nowHas = 0;
  247. if (hasApp.containsKey(appIt))
  248. nowHas = hasApp.get(appIt);
  249. for (Integer conditionalApp : hasApp.keySet()) {
  250. if (hasApp.get(conditionalApp) <= 0)
  251. continue;
  252. if (!appInterference[conditionalApp].containsKey(appIt))
  253. continue;
  254. if (nowHas + 1 > appInterference[conditionalApp].get(appIt)) {
  255. return "App Interference, inst: " + inst + ", " + apps[conditionalApp] + " -> " + apps[appIt] + ", "
  256. + (nowHas + 1) + " > " + appInterference[conditionalApp].get(appIt);
  257. }
  258. }
  259. // 初始数据这里有冲突
  260. for (Integer checkApp : hasApp.keySet()) {
  261. if (!appInterference[appIt].containsKey(checkApp))
  262. continue;
  263. if (hasApp.get(checkApp) > appInterference[appIt].get(checkApp)) {
  264. return "App Interference, inst: " + inst + ", " + apps[appIt] + " -> " + apps[checkApp] + ", "
  265. + (nowHas + 1) + " > " + appInterference[appIt].get(checkApp);
  266. }
  267. }
  268. // 检查资源限制,初始数据这里没有冲突
  269. for (int i = 0; i < num_k; i++)
  270. if (dcmp(
  271. machineResourcesUsed[machineIt][i] + appResources[appIt][i] - machineResources[machineIt][i]) > 0) {
  272. String res = "Resource Limit: inst: " + inst + ", " + "machine: " + machines[machineIt] + ", app: "
  273. + apps[appIt] + ", resIter: " + i + ", " + machineResourcesUsed[machineIt][i] + " + "
  274. + appResources[appIt][i] + " > " + machineResources[machineIt][i];
  275. // System.out.println(res);
  276. return res;
  277. }
  278. return "success";
  279. }
  280. private String toMachine(String inst, int machineIt, boolean doCheck) {
  281. int appIt = inst2AppIndex.get(inst);
  282. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  283. if (doCheck) {
  284. String res_tmp = doCheck(inst, machineIt);
  285. if (res_tmp != "success") {
  286. return res_tmp;
  287. }
  288. }
  289. // 将inst放入新的machine
  290. inst2Machine.put(inst, machineIt);
  291. if (!hasApp.containsKey(appIt))
  292. hasApp.put(appIt, 0);
  293. hasApp.put(appIt, hasApp.get(appIt) + 1);
  294. for (int i = 0; i < num_k; i++)
  295. machineResourcesUsed[machineIt][i] += appResources[appIt][i];
  296. return "success";
  297. }
  298. /**
  299. * 把实例inst 移除主机,撤销消耗资源
  300. *
  301. * @param inst
  302. * 实例id
  303. */
  304. private void pickInstance(String inst) {
  305. if (!inst2Machine.containsKey(inst))
  306. return;
  307. int appIt = inst2AppIndex.get(inst);
  308. int fromMachine = inst2Machine.get(inst);
  309. // 更新machineHasApp
  310. Map<Integer, Integer> fromHasApp = machineHasApp[fromMachine];
  311. fromHasApp.put(appIt, fromHasApp.get(appIt) - 1);
  312. if (fromHasApp.get(appIt) <= 0)
  313. fromHasApp.remove(appIt);
  314. // 更新machineResourcesUsed
  315. for (int i = 0; i < num_k; i++)
  316. machineResourcesUsed[fromMachine][i] -= appResources[appIt][i];
  317. // 更新inst2Machine
  318. inst2Machine.remove(inst);
  319. }
  320. private int dcmp(double x) {
  321. if (Math.abs(x) < 1e-9)
  322. return 0;
  323. return x < 0. ? -1 : 1;
  324. }
  325. private void saveResult(List<String> res) throws IOException {
  326. String res_path = "result.csv";
  327. File file = new File(res_path);
  328. if (!file.exists()) {
  329. file.createNewFile();
  330. }
  331. BufferedWriter writer = new BufferedWriter(new FileWriter(file));
  332. for (int i = 0; i < res.size(); i++) {
  333. writer.write(res.get(i));
  334. writer.newLine();
  335. }
  336. // for (String line : res) {
  337. // writer.write(line);
  338. // writer.newLine();
  339. // }
  340. writer.close();
  341. }
  342. public static void main(String[] args) throws Exception {
  343. if (args.length != 4 && args.length != 2) {
  344. System.err.println(
  345. "传入参数有误,使用方式为:java -cp xxx.jar app_resources.csv machine_resources.csv instance_deploy.csv app_interference.csv");
  346. return;
  347. }
  348. System.out.println("-------开始部署啦--------");
  349. long startTime = System.currentTimeMillis(); // 获取开始时间
  350. InputStream problem;
  351. // app_resources.csv
  352. // machine_resources.csv
  353. // instance_deploy.csv
  354. // app_interference.csv
  355. if (args.length == 4) {
  356. // 将赛题拼成评测数据
  357. StringBuffer sb = new StringBuffer();
  358. for (int i = 0; i < 4; i++) {
  359. List<String> lines = new ArrayList<String>();
  360. BufferedReader bs = new BufferedReader(new FileReader(new File(args[i])));
  361. for (String line = bs.readLine(); line != null; line = bs.readLine())
  362. lines.add(line);
  363. sb.append("" + lines.size()).append("\n");
  364. for (String line : lines)
  365. sb.append(line).append("\n");
  366. }
  367. String alldata = sb.toString();
  368. problem = new ByteArrayInputStream(alldata.getBytes());
  369. } else {
  370. problem = new FileInputStream(args[0]);
  371. }
  372. // 评测
  373. Main2 evaluator = new Main2();
  374. evaluator.init(new BufferedReader(new InputStreamReader(problem, Charsets.UTF_8)));
  375. System.out.println("默认已经部署了:" + evaluator.inst2Machine.size());
  376. evaluator.run();
  377. long endTime = System.currentTimeMillis(); // 获取结束时间
  378. System.out.println("程序运行时间:" + (endTime - startTime) / 1000 + "s"); // 输出程序运行时间
  379. System.out.println("-------部署结束啦--------");
  380. }
  381. }