[haizea-commit] r764 - in branches/1.1/src/haizea: core core/scheduler pluggable/policies

haizea-commit at mailman.cs.uchicago.edu haizea-commit at mailman.cs.uchicago.edu
Thu Jan 14 23:20:03 CST 2010


Author: borja
Date: 2010-01-14 23:20:03 -0600 (Thu, 14 Jan 2010)
New Revision: 764

Modified:
   branches/1.1/src/haizea/core/leases.py
   branches/1.1/src/haizea/core/scheduler/lease_scheduler.py
   branches/1.1/src/haizea/core/scheduler/slottable.py
   branches/1.1/src/haizea/core/scheduler/vm_scheduler.py
   branches/1.1/src/haizea/pluggable/policies/preemption.py
Log:
- Optimized rescheduling of deadline leases
- Allow leases to be preempted at any point, not just at the "last vm"
- Enable rescheduling of deadline leases when a lease ends prematurely


Modified: branches/1.1/src/haizea/core/leases.py
===================================================================
--- branches/1.1/src/haizea/core/leases.py	2010-01-14 04:09:27 UTC (rev 763)
+++ branches/1.1/src/haizea/core/leases.py	2010-01-15 05:20:03 UTC (rev 764)
@@ -474,7 +474,10 @@
         """Returns the last VM reservation for this lease.
                         
         """            
-        return self.vm_rrs[-1]    
+        if len(self.vm_rrs) > 0:
+            return self.vm_rrs[-1]
+        else:
+            return None
     
     def get_vmrr_at(self, time):
         """...
@@ -509,6 +512,30 @@
         vmrr = self.get_last_vmrr()
         return vmrr.end
     
+    def get_accumulated_duration_at(self, time):
+        """Returns the amount of time required to fulfil the entire
+        requested duration of the lease at a given time.
+                        
+        """
+        t = TimeDelta(0)
+        for vmrr in self.vm_rrs:
+            if time >= vmrr.end:
+                t += vmrr.end - vmrr.start
+            elif time >= vmrr.start and time < vmrr.end:
+                t += time -vmrr.start
+                break
+            else:
+                break
+        return t
+
+    
+    def get_remaining_duration_at(self, time):
+        """Returns the amount of time required to fulfil the entire
+        requested duration of the lease at a given time.
+                        
+        """
+        return self.duration.requested - self.get_accumulated_duration_at(time)    
+    
     def append_vmrr(self, vmrr):
         """Adds a VM resource reservation to the lease.
         
@@ -1038,7 +1065,7 @@
         known duration of the lease.
               
         ONLY for simulations.
-        """           
+        """
         return self.known - self.accumulated
             
     def __repr__(self):

Modified: branches/1.1/src/haizea/core/scheduler/lease_scheduler.py
===================================================================
--- branches/1.1/src/haizea/core/scheduler/lease_scheduler.py	2010-01-14 04:09:27 UTC (rev 763)
+++ branches/1.1/src/haizea/core/scheduler/lease_scheduler.py	2010-01-15 05:20:03 UTC (rev 764)
@@ -33,6 +33,7 @@
 from haizea.common.utils import round_datetime, get_config, get_clock, get_policy, get_persistence
 from haizea.core.leases import Lease
 from haizea.core.scheduler import RescheduleLeaseException, NormalEndLeaseException, InconsistentLeaseStateError, EnactmentError, UnrecoverableError, NotSchedulableException, EarliestStartingTime
+from haizea.core.scheduler.vm_scheduler import VMResourceReservation
 from haizea.core.scheduler.slottable import ResourceReservation
 from operator import attrgetter
 
@@ -432,17 +433,18 @@
             self._handle_end_rr(vmrr)
             # TODO: Exception handling
             self.vm_scheduler._handle_unscheduled_end_vm(lease, vmrr)
-            self._handle_end_lease(lease)
-            get_persistence().persist_lease(lease)
             
             # We need to reevaluate the schedule to see if there are any 
             # leases scheduled in the future that could be rescheduled
             # to start earlier
             nexttime = get_clock().get_next_schedulable_time()
-            self.reevaluate_schedule(nexttime)
+            self.reevaluate_schedule(nexttime, lease)
 
+            self._handle_end_lease(lease)
+            get_persistence().persist_lease(lease)
 
-    def reevaluate_schedule(self, nexttime):
+
+    def reevaluate_schedule(self, nexttime, ending_lease):
         """Reevaluates the schedule.
         
         This method can be called whenever resources are freed up
@@ -461,9 +463,9 @@
         ## BEGIN NOT-FIT-FOR-PRODUCTION CODE
         ## This is only necessary because we're currently using the best-effort
         ## scheduling algorithm for many of the deadline leases
-        future = [l for l in future if l.get_type() == Lease.BEST_EFFORT]
+        future_best_effort = [l for l in future if l.get_type() == Lease.BEST_EFFORT]
         ## END NOT-FIT-FOR-PRODUCTION CODE
-        for l in future:
+        for l in future_best_effort:
             # We can only reschedule leases in the following four states
             if l.get_state() in (Lease.STATE_PREPARING, Lease.STATE_READY, Lease.STATE_SCHEDULED, Lease.STATE_SUSPENDED_SCHEDULED):
                 # For each reschedulable lease already scheduled in the
@@ -488,7 +490,52 @@
                 # scenario is that it simply replicates the previous schedule)
                 self.__schedule_lease(l, nexttime)
 
+        future_vmrrs = self.slottable.get_reservations_on_or_after(nexttime)
+        future_vmrrs = [rr for rr in future_vmrrs 
+                        if isinstance(rr, VMResourceReservation) 
+                        and rr.lease.get_type() == Lease.DEADLINE
+                        and rr.lease.get_state() in (Lease.STATE_SCHEDULED, Lease.STATE_READY, Lease.STATE_SUSPENDED_SCHEDULED)]
 
+        leases = list(set([future_vmrr.lease for future_vmrr in future_vmrrs]))
+
+        leases.sort(key= lambda l: (l.deadline - nexttime) / l.get_remaining_duration_at(nexttime))
+        if len(leases) > 0:
+            self.logger.debug("Rescheduling future deadline leases")
+            self.slottable.save(leases)
+            feasible = True
+            node_ids = self.slottable.nodes.keys()
+            earliest = {}
+            for node in node_ids:
+                earliest[node] = EarliestStartingTime(nexttime, EarliestStartingTime.EARLIEST_NOPREPARATION)
+                        
+            orig_vmrrs = dict([(l,[rr for rr in future_vmrrs if rr.lease == l]) for l in leases])            
+            dirtynodes = ending_lease.get_last_vmrr().resources_in_pnode.keys()
+
+            dirtynodes, cleanleases = self.vm_scheduler.find_dirty_nodes(leases, dirtynodes, orig_vmrrs)
+
+            for vmrr in [vmrr2 for vmrr2 in future_vmrrs if vmrr2.lease not in cleanleases]:
+                self.vm_scheduler.cancel_vm(vmrr)
+    
+            dirtyleases = [l for l in leases if l not in cleanleases]
+
+            try:
+                (scheduled, add_vmrrs, dirtytime) = self.vm_scheduler.reschedule_deadline_leases(dirtyleases, orig_vmrrs, nexttime, earliest, nexttime, dirtytime=None)
+            except NotSchedulableException:
+                self.logger.debug("Future leases could not be rescheduled, undoing changes.")
+                feasible = False
+            
+            if feasible:
+                for l in [l2 for l2 in orig_vmrrs if l2 in scheduled]:
+                    for vmrr in orig_vmrrs[l]:
+                        vmrr.lease.remove_vmrr(vmrr)
+                    
+                for lease2, vmrr in add_vmrrs.items():
+                    lease2.append_vmrr(vmrr)            
+            else:
+                self.slottable.restore()
+
+
+
     def is_queue_empty(self):
         """Return True is the queue is empty, False otherwise"""
         return self.queue.is_empty()
@@ -746,13 +793,7 @@
         lease.print_contents()
                 
     def __preempt_leases_deadline(self, lease, vmrr, preempted_leases, preemption_time, nexttime):
-        orig_vmrrs = dict([(l.id,l.vm_rrs[:]) for l in preempted_leases])
-        orig_vmrrs_data = {}
-        for orig_vmrr in orig_vmrrs.values():
-            for vmrr2 in orig_vmrr:
-                orig_vmrrs_data[vmrr2] = (vmrr2.start, vmrr2.end, vmrr2.prematureend, vmrr2.pre_rrs[:], vmrr2.post_rrs[:])
-
-        self.slottable.push()        
+        self.slottable.save(preempted_leases)  
         
         # Pre-VM RRs (if any)
         for rr in vmrr.pre_rrs:
@@ -770,7 +811,7 @@
         new_state = {}
         durs = {}
         for lease_to_preempt in preempted_leases:
-            preempt_vmrr = lease_to_preempt.get_last_vmrr()
+            preempt_vmrr = lease_to_preempt.get_vmrr_at(preemption_time)
             
             susptype = get_config().get("suspension")
             
@@ -779,7 +820,7 @@
             if susptype == constants.SUSPENSION_NONE:
                 cancel = True
             else:
-                if preempt_vmrr.state == ResourceReservation.STATE_SCHEDULED and preempt_vmrr.start >= preemption_time:
+                if preempt_vmrr == None:
                     self.logger.debug("Lease was set to start in the middle of the preempting lease.")
                     cancel = True
                 else:
@@ -788,29 +829,31 @@
                     if not can_suspend:
                         self.logger.debug("Suspending the lease does not meet scheduling threshold.")
                         cancel = True
-                    else:
-                        orig_end = preempt_vmrr.end
-                        orig_prematureend = preempt_vmrr.prematureend
-
-                        self.vm_scheduler.preempt_vm(preempt_vmrr, preemption_time)
                         
-                        durs[lease_to_preempt] = orig_end - preempt_vmrr.end                  
-                        
-            if cancel:
-                self.preparation_scheduler.cancel_preparation(lease_to_preempt)
-                durs[lease_to_preempt] = preempt_vmrr.end - preempt_vmrr.start
+            after_vmrrs = lease_to_preempt.get_vmrr_after(preemption_time)
 
-                active_vmrrs = lease_to_preempt.get_active_vmrrs(preemption_time)
-                                
-                lease_to_preempt.remove_vmrr(preempt_vmrr)
-                self.vm_scheduler.cancel_vm(preempt_vmrr)       
+            if not cancel:
+                # Preempting
+                durs[lease_to_preempt] = lease_to_preempt.get_remaining_duration_at(preemption_time)             
+                self.vm_scheduler.preempt_vm(preempt_vmrr, preemption_time)
+                susp_time = preempt_vmrr.post_rrs[-1].end - preempt_vmrr.post_rrs[0].start
+                durs[lease_to_preempt] += susp_time
+                                        
+            else:                                
                 cancelled.append(lease_to_preempt.id)
-                
-                lease_state = lease_to_preempt.get_state()
-                if preempt_vmrr in active_vmrrs:
-                    # The VMRR we're preempting is the active one
-                    new_state[lease_to_preempt] = Lease.STATE_READY
+
+                if preempt_vmrr != None:
+                    durs[lease_to_preempt] = lease_to_preempt.get_remaining_duration_at(preempt_vmrr.start)             
+                    
+                    if preempt_vmrr.state == ResourceReservation.STATE_ACTIVE:
+                        # The VMRR we're preempting is the active one
+                        new_state[lease_to_preempt] = Lease.STATE_READY
+
+                    lease_to_preempt.remove_vmrr(preempt_vmrr)
+                    self.vm_scheduler.cancel_vm(preempt_vmrr)
                 else:
+                    durs[lease_to_preempt] = lease_to_preempt.get_remaining_duration_at(preemption_time)             
+                    lease_state = lease_to_preempt.get_state()
                     if lease_state == Lease.STATE_ACTIVE:
                         # Don't do anything. The lease is active, but not in the VMs
                         # we're preempting.
@@ -821,8 +864,11 @@
                         new_state[lease_to_preempt] = None
                     elif lease_state != Lease.STATE_READY:
                         new_state[lease_to_preempt] = Lease.STATE_READY   
-                
-          
+                        
+            # Cancel future VMs
+            for after_vmrr in after_vmrrs:
+                lease_to_preempt.remove_vmrr(after_vmrr)
+                self.vm_scheduler.cancel_vm(after_vmrr)                   
 
         for lease_to_preempt in preempted_leases:
             dur = durs[lease_to_preempt]
@@ -836,9 +882,14 @@
                 lease.duration.accumulated = lease.duration.requested - dur
                 
                 if lease_to_preempt.id in cancelled:
+                    last_vmrr = lease_to_preempt.get_last_vmrr()
+                    if last_vmrr != None and last_vmrr.is_suspending():
+                        override_state = Lease.STATE_SUSPENDED_PENDING
+                    else:
+                        override_state = None
                     for node in node_ids:
                         earliest[node] = EarliestStartingTime(nexttime, EarliestStartingTime.EARLIEST_NOPREPARATION)                
-                    (new_vmrr, preemptions) = self.vm_scheduler.reschedule_deadline(lease_to_preempt, dur, nexttime, earliest)
+                    (new_vmrr, preemptions) = self.vm_scheduler.reschedule_deadline(lease_to_preempt, dur, nexttime, earliest, override_state)
                 else:
                     for node in node_ids:
                         earliest[node] = EarliestStartingTime(preemption_time, EarliestStartingTime.EARLIEST_NOPREPARATION)                
@@ -867,15 +918,7 @@
                 break
 
         if not feasible:
-            for l in preempted_leases:
-                l.vm_rrs = orig_vmrrs[l.id]
-                for vm_rr in l.vm_rrs:
-                    vm_rr.start = orig_vmrrs_data[vm_rr][0]
-                    vm_rr.end = orig_vmrrs_data[vm_rr][1]
-                    vm_rr.prematureend = orig_vmrrs_data[vm_rr][2]
-                    vm_rr.pre_rrs = orig_vmrrs_data[vm_rr][3]
-                    vm_rr.post_rrs = orig_vmrrs_data[vm_rr][4]
-            self.slottable.pop()
+            self.slottable.restore()
             raise NotSchedulableException, "Unable to preempt leases to make room for lease."
         else:
             # Pre-VM RRs (if any)

Modified: branches/1.1/src/haizea/core/scheduler/slottable.py
===================================================================
--- branches/1.1/src/haizea/core/scheduler/slottable.py	2010-01-14 04:09:27 UTC (rev 763)
+++ branches/1.1/src/haizea/core/scheduler/slottable.py	2010-01-15 05:20:03 UTC (rev 764)
@@ -569,7 +569,7 @@
         
         @param rr: Resource reservation
         @type rr: L{ResourceReservation}
-        """        
+        """
         startitem = KeyValueWrapper(rr.start, rr)
         enditem = KeyValueWrapper(rr.end, rr)
         bisect.insort(self.reservations_by_start, startitem)
@@ -855,13 +855,30 @@
         from haizea.core.scheduler.vm_scheduler import VMResourceReservation
         return [i.value for i in self.reservations_by_end if isinstance(i.value, VMResourceReservation) and i.value.prematureend == time]
 
-    def push(self):
+    def save(self, leases = []):
         self.reservations_by_start2 = self.reservations_by_start[:]
         self.reservations_by_end2 = self.reservations_by_end[:]
+        
+        self.orig_vmrrs = dict([(l,l.vm_rrs[:]) for l in leases])
+        self.orig_vmrrs_data = {}
+        for orig_vmrr in self.orig_vmrrs.values():
+            for vmrr in orig_vmrr:
+                self.orig_vmrrs_data[vmrr] = (vmrr.start, vmrr.end, vmrr.prematureend, vmrr.pre_rrs[:], vmrr.post_rrs[:])
 
-    def pop(self):
+
+    def restore(self):
         self.reservations_by_start = self.reservations_by_start2
         self.reservations_by_end = self.reservations_by_end2
+        
+        for l in self.orig_vmrrs:
+            l.vm_rrs = self.orig_vmrrs[l]
+            for vm_rr in l.vm_rrs:
+                vm_rr.start = self.orig_vmrrs_data[vm_rr][0]
+                vm_rr.end = self.orig_vmrrs_data[vm_rr][1]
+                vm_rr.prematureend = self.orig_vmrrs_data[vm_rr][2]
+                vm_rr.pre_rrs = self.orig_vmrrs_data[vm_rr][3]
+                vm_rr.post_rrs = self.orig_vmrrs_data[vm_rr][4]
+   
         self.__dirty()
 
 

Modified: branches/1.1/src/haizea/core/scheduler/vm_scheduler.py
===================================================================
--- branches/1.1/src/haizea/core/scheduler/vm_scheduler.py	2010-01-14 04:09:27 UTC (rev 763)
+++ branches/1.1/src/haizea/core/scheduler/vm_scheduler.py	2010-01-15 05:20:03 UTC (rev 764)
@@ -249,11 +249,8 @@
         Arguments:
         vmrr -- VM RR to be preempted
         t -- Time by which the VM must be preempted
-        """                     
-        # TODO: Make more general, should determine vmrr based on current time
-        # This won't currently break, though, since the calling function 
-        # operates on the last VM RR.
-        vmrr = lease.get_last_vmrr()
+        """
+        vmrr = lease.get_vmrr_at(t)
         time_until_suspend = t - vmrr.start
         min_duration = self.__compute_scheduling_threshold(lease)
         can_suspend = time_until_suspend >= min_duration        
@@ -618,8 +615,10 @@
 
     def __schedule_deadline(self, lease, duration, nexttime, earliest, override_state):   
         
+        earliest_time = nexttime
         for n in earliest:
             earliest[n].time = max(lease.start.requested, earliest[n].time)
+            earliest_time = max(earliest_time, earliest[n].time)
 
         slack = (lease.deadline - lease.start.requested) / lease.duration.requested
         if slack <= 2.0:
@@ -641,59 +640,116 @@
         if vmrr == None or vmrr.end - vmrr.start != duration or vmrr.end > lease.deadline or len(preemptions)>0:
             self.logger.debug("Lease #%i cannot be scheduled before deadline using best-effort." % lease.id)
             
-            self.slottable.push()
-            future_vmrrs = self.slottable.get_reservations_on_or_after(min([e.time for e in earliest.values()]))
+            self.slottable.save()
+            
+            dirtynodes = set()
+            dirtytime = earliest_time
+
+            future_vmrrs = self.slottable.get_reservations_on_or_after(earliest_time)
             future_vmrrs = [rr for rr in future_vmrrs 
                             if isinstance(rr, VMResourceReservation) 
-                            and rr.state==ResourceReservation.STATE_SCHEDULED
-                            and not rr.is_resuming()
-                            and not rr.is_suspending()]
+                            and rr.lease.get_state() in (Lease.STATE_SCHEDULED, Lease.STATE_READY, Lease.STATE_SUSPENDED_SCHEDULED)]
             
-            for vmrr in future_vmrrs:
-                for rr in vmrr.pre_rrs:
-                    if rr.state == ResourceReservation.STATE_SCHEDULED:
-                         self.slottable.remove_reservation(rr)
-        
-                for rr in vmrr.post_rrs:
-                    self.slottable.remove_reservation(rr)
-    
-                self.slottable.remove_reservation(vmrr)            
+            for future_vmrr in future_vmrrs:
+                self.cancel_vm(future_vmrr)
             
-            leases = [vmrr.lease for vmrr in future_vmrrs]
+            leases = list(set([future_vmrr.lease for future_vmrr in future_vmrrs]))
+            
+            orig_vmrrs = dict([(l,[rr for rr in future_vmrrs if rr.lease == l]) for l in leases])
+            
             leases.append(lease)
-            leases.sort(key= lambda l: (l.deadline - l.start.requested) / l.duration.requested)
+            leases.sort(key= lambda l: (l.deadline - earliest_time) / l.get_remaining_duration_at(nexttime))
 
             new_vmrrs = {}
 
             self.logger.debug("Attempting to reschedule leases %s" % [l.id for l in leases])
 
+            # First pass
+            scheduled = set()
             for lease2 in leases:
                 for n in earliest:
                     earliest[n].time = max(lease2.start.requested, nexttime)                    
                 self.logger.debug("Rescheduling lease %s" % lease2.id)
-                vmrr, preemptions = self.__schedule_asap(lease2, lease2.duration.get_remaining_duration(), nexttime, earliest, allow_in_future = True)
-                if vmrr.end - vmrr.start != lease2.duration.requested or vmrr.end > lease2.deadline or len(preemptions) != 0:
+                dur = lease2.get_remaining_duration_at(nexttime)
+                vmrr, preemptions = self.__schedule_asap(lease2, dur, nexttime, earliest, allow_in_future = True)
+                if vmrr.end - vmrr.start != dur or vmrr.end > lease2.deadline or len(preemptions) != 0:
                     self.logger.debug("Lease %s could not be rescheduled, undoing changes." % lease2.id)
-                    self.slottable.pop()
+                    self.slottable.restore()
 
                     raise NotSchedulableException, "Could not schedule before deadline without making other leases miss deadline"
                     
+                dirtytime = max(vmrr.end, dirtytime)
+                dirtynodes.update(vmrr.resources_in_pnode.keys())
+                    
                 for rr in vmrr.pre_rrs:
                     self.slottable.add_reservation(rr)                
                 self.slottable.add_reservation(vmrr)
                 for rr in vmrr.post_rrs:
                     self.slottable.add_reservation(rr)                    
+                scheduled.add(lease2)
                 if lease2 == lease:
                     return_vmrr = vmrr
+                    break
                 else:
                     new_vmrrs[lease2] = vmrr
-                    
-            for vmrr in future_vmrrs:
-                vmrr.lease.remove_vmrr(vmrr)
+            
+            # We've scheduled the lease. Now we try to schedule the rest of the leases but,
+            # since now we know the nodes the new lease is in, we can do a few optimizations
+            
+            # Restore the leases in nodes we haven't used, and that would not be
+            # affected by the new lease. We need to find what this set of nodes is.
+            
+            to_schedule = [l for l in leases if l not in scheduled]
+            dirtynodes, cleanleases = self.find_dirty_nodes(to_schedule, dirtynodes, orig_vmrrs)
+            
+            
+            print "Ignoring %i nodes" % (len(set(self.slottable.nodes.keys()) - dirtynodes) - 1)
+
+            # Restore the leases
+            restored_leases = set()
+            for l in leases:
+                if l in cleanleases:
+                    # Restore
+                    for l_vmrr in orig_vmrrs[l]:
+                        for rr in l_vmrr.pre_rrs:
+                            self.slottable.add_reservation(rr)                
+                        self.slottable.add_reservation(l_vmrr)
+                        for rr in l_vmrr.post_rrs:
+                            self.slottable.add_reservation(rr)   
+                        scheduled.add(l)
+                        restored_leases.add(l)
+                            
+            to_schedule = [l for l in leases if l not in scheduled]
+            try:
+                (more_scheduled, add_vmrrs, dirtytime) = self.reschedule_deadline_leases(to_schedule, orig_vmrrs, earliest_time, earliest, nexttime, dirtytime)
+                scheduled.update(more_scheduled)
+                new_vmrrs.update(add_vmrrs)
+            except NotSchedulableException:
+                self.logger.debug("Lease %s could not be rescheduled, undoing changes." % l.id)
+                self.slottable.restore()
+                raise
+                                
+            for l in leases:
+                if l not in scheduled:
+                    for l_vmrr in orig_vmrrs[l]:
+                        for rr in l_vmrr.pre_rrs:
+                            self.slottable.add_reservation(rr)                
+                        self.slottable.add_reservation(l_vmrr)
+                        for rr in l_vmrr.post_rrs:
+                            self.slottable.add_reservation(rr)   
+                        restored_leases.add(l)
+    
+            print "Skipped re-scheduling %i leases (out of %i)" % (len(restored_leases), len(leases))
+            
+            for l in [l2 for l2 in orig_vmrrs if l2 in scheduled - restored_leases]:
+                for vmrr in orig_vmrrs[l]:
+                    vmrr.lease.remove_vmrr(vmrr)
                 
             for lease2, vmrr in new_vmrrs.items():
                 lease2.append_vmrr(vmrr)
                     
+            # Remove from slottable, because lease_scheduler is the one that actually
+            # adds the RRs
             for rr in return_vmrr.pre_rrs:
                 self.slottable.remove_reservation(rr)                
             self.slottable.remove_reservation(return_vmrr)
@@ -704,6 +760,61 @@
         else:
             return vmrr, preemptions
 
+
+    def find_dirty_nodes(self, to_schedule, dirtynodes, orig_vmrrs):
+        dirtynodes = set(dirtynodes)
+        done = False
+        while not done:
+            stable = True
+            cleanleases = set()            
+            for l in to_schedule:
+                pnodes = set()
+                for l_vmrr in orig_vmrrs[l]:
+                    pnodes.update(l_vmrr.resources_in_pnode.keys())
+                in_dirty = dirtynodes & pnodes
+                in_clean = pnodes - dirtynodes
+                if len(in_dirty) > 0 and len(in_clean) > 0:
+                    stable = False
+                    dirtynodes.update(in_clean)
+                if len(in_clean) > 0 and len(in_dirty) == 0:
+                    cleanleases.add(l)
+            if stable == True:
+                done = True
+                
+        return dirtynodes, cleanleases
+
+
+    def reschedule_deadline_leases(self, leases, orig_vmrrs, earliest_time, earliest, nexttime, dirtytime):
+        scheduled = set()
+        new_vmrrs = {}
+        for l in leases:
+            if len(scheduled) < len(leases) and dirtytime != None:
+                min_future_start = min([min([rr.start for rr in lrr]) for l2, lrr in orig_vmrrs.items() if l2 in leases and l2 not in scheduled])
+                if min_future_start > dirtytime:
+                    print "Ignoring after %s" % dirtytime
+                    break
+            for n in earliest:
+                earliest[n].time = max(l.start.requested, nexttime)                    
+            self.logger.debug("Rescheduling lease %s" % l.id)
+            dur = l.get_remaining_duration_at(earliest_time)
+            vmrr, preemptions = self.__schedule_asap(l, dur, nexttime, earliest, allow_in_future = True)
+            if vmrr.end - vmrr.start != dur or vmrr.end > l.deadline or len(preemptions) != 0:
+                raise NotSchedulableException, "Could not schedule before deadline without making other leases miss deadline"
+            
+            if dirtytime != None:
+                dirtytime = max(vmrr.end, dirtytime)
+            
+            for rr in vmrr.pre_rrs:
+                self.slottable.add_reservation(rr)                
+            self.slottable.add_reservation(vmrr)
+            for rr in vmrr.post_rrs:
+                self.slottable.add_reservation(rr)                    
+            new_vmrrs[l] = vmrr
+            scheduled.add(l)                    
+                
+        return scheduled, new_vmrrs, dirtytime
+        
+
     def reschedule_deadline(self, lease, duration, nexttime, earliest, override_state = None):
         for n in earliest:
             earliest[n].time = max(lease.start.requested, earliest[n].time)

Modified: branches/1.1/src/haizea/pluggable/policies/preemption.py
===================================================================
--- branches/1.1/src/haizea/pluggable/policies/preemption.py	2010-01-14 04:09:27 UTC (rev 763)
+++ branches/1.1/src/haizea/pluggable/policies/preemption.py	2010-01-15 05:20:03 UTC (rev 764)
@@ -104,20 +104,8 @@
         preemptor -- Preemptor lease
         preemptee -- Preemptee lease
         time -- Time at which preemption would take place
-        """        
+        """
         if preemptee.get_type() == Lease.DEADLINE:
-            for vmrr in preemptee.vm_rrs:
-                if time >= vmrr.start and time < vmrr.end:
-                    preempt_vmrr = vmrr
-                    break
-            last_vmrr = preemptee.get_last_vmrr()
-            
-            if preempt_vmrr != last_vmrr:
-                return -1
-            
-            if preempt_vmrr.is_suspending():
-                return -1
-            
             # We can only preempt leases in these states
             if not preemptee.get_state() in (Lease.STATE_SCHEDULED, Lease.STATE_READY,
                                              Lease.STATE_ACTIVE, Lease.STATE_SUSPENDING, Lease.STATE_SUSPENDED_PENDING,
@@ -125,7 +113,7 @@
                 return -1
 
             deadline = preemptee.deadline
-            remaining_duration = preempt_vmrr.end - time
+            remaining_duration = preemptee.get_remaining_duration_at(time)
             slack = (deadline - time) / remaining_duration
             delay = preemptee.estimate_suspend_time() + preemptor.duration.requested + preemptee.estimate_resume_time()
             if time + delay + remaining_duration < deadline:



More information about the Haizea-commit mailing list