Revision 24d16f76 lib/locking.py

b/lib/locking.py
32 32
import weakref
33 33
import logging
34 34
import heapq
35
import operator
35 36

  
36 37
from ganeti import errors
37 38
from ganeti import utils
38 39
from ganeti import compat
40
from ganeti import query
39 41

  
40 42

  
41 43
_EXCLUSIVE_TEXT = "exclusive"
42 44
_SHARED_TEXT = "shared"
45
_DELETED_TEXT = "deleted"
43 46

  
44 47
_DEFAULT_PRIORITY = 0
45 48

  
......
432 435
    if monitor:
433 436
      monitor.RegisterLock(self)
434 437

  
435
  def GetInfo(self, fields):
438
  def GetInfo(self, requested):
436 439
    """Retrieves information for querying locks.
437 440

  
438
    @type fields: list of strings
439
    @param fields: List of fields to return
441
    @type requested: set
442
    @param requested: Requested information, see C{query.LQ_*}
440 443

  
441 444
    """
442 445
    self.__lock.acquire()
443 446
    try:
444
      info = []
445

  
446 447
      # Note: to avoid unintentional race conditions, no references to
447 448
      # modifiable objects should be returned unless they were created in this
448 449
      # function.
449
      for fname in fields:
450
        if fname == "name":
451
          info.append(self.name)
452
        elif fname == "mode":
453
          if self.__deleted:
454
            info.append("deleted")
455
            assert not (self.__exc or self.__shr)
456
          elif self.__exc:
457
            info.append(_EXCLUSIVE_TEXT)
458
          elif self.__shr:
459
            info.append(_SHARED_TEXT)
460
          else:
461
            info.append(None)
462
        elif fname == "owner":
463
          if self.__exc:
464
            owner = [self.__exc]
465
          else:
466
            owner = self.__shr
467

  
468
          if owner:
469
            assert not self.__deleted
470
            info.append([i.getName() for i in owner])
471
          else:
472
            info.append(None)
473
        elif fname == "pending":
474
          data = []
475

  
476
          # Sorting instead of copying and using heaq functions for simplicity
477
          for (_, prioqueue) in sorted(self.__pending):
478
            for cond in prioqueue:
479
              if cond.shared:
480
                mode = _SHARED_TEXT
481
              else:
482
                mode = _EXCLUSIVE_TEXT
483

  
484
              # This function should be fast as it runs with the lock held.
485
              # Hence not using utils.NiceSort.
486
              data.append((mode, sorted(i.getName()
487
                                        for i in cond.get_waiting())))
488

  
489
          info.append(data)
450
      mode = None
451
      owner_names = None
452

  
453
      if query.LQ_MODE in requested:
454
        if self.__deleted:
455
          mode = _DELETED_TEXT
456
          assert not (self.__exc or self.__shr)
457
        elif self.__exc:
458
          mode = _EXCLUSIVE_TEXT
459
        elif self.__shr:
460
          mode = _SHARED_TEXT
461

  
462
      # Current owner(s) are wanted
463
      if query.LQ_OWNER in requested:
464
        if self.__exc:
465
          owner = [self.__exc]
490 466
        else:
491
          raise errors.OpExecError("Invalid query field '%s'" % fname)
467
          owner = self.__shr
468

  
469
        if owner:
470
          assert not self.__deleted
471
          owner_names = [i.getName() for i in owner]
492 472

  
493
      return info
473
      # Pending acquires are wanted
474
      if query.LQ_PENDING in requested:
475
        pending = []
476

  
477
        # Sorting instead of copying and using heaq functions for simplicity
478
        for (_, prioqueue) in sorted(self.__pending):
479
          for cond in prioqueue:
480
            if cond.shared:
481
              pendmode = _SHARED_TEXT
482
            else:
483
              pendmode = _EXCLUSIVE_TEXT
484

  
485
            # List of names will be sorted in L{query._GetLockPending}
486
            pending.append((pendmode, [i.getName()
487
                                       for i in cond.get_waiting()]))
488
      else:
489
        pending = None
490

  
491
      return (self.name, mode, owner_names, pending)
494 492
    finally:
495 493
      self.__lock.release()
496 494

  
......
1344 1342
                              monitor=self._monitor),
1345 1343
      }
1346 1344

  
1347
  def QueryLocks(self, fields, sync):
1345
  def QueryLocks(self, fields):
1348 1346
    """Queries information from all locks.
1349 1347

  
1350 1348
    See L{LockMonitor.QueryLocks}.
1351 1349

  
1352 1350
    """
1353
    return self._monitor.QueryLocks(fields, sync)
1351
    return self._monitor.QueryLocks(fields)
1352

  
1353
  def OldStyleQueryLocks(self, fields):
1354
    """Queries information from all locks, returning old-style data.
1355

  
1356
    See L{LockMonitor.OldStyleQueryLocks}.
1357

  
1358
    """
1359
    return self._monitor.OldStyleQueryLocks(fields)
1354 1360

  
1355 1361
  def _names(self, level):
1356 1362
    """List the lock names at the given level.
......
1533 1539
    self._locks[lock] = None
1534 1540

  
1535 1541
  @ssynchronized(_LOCK_ATTR)
1536
  def _GetLockInfo(self, fields):
1542
  def _GetLockInfo(self, requested):
1537 1543
    """Get information from all locks while the monitor lock is held.
1538 1544

  
1539 1545
    """
1540
    result = {}
1546
    return [lock.GetInfo(requested) for lock in self._locks.keys()]
1541 1547

  
1542
    for lock in self._locks.keys():
1543
      assert lock.name not in result, "Found duplicate lock name"
1544
      result[lock.name] = lock.GetInfo(fields)
1548
  def _Query(self, fields):
1549
    """Queries information from all locks.
1545 1550

  
1546
    return result
1551
    @type fields: list of strings
1552
    @param fields: List of fields to return
1553

  
1554
    """
1555
    qobj = query.Query(query.LOCK_FIELDS, fields)
1556

  
1557
    # Get all data and sort by name
1558
    lockinfo = utils.NiceSort(self._GetLockInfo(qobj.RequestedData()),
1559
                              key=operator.itemgetter(0))
1560

  
1561
    return (qobj, query.LockQueryData(lockinfo))
1547 1562

  
1548
  def QueryLocks(self, fields, sync):
1563
  def QueryLocks(self, fields):
1549 1564
    """Queries information from all locks.
1550 1565

  
1551 1566
    @type fields: list of strings
1552 1567
    @param fields: List of fields to return
1553
    @type sync: boolean
1554
    @param sync: Whether to operate in synchronous mode
1555 1568

  
1556 1569
    """
1557
    if sync:
1558
      raise NotImplementedError("Synchronous queries are not implemented")
1570
    (qobj, ctx) = self._Query(fields)
1559 1571

  
1560
    # Get all data without sorting
1561
    result = self._GetLockInfo(fields)
1572
    # Prepare query response
1573
    return query.GetQueryResponse(qobj, ctx)
1574

  
1575
  def OldStyleQueryLocks(self, fields):
1576
    """Queries information from all locks, returning old-style data.
1577

  
1578
    @type fields: list of strings
1579
    @param fields: List of fields to return
1580

  
1581
    """
1582
    (qobj, ctx) = self._Query(fields)
1562 1583

  
1563
    # Sort by name
1564
    return [result[name] for name in utils.NiceSort(result.keys())]
1584
    return qobj.OldStyleQuery(ctx)

Also available in: Unified diff