Пример #1
0
    def is_gte_than_lock_holding_events(self,waiting_event_priority):
        '''
        @param {priority} waiting_event_priority --- 
        
        @returns {bool} --- Returns True if waiting_event_uuid is
        greater than or equal to all other events that are currently
        holding read or read/write locks on data.
        '''

        # check write lock
        if ((self.write_lock_holder is not None) and
            (not gte_priority(waiting_event_priority,self.write_lock_holder.cached_priority))):
            
            return False

        # check read locks
        for read_lock_uuid in self.read_lock_holders:
            read_lock_holder_event_cached_priority = self.read_lock_holders[read_lock_uuid]
            if not gte_priority(
                waiting_event_priority,read_lock_holder_event_cached_priority.cached_priority):
                return False
            
        return True
Пример #2
0
    def try_schedule_read_waiting_event(self,waiting_event):
        '''
        CALLED FROM WITHIN LOCK
        
        Check if can schedule the read event waiting_event

        Should be able to schedule if:

          1) There is not a write lock holder or 

          2) There is a write lock holder that is not currently in two
             phase commit, and has a uuid that is less than our uuid.

              a) check if write lock holder is younger (ie, it should
                 be preempted).
                 
              b) If it is younger and it's not in two phase commit,
                 then go ahead and revoke it.
             
        @returns {bool} --- Returns True if could schedule read
        waiting event.  False if could not.
        '''
        # CASE 1
        if self.write_lock_holder is None:
            self.read_lock_holders[waiting_event.event.uuid] = (
                EventCachedPriorityObj(waiting_event.event,waiting_event.cached_priority))
            waiting_event.unwait(self)
            return True

        # CASE 2
        #   b) If it is younger and it's not in two phase commit, 
        #      then go ahead and revoke it.

        # 2 a --- check if write lock holder is younger (ie, it should be
        #         preempted).
        if gte_priority(
            self.write_lock_holder.cached_priority,waiting_event.cached_priority):
            # do not preempt write lock: it has been around longer
            return False

        # 2 b --- If it is younger and it's not in two phase commit, 
        #         then go ahead and revoke it.
        if not self.write_lock_holder.event.can_backout_and_hold_lock():
            # cannot backout write lock holder
            return False

        # Can backout write lock holder:
        #    1) Actually perform backout of writing event
        #    2) Clean up write lock holder and read lock holder state
        #       associated with write lock
        #    3) Waiting event gets included in read lock holder
        #    4) Unjam waiting event's read queue, which returns value.

        # 1
        self.obj_request_backout_and_release_lock(write_lock_holder.event)
        
        # following code will remove all write lock holders and read
        # lock holders.
        
        # 2
        self.write_lock_holder = None
        self.read_lock_holders = {}
        # 3
        self.read_lock_holders[waiting_event.event.uuid] = (
            EventCachedPriorityObj(waiting_event.event,waiting_event.cached_priority))
        # 4
        waiting_event.unwait(self)
        return True
Пример #3
0
    def acquire_read_lock(self,active_event):
        '''
        DOES NOT ASSUME ALREADY WITHIN LOCK

        @returns {DataWrapper object}

        Algorithms:

           0) If already holds a write lock on the variable, then
              return the dirty value associated with event.
           
           1) If already holds a read lock on variable, returns the value
              immediately.

           2) If does not hold a read lock on variable, then attempts
              to acquire one.  If worked, then return the variable.
              When attempting to acquire read lock:

                 a) Checks if there is any event holding a write lock.
                    If there is not, then adds itself to read lock
                    holder dict.
              
                 b) If there is another event holding a write lock,
                    then check if uuid of the read lock requester is
                    >= uuid of the write lock.  If it is, then try to
                    backout the holder of write lock.

                 c) If cannot backout or have a lesser uuid, then
                    create a waiting event and block while listening
                    to queue.  (same as #3)
              
           3) If did not work, then create a waiting event and a queue
              and block while listening on that queue.

        Blocks until has acquired.
              
        '''
        self._lock()

        # Each event has a priority associated with it.  This priority
        # can change when an event gets promoted to be boosted.  To
        # avoid the read/write conflicts this might cause, at the
        # beginning of acquring read lock, get priority and use that
        # for majority of time trying to acquire read lock.  If cached
        # priority ends up in WaitingElement, another thread can later
        # update it.
        cached_priority = active_event.get_priority()

        
        # must be careful to add obj to active_event's touched_objs.
        # That way, if active_event needs to backout, we're guaranteed
        # that the state we've allocated for accounting the
        # active_event is cleaned up here.
        if not self.insert_in_touched_objs(active_event):
            self._unlock()
            raise util.BackoutException()

        # check 0 above
        if ((self.write_lock_holder is not None) and
            (active_event.uuid == self.write_lock_holder.event.uuid)):
            to_return = self.dirty_val
            self._unlock()
            return to_return


        # also check 1 above
        if active_event.uuid in self.read_lock_holders:
            # already allowed to read the variable
            to_return = self.val
            self._unlock()
            return to_return

        # must be careful to add obj to active_event's touched_objs.
        # That way, if active_event needs to backout, we're guaranteed
        # that the state we've allocated for accounting the
        # active_event is cleaned up here.
        if not self.insert_in_touched_objs(active_event):
            self._unlock()
            raise util.BackoutException()

        # Check 2 from above
        
        # check 2a
        if self.write_lock_holder is None:
            to_return = self.val
            self.read_lock_holders[active_event.uuid] = (
                EventCachedPriorityObj(active_event,cached_priority))
            
            self._unlock()
            return to_return

        # check 2b
        if gte_priority(cached_priority, self.write_lock_holder.cached_priority):

            # backout write lock if can
            if self.write_lock_holder.event.can_backout_and_hold_lock():
                # actually back out the event
                self.obj_request_backout_and_release_lock(self.write_lock_holder.event)

                # add active event as read lock holder and return
                self.dirty_val = None
                self.write_lock_holder = None
                self.read_lock_holders = {}
                self.read_lock_holders[active_event.uuid] = (
                    EventCachedPriorityObj(active_event,cached_priority))
                to_return = self.val
                self._unlock()
                return to_return

        # Condition 2c + 3

        # create a waiting read element
        waiting_element = WaitingElement(
            active_event,cached_priority,True,self.data_wrapper_constructor,self.peered)
        
        self.waiting_events[active_event.uuid] = waiting_element
        self._unlock()

        return waiting_element.queue.get()