Main.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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. /**
  18. * 不考虑迁移代价而不断迁移,跑b数据9746。 Created by liuyuqi.gov@msn.cn on 2018/07/02.
  19. */
  20. public class Main {
  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 List<String> instSortByDisk = new ArrayList<String>();// 未部署的实例
  50. private Map<String, Integer> inst2MachineDefaultConflict = new HashMap<String, Integer>();;// 记录初始部署冲突的实例和主机
  51. private double[][] machineResourcesUsed;// 6000*200
  52. private Map<Integer, Integer>[] machineHasApp;// 6000 [{}, {},{6004=1,
  53. // 9126=1, 1598=1}, {}, {},
  54. // {},
  55. /**
  56. * 先对disk排序,然后first fit
  57. *
  58. * @throws IOException
  59. * 写文件异常
  60. */
  61. private void run() throws IOException {
  62. // 主机优先顺序,使用过的主机在前,目的紧凑;然后大主机在前。做一个主机优先部署序列
  63. String tmp_Res;
  64. String inst_tmp = null;
  65. int time_count = 0;
  66. long startTime=System.currentTimeMillis();
  67. long cost_time = 0;
  68. for (Map.Entry<String, Integer> entry : inst2AppIndex.entrySet()) {
  69. // 判断是否部署过,如果部署过则重新部署
  70. inst_tmp = entry.getKey();
  71. if (inst2Machine.containsKey(inst_tmp)) {
  72. pickInstance(entry.getKey());
  73. }
  74. for (int i = num_mac - 1; i >= 0; i--) {
  75. tmp_Res = toMachine(inst_tmp, i);
  76. if (tmp_Res == "success") {
  77. deployResult.add(inst_tmp + "," + "machine_" + (i + 1));
  78. break;
  79. }
  80. }
  81. time_count++;
  82. if (time_count % 5000 == 0) {
  83. cost_time = System.currentTimeMillis() - startTime;
  84. System.out.println("已经部署:" + time_count+" 剩余部署:" + (num_inst - time_count));
  85. System.out.println("预估剩余时间:" + ((cost_time / 1000) * (num_inst - time_count) / time_count)+"s");
  86. }
  87. }
  88. saveResult(deployResult);
  89. }
  90. // 读取数据
  91. protected void init(BufferedReader bufferedReader) throws IOException {
  92. cpuIter = new ArrayList<Integer>();
  93. for (int i = 0; i < T; i++)
  94. cpuIter.add(i);
  95. /** Read app_resources */
  96. num_app = Integer.parseInt(bufferedReader.readLine());// 9338
  97. apps = new String[num_app];
  98. for (int i = 0; i < num_app; i++) {// 循环app表每一行
  99. // appId,resources
  100. String line = bufferedReader.readLine();
  101. String[] parts = line.split(",", -1);
  102. List<Double> resources = new ArrayList<Double>();
  103. for (String x : parts[1].split("\\|", -1))// cpu
  104. resources.add(Double.parseDouble(x));
  105. for (String x : parts[2].split("\\|", -1))// mem
  106. resources.add(Double.parseDouble(x));
  107. for (int j = 3; j < parts.length; j++) // disk/P/M/PM
  108. resources.add(Double.parseDouble(parts[j]));
  109. if (i == 0) {
  110. num_k = resources.size();
  111. appIndex = new HashMap<String, Integer>();
  112. appResources = new double[num_app][num_k];
  113. }
  114. if (num_k != resources.size())
  115. throw new IOException("[DEBUG 2]Invaild problem");
  116. if (appIndex.containsKey(parts[0]))
  117. throw new IOException("[DEBUG 3]Invaild problem");
  118. appIndex.put(parts[0], i);
  119. apps[i] = parts[0];// [app_1, app_2, app_3, app_4]
  120. for (int j = 0; j < num_k; j++)
  121. appResources[i][j] = resources.get(j);
  122. }
  123. /** Read machine_resources */
  124. num_mac = Integer.parseInt(bufferedReader.readLine());// 6000
  125. machineResources = new double[num_mac][num_k];
  126. machineResourcesUsed = new double[num_mac][num_k];
  127. machineIndex = new HashMap<String, Integer>();// {machine_3791=3790,
  128. machineHasApp = new Map[num_mac];
  129. machines = new String[num_mac];
  130. for (int i = 0; i < num_mac; i++) {
  131. // machineId,resources
  132. String line = bufferedReader.readLine();
  133. String[] parts = line.split(",", -1);
  134. if (machineIndex.containsKey(parts[0]))
  135. throw new IOException("[DEBUG 4]Invaild problem");
  136. machineIndex.put(parts[0], i);
  137. machines[i] = parts[0];
  138. machineHasApp[i] = new HashMap<Integer, Integer>();
  139. double cpu = Double.parseDouble(parts[1]);
  140. double mem = Double.parseDouble(parts[2]);
  141. for (int j = 0; j < T; j++) {
  142. machineResources[i][j] = cpu;
  143. machineResources[i][T + j] = mem;
  144. }
  145. for (int j = 3; j < parts.length; j++)
  146. machineResources[i][2 * T + j - 3] = Double.parseDouble(parts[j]);
  147. for (int j = 0; j < num_k; j++)
  148. machineResourcesUsed[i][j] = 0.;
  149. }
  150. /** Read app_interference */
  151. int icnt = Integer.parseInt(bufferedReader.readLine());// 35242
  152. appInterference = new Map[num_app];
  153. for (int i = 0; i < num_app; i++)
  154. appInterference[i] = new HashMap<Integer, Integer>();
  155. for (int i = 0; i < icnt; i++) {
  156. String line = bufferedReader.readLine();
  157. String[] parts = line.split(",", -1);
  158. if (!appIndex.containsKey(parts[0]) || !appIndex.containsKey(parts[1]))
  159. throw new IOException("[DEBUG 8]Invaild problem");
  160. int app1 = appIndex.get(parts[0]);
  161. int app2 = appIndex.get(parts[1]);
  162. int limit = Integer.parseInt(parts[2]);
  163. Map<Integer, Integer> inter = appInterference[app1];
  164. if (inter.containsKey(app2))
  165. throw new IOException("[DEBUG 9]Invaild problem");
  166. if (app1 == app2)
  167. limit += 1; // self-interference +1 here
  168. inter.put(app2, limit);
  169. }
  170. /** Read instance_deploy */
  171. num_inst = Integer.parseInt(bufferedReader.readLine());// 68219
  172. inst2AppIndex = new HashMap<String, Integer>();// 68219*2
  173. // {inst_33717=8766,
  174. // inst_33718=2956}
  175. inst2Machine = new HashMap<String, Integer>();// {inst_33717=5456,
  176. for (int i = 0; i < num_inst; i++) {
  177. String line = bufferedReader.readLine();
  178. String[] parts = line.split(",", -1);
  179. if (inst2AppIndex.containsKey(parts[0]))
  180. throw new IOException("[DEBUG 5]Invaild problem");
  181. if (!appIndex.containsKey(parts[1]))
  182. throw new IOException("[DEBUG 6]Invaild problem");
  183. inst2AppIndex.put(parts[0], appIndex.get(parts[1]));
  184. if (!"".equals(parts[2])) {
  185. if (!machineIndex.containsKey(parts[2]))
  186. throw new IOException("[DEBUG 7]Invaild problem");
  187. toMachineDefault(parts[0], machineIndex.get(parts[2]));
  188. } else {
  189. instUnDelpoy.add(parts[0]);
  190. }
  191. }
  192. System.out.println("finish init");
  193. }
  194. private String toMachineDefault(String inst, int machineIt) {
  195. int appIt = inst2AppIndex.get(inst);
  196. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  197. String res_tmp = doCheck(inst, machineIt);
  198. if (res_tmp != "success") {
  199. inst2MachineDefaultConflict.put(inst, machineIt);
  200. }
  201. // 将inst放入新的machine
  202. inst2Machine.put(inst, machineIt);
  203. if (!hasApp.containsKey(appIt))
  204. hasApp.put(appIt, 0);
  205. hasApp.put(appIt, hasApp.get(appIt) + 1);
  206. for (int i = 0; i < num_k; i++)
  207. machineResourcesUsed[machineIt][i] += appResources[appIt][i];
  208. return "success";
  209. }
  210. private String toMachine(String inst, int machineIt) {
  211. return toMachine(inst, machineIt, true);
  212. }
  213. private String doCheck(String inst, int machineIt) {
  214. int appIt = inst2AppIndex.get(inst);
  215. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  216. // 检查互斥规则,初始数据这里有冲突
  217. int nowHas = 0;
  218. if (hasApp.containsKey(appIt))
  219. nowHas = hasApp.get(appIt);
  220. for (Integer conditionalApp : hasApp.keySet()) {
  221. if (hasApp.get(conditionalApp) <= 0)
  222. continue;
  223. if (!appInterference[conditionalApp].containsKey(appIt))
  224. continue;
  225. if (nowHas + 1 > appInterference[conditionalApp].get(appIt)) {
  226. return "App Interference, inst: " + inst + ", " + apps[conditionalApp] + " -> " + apps[appIt] + ", "
  227. + (nowHas + 1) + " > " + appInterference[conditionalApp].get(appIt);
  228. }
  229. }
  230. // 初始数据这里有冲突
  231. for (Integer checkApp : hasApp.keySet()) {
  232. if (!appInterference[appIt].containsKey(checkApp))
  233. continue;
  234. if (hasApp.get(checkApp) > appInterference[appIt].get(checkApp)) {
  235. return "App Interference, inst: " + inst + ", " + apps[appIt] + " -> " + apps[checkApp] + ", "
  236. + (nowHas + 1) + " > " + appInterference[appIt].get(checkApp);
  237. }
  238. }
  239. // 检查资源限制,初始数据这里没有冲突
  240. for (int i = 0; i < num_k; i++)
  241. if (dcmp(
  242. machineResourcesUsed[machineIt][i] + appResources[appIt][i] - machineResources[machineIt][i]) > 0) {
  243. String res = "Resource Limit: inst: " + inst + ", " + "machine: " + machines[machineIt] + ", app: "
  244. + apps[appIt] + ", resIter: " + i + ", " + machineResourcesUsed[machineIt][i] + " + "
  245. + appResources[appIt][i] + " > " + machineResources[machineIt][i];
  246. // System.out.println(res);
  247. return res;
  248. }
  249. return "success";
  250. }
  251. private String toMachine(String inst, int machineIt, boolean doCheck) {
  252. int appIt = inst2AppIndex.get(inst);
  253. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  254. if (doCheck) {
  255. String res_tmp = doCheck(inst, machineIt);
  256. if (res_tmp != "success") {
  257. return res_tmp;
  258. }
  259. }
  260. // 将inst放入新的machine
  261. inst2Machine.put(inst, machineIt);
  262. if (!hasApp.containsKey(appIt))
  263. hasApp.put(appIt, 0);
  264. hasApp.put(appIt, hasApp.get(appIt) + 1);
  265. for (int i = 0; i < num_k; i++)
  266. machineResourcesUsed[machineIt][i] += appResources[appIt][i];
  267. return "success";
  268. }
  269. /**
  270. * 把实例inst 移除主机,撤销消耗资源
  271. *
  272. * @param inst
  273. * 实例id
  274. */
  275. private void pickInstance(String inst) {
  276. if (!inst2Machine.containsKey(inst))
  277. return;
  278. int appIt = inst2AppIndex.get(inst);
  279. int fromMachine = inst2Machine.get(inst);
  280. // 更新machineHasApp
  281. Map<Integer, Integer> fromHasApp = machineHasApp[fromMachine];
  282. fromHasApp.put(appIt, fromHasApp.get(appIt) - 1);
  283. if (fromHasApp.get(appIt) <= 0)
  284. fromHasApp.remove(appIt);
  285. // 更新machineResourcesUsed
  286. for (int i = 0; i < num_k; i++)
  287. machineResourcesUsed[fromMachine][i] -= appResources[appIt][i];
  288. // 更新inst2Machine
  289. inst2Machine.remove(inst);
  290. }
  291. private int dcmp(double x) {
  292. if (Math.abs(x) < 1e-9)
  293. return 0;
  294. return x < 0. ? -1 : 1;
  295. }
  296. private void saveResult(List<String> res) throws IOException {
  297. String res_path = "result.csv";
  298. File file = new File(res_path);
  299. if (!file.exists()) {
  300. file.createNewFile();
  301. }
  302. BufferedWriter writer = new BufferedWriter(new FileWriter(file));
  303. for (int i = 0; i < res.size(); i++) {
  304. writer.write(res.get(i));
  305. writer.newLine();
  306. }
  307. writer.close();
  308. }
  309. public static void main(String[] args) throws Exception {
  310. if (args.length != 4 && args.length != 2) {
  311. System.err.println(
  312. "传入参数有误,使用方式为:java -cp xxx.jar app_resources.csv machine_resources.csv instance_deploy.csv app_interference.csv");
  313. return;
  314. }
  315. System.out.println("-------开始部署啦--------");
  316. long startTime = System.currentTimeMillis(); // 获取开始时间
  317. InputStream problem;
  318. // app_resources.csv
  319. // machine_resources.csv
  320. // instance_deploy.csv
  321. // app_interference.csv
  322. if (args.length == 4) {
  323. // 将赛题拼成评测数据
  324. StringBuffer sb = new StringBuffer();
  325. for (int i = 0; i < 4; i++) {
  326. List<String> lines = new ArrayList<String>();
  327. BufferedReader bs = new BufferedReader(new FileReader(new File(args[i])));
  328. for (String line = bs.readLine(); line != null; line = bs.readLine())
  329. lines.add(line);
  330. sb.append("" + lines.size()).append("\n");
  331. for (String line : lines)
  332. sb.append(line).append("\n");
  333. }
  334. String alldata = sb.toString();
  335. problem = new ByteArrayInputStream(alldata.getBytes());
  336. } else {
  337. problem = new FileInputStream(args[0]);
  338. }
  339. // 评测
  340. Main evaluator = new Main();
  341. evaluator.init(new BufferedReader(new InputStreamReader(problem, Charsets.UTF_8)));
  342. System.out.println("默认已经部署了:" + evaluator.inst2Machine.size());
  343. evaluator.run();
  344. long endTime = System.currentTimeMillis(); // 获取结束时间
  345. System.out.println("程序运行时间:" + (endTime - startTime) / 1000 + "s"); // 输出程序运行时间
  346. System.out.println("-------部署结束啦--------");
  347. }
  348. }