1553
1553
"""Release the mutex around the pack-names index."""
1554
1554
self.repo.control_files.unlock()
1556
def _save_pack_names(self, clear_obsolete_packs=False):
1557
"""Save the list of packs.
1559
This will take out the mutex around the pack names list for the
1560
duration of the method call. If concurrent updates have been made, a
1561
three-way merge between the current list and the current in memory list
1564
:param clear_obsolete_packs: If True, clear out the contents of the
1565
obsolete_packs directory.
1569
builder = self._index_builder_class()
1570
# load the disk nodes across
1572
for index, key, value in self._iter_disk_pack_index():
1573
disk_nodes.add((key, value))
1574
# do a two-way diff against our original content
1575
current_nodes = set()
1576
for name, sizes in self._names.iteritems():
1578
((name, ), ' '.join(str(size) for size in sizes)))
1579
deleted_nodes = self._packs_at_load - current_nodes
1580
new_nodes = current_nodes - self._packs_at_load
1581
disk_nodes.difference_update(deleted_nodes)
1582
disk_nodes.update(new_nodes)
1583
# TODO: handle same-name, index-size-changes here -
1584
# e.g. use the value from disk, not ours, *unless* we're the one
1586
for key, value in disk_nodes:
1587
builder.add_node(key, value)
1588
self.transport.put_file('pack-names', builder.finish(),
1589
mode=self.repo.bzrdir._get_file_mode())
1590
# move the baseline forward
1591
self._packs_at_load = disk_nodes
1592
if clear_obsolete_packs:
1593
self._clear_obsolete_packs()
1595
self._unlock_names()
1596
# synchronise the memory packs list with what we just wrote:
1556
def _diff_pack_names(self):
1557
"""Read the pack names from disk, and compare it to the one in memory.
1559
:return: (disk_nodes, deleted_nodes, new_nodes)
1560
disk_nodes The final set of nodes that should be referenced
1561
deleted_nodes Nodes which have been removed from when we started
1562
new_nodes Nodes that are newly introduced
1564
# load the disk nodes across
1566
for index, key, value in self._iter_disk_pack_index():
1567
disk_nodes.add((key, value))
1569
# do a two-way diff against our original content
1570
current_nodes = set()
1571
for name, sizes in self._names.iteritems():
1573
((name, ), ' '.join(str(size) for size in sizes)))
1575
# Packs no longer present in the repository, which were present when we
1576
# locked the repository
1577
deleted_nodes = self._packs_at_load - current_nodes
1578
# Packs which this process is adding
1579
new_nodes = current_nodes - self._packs_at_load
1581
# Update the disk_nodes set to include the ones we are adding, and
1582
# remove the ones which were removed by someone else
1583
disk_nodes.difference_update(deleted_nodes)
1584
disk_nodes.update(new_nodes)
1586
return disk_nodes, deleted_nodes, new_nodes
1588
def _syncronize_pack_names_from_disk_nodes(self, disk_nodes):
1589
"""Given the correct set of pack files, update our saved info.
1591
:return: (removed, added, modified)
1592
removed pack names removed from self._names
1593
added pack names added to self._names
1594
modified pack names that had changed value
1599
## self._packs_at_load = disk_nodes
1597
1600
new_names = dict(disk_nodes)
1598
1601
# drop no longer present nodes
1599
1602
for pack in self.all_packs():
1600
1603
if (pack.name,) not in new_names:
1604
removed.append(pack.name)
1601
1605
self._remove_pack_from_memory(pack)
1602
1606
# add new nodes/refresh existing ones
1603
1607
for key, value in disk_nodes:
1617
1621
self._remove_pack_from_memory(self.get_pack_by_name(name))
1618
1622
self._names[name] = sizes
1619
1623
self.get_pack_by_name(name)
1624
modified.append(name)
1622
1627
self._names[name] = sizes
1623
1628
self.get_pack_by_name(name)
1630
return removed, added, modified
1632
def _save_pack_names(self, clear_obsolete_packs=False):
1633
"""Save the list of packs.
1635
This will take out the mutex around the pack names list for the
1636
duration of the method call. If concurrent updates have been made, a
1637
three-way merge between the current list and the current in memory list
1640
:param clear_obsolete_packs: If True, clear out the contents of the
1641
obsolete_packs directory.
1645
builder = self._index_builder_class()
1646
disk_nodes, deleted_nodes, new_nodes = self._diff_pack_names()
1647
# TODO: handle same-name, index-size-changes here -
1648
# e.g. use the value from disk, not ours, *unless* we're the one
1650
for key, value in disk_nodes:
1651
builder.add_node(key, value)
1652
self.transport.put_file('pack-names', builder.finish(),
1653
mode=self.repo.bzrdir._get_file_mode())
1654
# move the baseline forward
1655
self._packs_at_load = disk_nodes
1656
if clear_obsolete_packs:
1657
self._clear_obsolete_packs()
1659
self._unlock_names()
1660
# synchronise the memory packs list with what we just wrote:
1661
self._syncronize_pack_names_from_disk_nodes(disk_nodes)
1663
def reload_pack_names(self):
1664
"""Sync our pack listing with what is present in the repository.
1666
This should be called when we find out that something we thought was
1667
present is now missing. This happens when another process re-packs the
1670
# This is functionally similar to _save_pack_names, but we don't write
1671
# out the new value.
1672
disk_nodes, _, _ = self._diff_pack_names()
1673
self._packs_at_load = disk_nodes
1674
return self._syncronize_pack_names_from_disk_nodes(disk_nodes)
1625
1676
def _clear_obsolete_packs(self):
1626
1677
"""Delete everything from the obsolete-packs directory.