1 package org.cloudbus.cloudsim;
2
3 import java.text.DecimalFormat;//十进制
4 import java.util.ArrayList;
5 import java.util.HashMap;//哈希映射
6 import java.util.Iterator;//迭代器
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10
11 import org.cloudbus.cloudsim.core.CloudSim;//这个类扩展了CloudSimCore使网络模拟在CloudSim中实现
12 import org.cloudbus.cloudsim.core.CloudSimTags;//含有多种静态命令,当CloudSim实体接收或发送事件时,表明被执行的一种行为
13 import org.cloudbus.cloudsim.core.SimEntity;//代表一仿真实体,实体操作事件并可以发送事件到其他实体,要扩展这个类需要加入startEntity(),processEvent()and shutdownEntity()
14 import org.cloudbus.cloudsim.core.SimEvent;//仿真事件 在实体间传递
15
16 /**
17 * Datacenter class is {a CloudResource whose hostList
18 * are virtualized}. It deals with processing of VM queries (i.e., handling
19 * of VMs) instead of processing Cloudlet-related queries. So, even though an
20 * AllocPolicy will be instantiated (in the init() method of the superclass,
21 * it will not be used, as processing of (cloudlets )are handled by the (CloudletScheduler)
22 * and processing of 【VirtualMachines 】are handled by the【 VmAllocationPolicy】.
23 *
24 * @author Rodrigo N. Calheiros
25 * @author Anton Beloglazov
26 * @since CloudSim Toolkit 1.0
27 */
28 public class Datacenter extends SimEntity {//扩展SimEntity类
29
30 /** The characteristics. *///数据中心特性
31 private DatacenterCharacteristics characteristics;
32
33 /** The regional cis name. *///局部CIS名称
34 private String regionalCisName;
35
36 /** The vm provisioner. *///虚拟机供应
37 private VmAllocationPolicy vmAllocationPolicy;
38
39 /** The last process time. *///上一次处理时间
40 private double lastProcessTime;
41
42 /** The debts. *///费用
43 private Map<Integer, Double> debts;
44
45 /** The storage list. *///存储列表
46 private List<Storage> storageList;
47
48 /** The vm list. *///虚拟机列表
49 private List<? extends Vm> vmList;
50
51 /** The scheduling interval. *///调度间隔
52 private double schedulingInterval;
53
54 /**分配一个功率意识的数据中心对象
55 * Allocates a new PowerDatacenter object.
56 *
57 * @param name the name to be associated with this entity (as
58 * required by Sim_entity class from simjava package)
59 * @param characteristics an object of DatacenterCharacteristics
60 * @param storageList a LinkedList of storage elements, for data simulation
61 * @param vmAllocationPolicy the vmAllocationPolicy
62 *
63 * @throws Exception This happens when one of the following scenarios occur:
64 * <ul>
65 * <li> creating this entity before initializing CloudSim package
66 * <li> this entity name is <tt>null</tt> or empty
67 * <li> this entity has <tt>zero</tt> number of PEs (Processing
68 * Elements). <br>
69 * No PEs mean the Cloudlets can't be processed.
70 * A CloudResource must contain【 one or more Machines】.
71 * A Machine must contain 【one or more PEs】.
72 * </ul>
73 *
74 * @pre name != null
75 * @pre resource != null
76 * @post $none
77 */
78 public Datacenter(String name, DatacenterCharacteristics characteristics, VmAllocationPolicy vmAllocationPolicy, List<Storage> storageList, double schedulingInterval) throws Exception {
79 super(name);
80
81 setCharacteristics(characteristics);
82 setVmAllocationPolicy(vmAllocationPolicy);
83 setLastProcessTime(0.0);
84 setDebts(new HashMap<Integer,Double>());
85 setStorageList(storageList);
86 setVmList(new ArrayList<Vm>());
87 setSchedulingInterval(schedulingInterval);
88
89 // If this resource doesn't have any PEs then no useful at all 资源没有PE 则是没有用(不能处理云任务)
90 if (getCharacteristics().getPesNumber() == 0) {
91 throw new Exception(super.getName() + " : Error - this entity has no PEs. Therefore, can't process any Cloudlets.");
92 }
93
94 // stores id of this class类的存储ID
95 getCharacteristics().setId(super.getId());
96 }
97
98 /**重写此方法 以创建一个新的不同类型的资源
99 * Overrides this method when making a new and different type of resource.
100 * This method is called by {@link #body()} to register other type to
101 * GIS entity. In doing so, you
102 * need to create a new child class extending from
103 * gridsim.CloudInformationService.
104 * <br>
105 * <b>NOTE:</b> 【You do not need to override {@link #body()} method, if
106 * you use this method.】
107 *
108 * @pre $none
109 * @post $none
110 */
111 protected void registerOtherEntity() {
112 // empty. This should be override by a child class 【用一个子类重写】
113 }
114
115 /**处理时间 服务
116 * Processes events or services that are available for this PowerDatacenter.
117 *
118 * @param ev a Sim_event object
119 *
120 * @pre ev != null
121 * @post $none
122 */
123 @Override
124 public void processEvent(SimEvent ev) { //implements org.cloudbus.cloudsim.core.SimEntity.processEvent
125 int srcId = -1;
126 //Log.printLine(CloudSim.clock()+"[PowerDatacenter]: event received:"+ev.getTag());
127
128 switch (ev.getTag()) {
129 // Resource characteristics inquiry 资源特征调查
130 case CloudSimTags.RESOURCE_CHARACTERISTICS:
131 srcId = ((Integer) ev.getData()).intValue();
132 sendNow(srcId, ev.getTag(), getCharacteristics());
133 break;
134
135 // Resource dynamic info inquiry 资源动态信息查询
136 case CloudSimTags.RESOURCE_DYNAMICS:
137 srcId = ((Integer) ev.getData()).intValue();
138 sendNow(srcId, ev.getTag(), 0);
139 break;
140
141 case CloudSimTags.RESOURCE_NUM_PE:
142 srcId = ((Integer) ev.getData()).intValue();
143 int numPE = getCharacteristics().getPesNumber();
144 sendNow(srcId, ev.getTag(), numPE);
145 break;
146
147 case CloudSimTags.RESOURCE_NUM_FREE_PE:
148 srcId = ((Integer) ev.getData()).intValue();
149 int freePesNumber = getCharacteristics().getFreePesNumber();
150 sendNow(srcId, ev.getTag(), freePesNumber);
151 break;
152
153 // New Cloudlet arrives 新的云任务到达
154 case CloudSimTags.CLOUDLET_SUBMIT:
155 processCloudletSubmit(ev, false);
156 break;
157
158 // New Cloudlet arrives, but the sender asks for an ack 确认
159 case CloudSimTags.CLOUDLET_SUBMIT_ACK:
160 processCloudletSubmit(ev, true);
161 break;
162
163 // Cancels a previously submitted Cloudlet取消一个先前提交的云任务
164 case CloudSimTags.CLOUDLET_CANCEL:
165 processCloudlet(ev, CloudSimTags.CLOUDLET_CANCEL);
166 break;
167
168 // Pauses a previously submitted Cloudlet暂停一个先前提交的云任务
169 case CloudSimTags.CLOUDLET_PAUSE:
170 processCloudlet(ev, CloudSimTags.CLOUDLET_PAUSE);
171 break;
172
173 // Pauses a previously submitted Cloudlet, but the sender
174 // asks for an acknowledgement取消一个先前提交的云任务 发送则者要求确认
175 case CloudSimTags.CLOUDLET_PAUSE_ACK:
176 processCloudlet(ev, CloudSimTags.CLOUDLET_PAUSE_ACK);
177 break;
178
179 // Resumes a previously submitted Cloudlet重启一个先前提交的云任务
180 case CloudSimTags.CLOUDLET_RESUME:
181 processCloudlet(ev, CloudSimTags.CLOUDLET_RESUME);
182 break;
183
184 // Resumes a previously submitted Cloudlet, but the sender
185 // asks for an acknowledgement重启一个先前提交的云任务 发送则者要求确认
186 case CloudSimTags.CLOUDLET_RESUME_ACK:
187 processCloudlet(ev, CloudSimTags.CLOUDLET_RESUME_ACK);
188 break;
189
190 // Moves a previously submitted Cloudlet to a different resource移动一个先前提交的云任务
191 case CloudSimTags.CLOUDLET_MOVE:
192 processCloudletMove((int[]) ev.getData(), CloudSimTags.CLOUDLET_MOVE);
193 break;
194
195 // Moves a previously submitted Cloudlet to a different resource
196 case CloudSimTags.CLOUDLET_MOVE_ACK:
197 processCloudletMove((int[]) ev.getData(), CloudSimTags.CLOUDLET_MOVE_ACK);
198 break;
199
200 // Checks the status of a Cloudlet检查云任务状态
201 case CloudSimTags.CLOUDLET_STATUS:
202 processCloudletStatus(ev);
203 break;
204
205 // Ping packet
206 case CloudSimTags.INFOPKT_SUBMIT:
207 processPingRequest(ev);
208 break;
209
210 case CloudSimTags.VM_CREATE:
211 processVmCreate(ev, false);
212 break;
213
214 case CloudSimTags.VM_CREATE_ACK:
215 processVmCreate(ev, true);
216 break;
217
218 case CloudSimTags.VM_DESTROY:
219 processVmDestroy(ev, false);
220 break;
221
222 case CloudSimTags.VM_DESTROY_ACK:
223 processVmDestroy(ev, true);
224 break;
225
226 case CloudSimTags.VM_MIGRATE:
227 processVmMigrate(ev, false);
228 break;
229
230 case CloudSimTags.VM_MIGRATE_ACK:
231 processVmMigrate(ev, true);
232 break;
233
234 case CloudSimTags.VM_DATA_ADD:
235 processDataAdd(ev, false);
236 break;
237
238 case CloudSimTags.VM_DATA_ADD_ACK:
239 processDataAdd(ev, true);
240 break;
241
242 case CloudSimTags.VM_DATA_DEL:
243 processDataDelete(ev, false);
244 break;
245
246 case CloudSimTags.VM_DATA_DEL_ACK:
247 processDataDelete(ev, true);
248 break;
249
250 case CloudSimTags.VM_DATACENTER_EVENT:
251 updateCloudletProcessing();
252 checkCloudletCompletion();
253 break;
254
255 // other unknown tags are processed by this method通过这种方法处理其他不知道的标签
256 default:
257 processOtherEvent(ev);
258 break;
259 }
260 }
261
262 /**处理数据删除文件
263 * Process data del.
264 *
265 * @param ev the ev
266 * @param ack the ack
267 */
268 protected void processDataDelete(SimEvent ev, boolean ack) {
269 if (ev == null) {
270 return;
271 }
272
273 Object[] data = (Object[]) ev.getData();
274 if (data == null) {
275 return;
276 }
277
278 String filename = (String) data[0];
279 int req_source = ((Integer) data[1]).intValue();
280 int tag = -1;
281
282 // check if this file can be deleted (do not delete is right now)检查文件是否可以删除
283 int msg = deleteFileFromStorage(filename);
284 if (msg == DataCloudTags.FILE_DELETE_SUCCESSFUL) {
285 tag = DataCloudTags.CTLG_DELETE_MASTER;
286 } else { // if an error occured, notify user
287 tag = DataCloudTags.FILE_DELETE_MASTER_RESULT;
288 }
289
290 if (ack){
291 // send back to sender
292 Object pack[] = new Object[2];
293 pack[0] = filename;
294 pack[1] = Integer.valueOf(msg);
295
296 sendNow(req_source, tag, pack);
297 }
298 }
299
300 /**数据增加
301 * Process data add.
302 *
303 * @param ev the ev
304 * @param ack the ack
305 */
306 protected void processDataAdd(SimEvent ev, boolean ack) {
307 if (ev == null) {
308 return;
309 }
310
311 Object[] pack = (Object[]) ev.getData();
312 if (pack == null) {
313 return;
314 }
315
316 File file = (File) pack[0]; // get the file
317 file.setMasterCopy(true); // set the file into a master copy
318 int sentFrom = ((Integer) pack[1]).intValue(); // get sender ID
319
320 /****** // DEBUG
321 Log.printLine(super.get_name() + ".addMasterFile(): " +
322 file.getName() + " from " + CloudSim.getEntityName(sentFrom));
323 *******/
324
325 Object[] data = new Object[3];
326 data[0] = file.getName();
327
328 int msg = addFile(file); // add the file
329
330 double debit;
331 if (getDebts().containsKey(sentFrom)) {
332 debit = getDebts().get(sentFrom);
333 } else {
334 debit = 0.0;
335 }
336
337 debit += getCharacteristics().getCostPerBw() * file.getSize();
338
339 getDebts().put(sentFrom, debit);
340
341 if (ack) {
342 data[1] = Integer.valueOf(-1); // no sender id
343 data[2] = Integer.valueOf(msg); // the result of adding a master file
344 sendNow(sentFrom, DataCloudTags.FILE_ADD_MASTER_RESULT, data);
345 }
346 }
347
348 /**
349 * Processes a ping request.
350 *
351 * @param ev a Sim_event object
352 *
353 * @pre ev != null
354 * @post $none
355 */
356 protected void processPingRequest(SimEvent ev) {
357 InfoPacket pkt = (InfoPacket) ev.getData();
358 pkt.setTag(CloudSimTags.INFOPKT_RETURN);
359 pkt.setDestId(pkt.getSrcId());
360
361 // sends back to the sender
362 sendNow(pkt.getSrcId(), CloudSimTags.INFOPKT_RETURN, pkt);
363 }
364
365 /**处理事件:用户/代理想知道云任务状态
366 * Process the event for an User/Broker who wants to know the status of a Cloudlet.
367 * This PowerDatacenter will then send the status back to the User/Broker.
368 *
369 * @param ev a Sim_event object
370 *
371 * @pre ev != null
372 * @post $none
373 */
374 protected void processCloudletStatus(SimEvent ev) {
375 int cloudletId = 0;
376 int userId = 0;
377 int vmId = 0;
378 int status = -1;
379
380 try{
381 // if a sender using 【cloudletXXX() methods】
382 int data[] = (int[]) ev.getData();
383 cloudletId = data[0];
384 userId = data[1];
385 vmId = data[2];
386
387 status = getVmAllocationPolicy().getHost(vmId, userId).getVm(userId, vmId).getCloudletScheduler().getCloudletStatus(cloudletId);
388 }
389
390 // if a sender using normal 【send() methods】
391 catch (ClassCastException c) {
392 try {
393 Cloudlet cl = (Cloudlet) ev.getData();
394 cloudletId = cl.getCloudletId();
395 userId = cl.getUserId();
396
397 status = getVmAllocationPolicy().getHost(vmId, userId).getVm(userId, vmId).getCloudletScheduler().getCloudletStatus(cloudletId);
398 }
399 catch (Exception e) {
400 Log.printLine(getName() +
401 ": Error in processing CloudSimTags.CLOUDLET_STATUS");
402 Log.printLine( e.getMessage() );
403 return;
404 }
405 }
406 catch (Exception e) {
407 Log.printLine(getName() +
408 ": Error in processing CloudSimTags.CLOUDLET_STATUS");
409 Log.printLine( e.getMessage() );
410 return;
411 }
412
413 int[] array = new int[3];
414 array[0] = getId();
415 array[1] = cloudletId;
416 array[2] = status;
417
418 int tag = CloudSimTags.CLOUDLET_STATUS;
419 sendNow(userId, tag, array);
420 }
421
422 /**
423 * Here all the method related to 【VM requests 】will be received and forwarded to the related method.
424 *
425 * @param ev the received event
426 *
427 * @pre $none
428 * @post $none
429 */
430 protected void processOtherEvent(SimEvent ev) {
431 if (ev == null){
432 Log.printLine(getName() + ".processOtherEvent(): Error - an event is null.");
433 }
434 }
435
436 /**处理事件:用户/代理创建一个虚拟机
437 * Process the event for an User/Broker who wants to create a VM
438 * in this PowerDatacenter. This PowerDatacenter will then send the status back to
439 * the User/Broker.
440 *
441 * @param ev a Sim_event object
442 * @param ack the ack
443 *
444 * @pre ev != null
445 * @post $none
446 */
447 protected void processVmCreate(SimEvent ev, boolean ack) {
448 Vm vm = (Vm) ev.getData();
449
450 boolean result = getVmAllocationPolicy().allocateHostForVm(vm);
451
452 if (ack) {
453 int[] data = new int[3];
454 data[0] = getId();
455 data[1] = vm.getId();
456
457 if (result) {
458 data[2] = CloudSimTags.TRUE;
459 } else {
460 data[2] = CloudSimTags.FALSE;
461 }
462 sendNow(vm.getUserId(), CloudSimTags.VM_CREATE_ACK, data);
463 }
464
465 if (result) {
466 double amount = 0.0;
467 if (getDebts().containsKey(vm.getUserId())) {
468 amount = getDebts().get(vm.getUserId());
469 }
470 amount += getCharacteristics().getCostPerMem() * vm.getRam();
471 amount += getCharacteristics().getCostPerStorage() * vm.getSize();
472
473 getDebts().put(vm.getUserId(), amount);
474
475 getVmList().add(vm);
476
477 vm.updateVmProcessing(CloudSim.clock(), getVmAllocationPolicy().getHost(vm).getVmScheduler().getAllocatedMipsForVm(vm));
478 }
479
480 }
481
482 /**处理事件:用户/代理销毁虚拟机
483 * Process the event for an User/Broker who wants to destroy a VM
484 * previously created in this PowerDatacenter. This PowerDatacenter may send,
485 * upon request, the status back to the User/Broker.
486 *
487 * @param ev a Sim_event object
488 * @param ack the ack
489 *
490 * @pre ev != null
491 * @post $none
492 */
493 protected void processVmDestroy(SimEvent ev, boolean ack) {
494 Vm vm = (Vm) ev.getData();
495 getVmAllocationPolicy().deallocateHostForVm(vm);
496
497 if (ack) {
498 int[] data = new int[3];
499 data[0] = getId();
500 data[1] = vm.getId();
501 data[2] = CloudSimTags.TRUE;
502
503 sendNow(vm.getUserId(), CloudSimTags.VM_DESTROY_ACK, data);
504 }
505
506 getVmList().remove(vm);
507 }
508
509 /**处理事件:用户/代理迁移虚拟机
510 * Process the event for an User/Broker who wants to migrate a VM.
511 * This PowerDatacenter will then send the status back to the User/Broker.
512 * @param ev a Sim_event object
513 * @pre ev != null
514 * @post $none
515 */
516 protected void processVmMigrate(SimEvent ev, boolean ack) {
517 Object tmp = ev.getData();
518 if (!(tmp instanceof Map<?, ?>)) {
519 throw new ClassCastException("The data object must be Map<String, Object>");
520 }
521
522 @SuppressWarnings("unchecked")
523 Map<String, Object> migrate = (HashMap<String, Object>) tmp;
524
525 Vm vm = (Vm) migrate.get("vm");
526 Host host = (Host) migrate.get("host");
527
528 getVmAllocationPolicy().deallocateHostForVm(vm);
529 host.removeMigratingInVm(vm);
530 boolean result = getVmAllocationPolicy().allocateHostForVm(vm, host);
531 if (!result) {
532 Log.printLine("Allocation failed");
533 }
534
535 if (ack) {
536 int[] data = new int[3];
537 data[0] = getId();
538 data[1] = vm.getId();
539
540 if (result) {
541 data[2] = CloudSimTags.TRUE;
542 } else {
543 data[2] = CloudSimTags.FALSE;
544 }
545 sendNow(ev.getSource(), CloudSimTags.VM_CREATE_ACK, data);
546 }
547
548 double amount=0.0;
549 if (debts.containsKey(vm.getUserId())) {
550 amount = debts.get(vm.getUserId());
551 }
552
553 amount += getCharacteristics().getCostPerMem() * vm.getRam();
554 amount += getCharacteristics().getCostPerStorage() * vm.getSize();
555
556 debts.put(vm.getUserId(), amount);
557
558 Log.formatLine("%.2f: Migration of VM #%d to Host #%d is completed", CloudSim.clock(), vm.getId(), host.getId());
559 vm.setInMigration(false);
560 }
561
562 /**基于事件类别处理云任务
563 * Processes a Cloudlet based on the event type.
564 *
565 * @param ev a Sim_event object
566 * @param type event type
567 *
568 * @pre ev != null
569 * @pre type > 0
570 * @post $none
571 */
572 protected void processCloudlet(SimEvent ev, int type) {
573 int cloudletId = 0;
574 int userId = 0;
575 int vmId = 0;
576
577 try { // if the sender using 【cloudletXXX() methods】
578 int data[] = (int[]) ev.getData();
579 cloudletId = data[0];
580 userId = data[1];
581 vmId = data[2];
582 }
583
584 // if the sender using 【normal send() methods】
585 catch (ClassCastException c) {
586 try {
587 Cloudlet cl = (Cloudlet) ev.getData();
588 cloudletId = cl.getCloudletId();
589 userId = cl.getUserId();
590 vmId = cl.getVmId();
591 } catch (Exception e) {
592 Log.printLine(super.getName() + ": Error in processing Cloudlet");
593 Log.printLine(e.getMessage());
594 return;
595 }
596 } catch (Exception e) {
597 Log.printLine(super.getName() + ": Error in processing a Cloudlet.");
598 Log.printLine( e.getMessage() );
599 return;
600 }
601
602 // begins executing ....
603 switch (type) {
604 case CloudSimTags.CLOUDLET_CANCEL:
605 processCloudletCancel(cloudletId, userId, vmId);
606 break;
607
608 case CloudSimTags.CLOUDLET_PAUSE:
609 processCloudletPause(cloudletId, userId, vmId, false);
610 break;
611
612 case CloudSimTags.CLOUDLET_PAUSE_ACK:
613 processCloudletPause(cloudletId, userId, vmId, true);
614 break;
615
616 case CloudSimTags.CLOUDLET_RESUME:
617 processCloudletResume(cloudletId, userId, vmId, false);
618 break;
619
620 case CloudSimTags.CLOUDLET_RESUME_ACK:
621 processCloudletResume(cloudletId, userId, vmId, true);
622 break;
623 default:
624 break;
625 }
626
627 }
628
629 /**处理事件:用户/代理移动云任务
630 * Process the event for an User/Broker who wants to move a Cloudlet.
631 *
632 * @param receivedData information about the migration
633 * @param type event tag
634 *
635 * @pre receivedData != null
636 * @pre type > 0
637 * @post $none
638 */
639 protected void processCloudletMove(int[] receivedData, int type) {
640 updateCloudletProcessing();
641
642 int[] array = receivedData;
643 int cloudletId = array[0];
644 int userId = array[1];
645 int vmId = array[2];
646 int vmDestId = array[3];
647 int destId = array[4];
648
649 //get the cloudlet
650 Cloudlet cl = getVmAllocationPolicy().getHost(vmId, userId).getVm(userId, vmId).getCloudletScheduler().cloudletCancel(cloudletId);
651
652 boolean failed=false;
653 if (cl == null) {// cloudlet doesn't exist
654 failed = true;
655 } else {
656 // has the cloudlet already finished?
657 if (cl.getCloudletStatus() == Cloudlet.SUCCESS) {// if yes, send it back to user
658 int[] data = new int[3];
659 data[0] = this.getId();
660 data[1] = cloudletId;
661 data[2] = 0;
662 sendNow(cl.getUserId(), CloudSimTags.CLOUDLET_SUBMIT_ACK, data);
663 sendNow(cl.getUserId(), CloudSimTags.CLOUDLET_RETURN, cl);
664 }
665
666 // prepare cloudlet for migration
667 cl.setVmId(vmDestId);
668
669 // the cloudlet will migrate from one vm to another does the destination VM exist?
670 if (destId == this.getId()) {
671 Vm vm = getVmAllocationPolicy().getHost(vmDestId, userId).getVm(userId, vmDestId);
672 if (vm == null) {
673 failed = true;
674 } else {
675 double fileTransferTime = predictFileTransferTime(cl.getRequiredFiles()); // time to transfer the files
676 vm.getCloudletScheduler().cloudletSubmit(cl, fileTransferTime);
677 }
678 } else {// the cloudlet will migrate from one resource to another
679 int tag = ((type == CloudSimTags.CLOUDLET_MOVE_ACK) ? CloudSimTags.CLOUDLET_SUBMIT_ACK : CloudSimTags.CLOUDLET_SUBMIT);
680 sendNow(destId, tag, cl);
681 }
682 }
683
684 if (type == CloudSimTags.CLOUDLET_MOVE_ACK) {// send ACK if requested
685 int[] data = new int[3];
686 data[0] = this.getId();
687 data[1] = cloudletId;
688 if (failed) {
689 data[2] = 0;
690 } else {
691 data[2] = 1;
692 }
693 sendNow(cl.getUserId(), CloudSimTags.CLOUDLET_SUBMIT_ACK, data);
694 }
695 }
696
697 /**处理事件:云任务提交
698 * Processes a Cloudlet submission.
699 *
700 * @param ev a SimEvent object
701 * @param ack an acknowledgement
702 *
703 * @pre ev != null
704 * @post $none
705 */
706 protected void processCloudletSubmit(SimEvent ev, boolean ack) {
707 updateCloudletProcessing();
708
709 try {
710 // gets the Cloudlet object
711 Cloudlet cl = (Cloudlet) ev.getData();
712
713 // checks whether this Cloudlet has finished or not
714 if (cl.isFinished()){
715 String name = CloudSim.getEntityName(cl.getUserId());
716 Log.printLine(getName()+": Warning - Cloudlet #"+cl.getCloudletId()+" owned by "+name+" is already completed/finished.");
717 Log.printLine("Therefore, it is not being executed again");
718 Log.printLine();
719
720 // NOTE: If a Cloudlet has finished, then it won't be processed.
721 // So, if ack is required, this method sends back a result.
722 // If ack is not required, this method don't send back a result.
723 // Hence, this might cause CloudSim to be hanged since waiting
724 // for this Cloudlet back.
725 if (ack) {
726 int[] data = new int[3];
727 data[0] = getId();
728 data[1] = cl.getCloudletId();
729 data[2] = CloudSimTags.FALSE;
730
731 // unique tag = operation tag
732 int tag = CloudSimTags.CLOUDLET_SUBMIT_ACK;
733 sendNow(cl.getUserId(), tag, data);
734 }
735
736 sendNow(cl.getUserId(), CloudSimTags.CLOUDLET_RETURN, cl);
737
738 return;
739 }
740
741 // process this Cloudlet to this CloudResource
742 cl.setResourceParameter(getId(), getCharacteristics().getCostPerSecond(), getCharacteristics().getCostPerBw());
743
744 int userId = cl.getUserId();
745 int vmId = cl.getVmId();
746
747 double fileTransferTime = predictFileTransferTime(cl.getRequiredFiles()); //time to transfer the files
748
749 Host host = getVmAllocationPolicy().getHost(vmId, userId);
750 Vm vm = host.getVm(vmId, userId);
751 CloudletScheduler scheduler = vm.getCloudletScheduler();
752 double estimatedFinishTime = scheduler.cloudletSubmit(cl,fileTransferTime);
753
754 //if (estimatedFinishTime > 0.0 && estimatedFinishTime < getSchedulingInterval()) { //if this cloudlet is in the exec queue
755 if (estimatedFinishTime > 0.0) { //if this cloudlet is in the exec queue
756 //double estimatedFinishTime = (cl.getCloudletTotalLength()/(capacity*cl.getPesNumber())); //time to process the cloudlet
757 //Log.printLine(estimatedFinishTime+"="+gl.getCloudletLength()+"/("+capacity+"*"+gl.getNumPE()+")");
758 estimatedFinishTime += fileTransferTime;
759 //estimatedFinishTime += CloudSim.clock();
760 //Log.printLine(CloudSim.clock()+": Next event scheduled to +"+estimatedFinishTime);
761 send(getId(), estimatedFinishTime, CloudSimTags.VM_DATACENTER_EVENT);
762 }
763
764 }
765 catch (ClassCastException c) {
766 Log.printLine(getName() + ".processCloudletSubmit(): " + "ClassCastException error.");
767 c.printStackTrace();
768 }
769 catch (Exception e) {
770 Log.printLine(getName() + ".processCloudletSubmit(): " + "Exception error.");
771 e.printStackTrace();
772 }
773
774 checkCloudletCompletion();
775 }
776
777 /**预测文件传输时间
778 * Predict file transfer time.
779 *
780 * @param requiredFiles the required files
781 *
782 * @return the double
783 */
784 protected double predictFileTransferTime(List<String> requiredFiles) {
785 double time = 0.0;
786
787 Iterator<String> iter = requiredFiles.iterator();//【迭代器的使用】
788 while (iter.hasNext()) {
789 String fileName = iter.next();
790 for (int i = 0; i < getStorageList().size(); i++) {
791 Storage tempStorage = getStorageList().get(i);
792 File tempFile = tempStorage.getFile(fileName);
793 if (tempFile != null) {
794 time += tempFile.getSize() / tempStorage.getMaxTransferRate();
795 break;
796 }
797 }
798 }
799 return time;
800 }
801
802 /**处理云任务重启请求
803 * Processes a Cloudlet resume request.
804 *
805 * @param cloudletId resuming cloudlet ID
806 * @param userId ID of the cloudlet's owner
807 * @param ack $true if an ack is requested after operation
808 * @param vmId the vm id
809 *
810 * @pre $none
811 * @post $none
812 */
813 protected void processCloudletResume(int cloudletId, int userId, int vmId, boolean ack) {
814 double eventTime = getVmAllocationPolicy().getHost(vmId,userId).getVm(userId, vmId).getCloudletScheduler().cloudletResume(cloudletId);
815
816 boolean status = false;
817 if (eventTime > 0.0) { //if this cloudlet is in the exec queue
818 status = true;
819 if (eventTime > CloudSim.clock()) {
820 schedule(getId(), eventTime, CloudSimTags.VM_DATACENTER_EVENT);
821 }
822 }
823
824 if (ack) {
825 int[] data = new int[3];
826 data[0] = getId();
827 data[1] = cloudletId;
828 if (status) {
829 data[2] = CloudSimTags.TRUE;
830 } else {
831 data[2] = CloudSimTags.FALSE;
832 }
833 sendNow(userId, CloudSimTags.CLOUDLET_RESUME_ACK, data);
834 }
835 }
836
837 /**处理云任务暂停请求
838 * Processes a Cloudlet pause request.
839 *
840 * @param cloudletId resuming cloudlet ID
841 * @param userId ID of the cloudlet's owner
842 * @param ack $true if an ack is requested after operation
843 * @param vmId the vm id
844 *
845 * @pre $none
846 * @post $none
847 */
848 protected void processCloudletPause(int cloudletId, int userId, int vmId, boolean ack) {
849 boolean status = getVmAllocationPolicy().getHost(vmId,userId).getVm(userId, vmId).getCloudletScheduler().cloudletPause(cloudletId);
850
851 if (ack) {
852 int[] data = new int[3];
853 data[0] = getId();
854 data[1] = cloudletId;
855 if (status) {
856 data[2] = CloudSimTags.TRUE;
857 } else {
858 data[2] = CloudSimTags.FALSE;
859 }
860 sendNow(userId, CloudSimTags.CLOUDLET_PAUSE_ACK, data);
861 }
862 }
863
864 /**处理云任务取消请求
865 * Processes a Cloudlet cancel request.
866 *
867 * @param cloudletId resuming cloudlet ID
868 * @param userId ID of the cloudlet's owner
869 * @param vmId the vm id
870 *
871 * @pre $none
872 * @post $none
873 */
874 protected void processCloudletCancel(int cloudletId, int userId, int vmId) {
875 Cloudlet cl = getVmAllocationPolicy().getHost(vmId,userId).getVm(userId, vmId).getCloudletScheduler().cloudletCancel(cloudletId);
876
877 sendNow(userId, CloudSimTags.CLOUDLET_CANCEL, cl);
878 }
879
880 /**更新处理云任务
881 * Updates processing of each cloudlet running in this PowerDatacenter. It is necessary because
882 * Hosts and VirtualMachines are simple objects, not entities. So, they don't receive events
883 * and updating cloudlets inside them must be called from the outside.
884 *
885 * @pre $none
886 * @post $none
887 */
888 protected void updateCloudletProcessing() {
889 //Log.printLine(CloudSim.clock()+": PowerDatacenter #"+this.get_id()+": updating cloudlet processing.......................................");
890 //if some time passed since last processing
891 if (CloudSim.clock() > this.getLastProcessTime()) {
892 List<? extends Host> list = getVmAllocationPolicy().getHostList();
893 double smallerTime = Double.MAX_VALUE;
894 //for each host...
895 for (int i = 0; i < list.size(); i++) {
896 Host host = list.get(i);
897 double time = host.updateVmsProcessing(CloudSim.clock());//inform VMs to update processing
898 //what time do we expect that the next cloudlet will finish?
899 if (time < smallerTime) {
900 smallerTime = time;
901 }
902 }
903 //schedules an event to the next time, if valid
904 //if (smallerTime > CloudSim.clock() + 0.01 && smallerTime != Double.MAX_VALUE && smallerTime < getSchedulingInterval()) {
905 if (smallerTime > CloudSim.clock() + 0.01 && smallerTime != Double.MAX_VALUE) {
906 schedule(getId(), (smallerTime - CloudSim.clock()), CloudSimTags.VM_DATACENTER_EVENT);
907 }
908 setLastProcessTime(CloudSim.clock());
909 }
910 }
911
912 /**证实 如果一些任务已经完成
913 * Verifies if some cloudlet inside this PowerDatacenter already finished.
914 * If yes, send it to the User/Broker
915 *
916 * @pre $none
917 * @post $none
918 */
919 protected void checkCloudletCompletion() {
920 List<? extends Host> list = getVmAllocationPolicy().getHostList();
921 for (int i = 0; i < list.size(); i++) {
922 Host host = list.get(i);
923 for (Vm vm : host.getVmList()) {
924 while (vm.getCloudletScheduler().isFinishedCloudlets()){
925 Cloudlet cl = vm.getCloudletScheduler().getNextFinishedCloudlet();
926 if (cl != null) {
927 sendNow(cl.getUserId(), CloudSimTags.CLOUDLET_RETURN, cl);
928 }
929 }
930 }
931 }
932 }
933
934 /**实验开始前增加一个文件到资源存储 file ???
935 * Adds a file into the resource's storage before the experiment starts.
936 * If the file is a master file, then it will be registered to the RC when
937 * the experiment begins.
938 *
939 * @param file a DataCloud file
940 *
941 * @return a tag number denoting whether this operation is a success or not
942 *
943 * @see CloudSim.datagrid.DataCloudTags#FILE_ADD_SUCCESSFUL
944 * @see CloudSim.datagrid.DataCloudTags#FILE_ADD_ERROR_EMPTY
945 */
946 public int addFile(File file) {
947 if (file == null) {
948 return DataCloudTags.FILE_ADD_ERROR_EMPTY;
949 }
950
951 if (contains(file.getName())) {
952 return DataCloudTags.FILE_ADD_ERROR_EXIST_READ_ONLY;
953 }
954
955 // check storage space first
956 if (getStorageList().size() <= 0) {
957 return DataCloudTags.FILE_ADD_ERROR_STORAGE_FULL;
958 }
959
960 Storage tempStorage = null;
961 int msg = DataCloudTags.FILE_ADD_ERROR_STORAGE_FULL;
962
963 for (int i = 0; i < getStorageList().size(); i++) {
964 tempStorage = getStorageList().get(i);
965 if (tempStorage.getAvailableSpace() >= file.getSize()) {
966 tempStorage.addFile(file);
967 msg = DataCloudTags.FILE_ADD_SUCCESSFUL;
968 break;
969 }
970 }
971
972 return msg;
973 }
974
975 /**核实是否资源拥有给定的文件
976 * Checks whether the resource has the given file.
977 *
978 * @param file a file to be searched
979 *
980 * @return <tt>true</tt> if successful, <tt>false</tt> otherwise
981 */
982 protected boolean contains(File file) {
983 if (file == null) {
984 return false;
985 }
986 return contains( file.getName() );
987 }
988
989 /**
990 * Checks whether the resource has the given file.
991 *
992 * @param fileName a file name to be searched
993 *
994 * @return <tt>true</tt> if successful, <tt>false</tt> otherwise
995 */
996 protected boolean contains(String fileName) {
997 if (fileName == null || fileName.length() == 0) {
998 return false;
999 }
1000
1001 Iterator<Storage> it = getStorageList().iterator();
1002 Storage storage = null;
1003 boolean result = false;
1004
1005 while (it.hasNext()) {
1006 storage = it.next();
1007 if (storage.contains(fileName)) {
1008 result = true;
1009 break;
1010 }
1011 }
1012
1013 return result;
1014 }
1015
1016 /**删除文件
1017 * Deletes the file from the storage. Also, check whether it is
1018 * possible to delete the file from the storage.
1019 *
1020 * @param fileName the name of the file to be deleted
1021 *
1022 * @return the error message as defined in
1023 * {@link CloudSim.datagrid.DataCloudTags}
1024 *
1025 * @see CloudSim.datagrid.DataCloudTags#FILE_DELETE_SUCCESSFUL
1026 * @see CloudSim.datagrid.DataCloudTags#FILE_DELETE_ERROR_ACCESS_DENIED
1027 * @see CloudSim.datagrid.DataCloudTags#FILE_DELETE_ERROR
1028 */
1029 private int deleteFileFromStorage(String fileName) {
1030 Storage tempStorage = null;
1031 File tempFile = null;
1032 int msg = DataCloudTags.FILE_DELETE_ERROR;
1033
1034 for (int i = 0; i < getStorageList().size(); i++) {
1035 tempStorage = getStorageList().get(i);
1036 tempFile = tempStorage.getFile(fileName);
1037 tempStorage.deleteFile(fileName, tempFile);
1038 msg = DataCloudTags.FILE_DELETE_SUCCESSFUL;
1039 } // end for
1040
1041 return msg;
1042 }
1043
1044 /**打印费用
1045 * Prints the debts.
1046 */
1047 public void printDebts() {
1048 Log.printLine("*****PowerDatacenter: "+this.getName()+"*****");
1049 Log.printLine("User id\t\tDebt");
1050
1051 Set<Integer> keys = getDebts().keySet();
1052 Iterator<Integer> iter = keys.iterator();
1053 DecimalFormat df = new DecimalFormat("#.##");
1054 while (iter.hasNext()) {
1055 int key = iter.next();
1056 double value = getDebts().get(key);
1057 Log.printLine(key+"\t\t"+df.format(value));
1058 }
1059 Log.printLine("**********************************");
1060 }
1061
1062 /* (non-Javadoc)
1063 * @see cloudsim.core.SimEntity#shutdownEntity()
1064 */
1065 @Override
1066 public void shutdownEntity() {
1067 Log.printLine(getName() + " is shutting down...");
1068 }
1069
1070 /* (non-Javadoc)
1071 * @see cloudsim.core.SimEntity#startEntity()
1072 */
1073 @Override
1074 public void startEntity() {
1075 Log.printLine(getName() + " is starting...");
1076 // this resource should register to regional GIS.
1077 // However, if not specified, then register to system GIS (the
1078 // default CloudInformationService) entity.
1079 int gisID = CloudSim.getEntityId(regionalCisName);
1080 if (gisID == -1) {
1081 gisID = CloudSim.getCloudInfoServiceEntityId();
1082 }
1083
1084 // send the registration to GIS
1085 sendNow(gisID, CloudSimTags.REGISTER_RESOURCE, getId());
1086 // Below method is for a child class to override
1087 registerOtherEntity();
1088 }
1089
1090 /**获取主机列表
1091 * Gets the host list.
1092 *
1093 * @return the host list
1094 */
1095 @SuppressWarnings("unchecked")
1096 public <T extends Host> List<T> getHostList() {
1097 return (List<T>) getCharacteristics().getHostList();
1098 }
1099
1100 /**获取数据中心特征
1101 * Gets the characteristics.
1102 *
1103 * @return the characteristics
1104 */
1105 protected DatacenterCharacteristics getCharacteristics() {
1106 return characteristics;
1107 }
1108
1109 /**设置数据中心特征
1110 * Sets the characteristics.
1111 *
1112 * @param characteristics the new characteristics
1113 */
1114 protected void setCharacteristics(DatacenterCharacteristics characteristics) {
1115 this.characteristics = characteristics;
1116 }
1117
1118 /**获取局部CIS名
1119 * Gets the regional cis name.
1120 *
1121 * @return the regional cis name
1122 */
1123 protected String getRegionalCisName() {
1124 return regionalCisName;
1125 }
1126
1127 /**
1128 * Sets the regional cis name.
1129 *
1130 * @param regionalCisName the new regional cis name
1131 */
1132 protected void setRegionalCisName(String regionalCisName) {
1133 this.regionalCisName = regionalCisName;
1134 }
1135
1136 /**虚拟机分配协议
1137 * Gets the vm allocation policy.
1138 *
1139 * @return the vm allocation policy
1140 */
1141 public VmAllocationPolicy getVmAllocationPolicy() {
1142 return vmAllocationPolicy;
1143 }
1144
1145 /**
1146 * Sets the vm allocation policy.
1147 *
1148 * @param vmAllocationPolicy the new vm allocation policy
1149 */
1150 protected void setVmAllocationPolicy(VmAllocationPolicy vmAllocationPolicy) {
1151 this.vmAllocationPolicy = vmAllocationPolicy;
1152 }
1153
1154 /**
1155 * Gets the last process time.
1156 *
1157 * @return the last process time
1158 */
1159 protected double getLastProcessTime() {
1160 return lastProcessTime;
1161 }
1162
1163 /**
1164 * Sets the last process time.
1165 *
1166 * @param lastProcessTime the new last process time
1167 */
1168 protected void setLastProcessTime(double lastProcessTime) {
1169 this.lastProcessTime = lastProcessTime;
1170 }
1171
1172 /**费用
1173 * Gets the debts.
1174 *
1175 * @return the debts
1176 */
1177 protected Map<Integer, Double> getDebts() {
1178 return debts;
1179 }
1180
1181 /**
1182 * Sets the debts.
1183 *
1184 * @param debts the debts
1185 */
1186 protected void setDebts(Map<Integer, Double> debts) {
1187 this.debts = debts;
1188 }
1189
1190 /**存储列表
1191 * Gets the storage list.
1192 *
1193 * @return the storage list
1194 */
1195 protected List<Storage> getStorageList() {
1196 return storageList;
1197 }
1198
1199 /**
1200 * Sets the storage list.
1201 *
1202 * @param storageList the new storage list
1203 */
1204 protected void setStorageList(List<Storage> storageList) {
1205 this.storageList = storageList;
1206 }
1207
1208 /**虚拟机列表
1209 * Gets the vm list.
1210 *
1211 * @return the vm list
1212 */
1213 @SuppressWarnings("unchecked")
1214 public <T extends Vm> List<T> getVmList() {
1215 return (List<T>) vmList;
1216 }
1217
1218 /**
1219 * Sets the vm list.
1220 *
1221 * @param vmList the new vm list
1222 */
1223 protected <T extends Vm> void setVmList(List<T> vmList) {
1224 this.vmList = vmList;
1225 }
1226
1227 /**调度间隔
1228 * Gets the scheduling interval.
1229 *
1230 * @return the scheduling interval
1231 */
1232 protected double getSchedulingInterval() {
1233 return schedulingInterval;
1234 }
1235
1236 /**
1237 * Sets the scheduling interval.
1238 *
1239 * @param schedulingInterval the new scheduling interval
1240 */
1241 protected void setSchedulingInterval(double schedulingInterval) {
1242 this.schedulingInterval = schedulingInterval;
1243 }
1244
1245 }