--- a/src/modules/file_layout/file_manager.py Tue Nov 10 15:42:33 2009 -0700
+++ b/src/modules/file_layout/file_manager.py Tue Nov 10 18:24:21 2009 -0600
@@ -131,7 +131,7 @@
def set_read_only(self):
"""Make the FileManager read only."""
self.readonly = True
-
+
def __select_path(self, hashval, check_existence):
"""Find the path to the file with name hashval.
@@ -216,26 +216,36 @@
raise NeedToModifyReadOnlyFileManager(hashval)
cur_full_path, dest_full_path = \
self.__select_path(hashval, True)
- if cur_full_path == dest_full_path:
- return
- if cur_full_path:
+
+ if cur_full_path and cur_full_path != dest_full_path:
+ # The file is stored in an old location and needs to be
+ # moved to a new location. To prevent disruption of
+ # service or other race conditions, rename the source
+ # file into the old place first.
try:
- portable.remove(src_path)
+ portable.rename(src_path, cur_full_path)
except EnvironmentError, e:
if e.errno == errno.EACCES or \
e.errno == errno.EROFS:
raise FMPermissionsException(e.filename)
raise
src_path = cur_full_path
+
p_dir = os.path.dirname(dest_full_path)
try:
+ # Ensure that the destination's parent directory exists.
if not os.path.exists(p_dir):
os.makedirs(p_dir)
+
+ # Move the file into place.
portable.rename(src_path, dest_full_path)
except EnvironmentError, e:
if e.errno == errno.EACCES or e.errno == errno.EROFS:
raise FMPermissionsException(e.filename)
raise
+
+ # Attempt to remove the parent directory of the file's original
+ # location to ensure empty directories aren't left behind.
if cur_full_path:
try:
os.removedirs(os.path.dirname(cur_full_path))
@@ -248,7 +258,6 @@
raise FMPermissionsException(e.filename)
else:
raise
- return
def remove(self, hashval):
"""This function removes the file associated with the name
@@ -272,7 +281,6 @@
raise FMPermissionsException(e.filename)
else:
raise
- return
def walk(self):
"""Generate all the hashes of all files known."""
--- a/src/tests/api/t_file_manager.py Tue Nov 10 15:42:33 2009 -0700
+++ b/src/tests/api/t_file_manager.py Tue Nov 10 18:24:21 2009 -0600
@@ -23,9 +23,9 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
+import errno
import os
import shutil
-import stat
import sys
import tempfile
import unittest
@@ -61,12 +61,14 @@
def old_hash(s):
return os.path.join(s[0:2], s[2:8], s)
- def touch_old_file(self, s):
+ def touch_old_file(self, s, data=None):
+ if data is None:
+ data = s
p = os.path.join(self.__test_dir, self.old_hash(s))
if not os.path.exists(os.path.dirname(p)):
os.makedirs(os.path.dirname(p))
fh = open(p, "wb")
- fh.write(s)
+ fh.write(data)
fh.close()
return p
@@ -107,7 +109,7 @@
t = tempfile.gettempdir()
no_dir = os.path.join(t, "not_exist")
-
+
self.check_exception(file_manager.FileManager,
file_manager.NeedToModifyReadOnlyFileManager,
["create", no_dir], no_dir, readonly=True)
@@ -159,7 +161,7 @@
# Finally, remove file stored in the old location for the next
# few tests.
p1 = self.touch_old_file(hash1)
- p2 = self.touch_old_file(hash2)
+ self.touch_old_file(hash2)
self.assert_(os.path.isfile(p1))
self.assert_(os.path.isdir(os.path.dirname(p1)))
self.assertEqual(fm.lookup(hash1),
@@ -182,18 +184,10 @@
self.assert_(not os.path.exists(p4))
self.assert_(not os.path.exists(os.path.dirname(p4)))
- # Test that inserting a file already in the file manager just
- # moves the old file if necessary.
p3 = self.touch_old_file(hash3)
self.assert_(os.path.isfile(p3))
self.assert_(os.path.isdir(os.path.dirname(p3)))
-
- rh3_fd, raw_hash_3_loc = tempfile.mkstemp(dir=self.__test_dir)
- rh3_fh = os.fdopen(rh3_fd, "w")
- rh3_fh.write("foo")
- rh3_fh.close()
-
- fm.insert(hash3, raw_hash_3_loc)
+ fm.insert(hash3, p3)
self.assert_(not os.path.exists(p3))
self.assert_(not os.path.exists(os.path.dirname(p3)))
@@ -236,7 +230,7 @@
self.assert_(not os.path.exists(v0_hash3_loc))
self.assert_(not os.path.exists(os.path.dirname(v0_hash3_loc)))
self.assert_(os.path.isfile(fm.lookup(hash1)))
-
+
rh2_fd, raw_hash_2_loc = tempfile.mkstemp(dir=self.__test_dir)
rh2_fh = os.fdopen(rh2_fd, "w")
rh2_fh.write(hash2)
@@ -279,19 +273,19 @@
l1 = layout.V1Layout()
# Populate the managed location using the v0 layout.
- for hash in (hash1, hash2, hash3, hash4):
- self.touch_old_file(hash)
+ for fhash in (hash1, hash2, hash3, hash4):
+ self.touch_old_file(fhash)
# Migrate it to the v1 layout.
fm = file_manager.FileManager(self.__test_dir, False)
- for hash in fm.walk():
- self.assertEqual(fm.lookup(hash),
- os.path.join(self.__test_dir, l1.lookup(hash)))
+ for fhash in fm.walk():
+ self.assertEqual(fm.lookup(fhash),
+ os.path.join(self.__test_dir, l1.lookup(fhash)))
# After migration verify that no v0 parent directories remain.
- for hash in fm.walk():
+ for fhash in fm.walk():
self.assertFalse(os.path.exists(os.path.dirname(
- os.path.join(self.__test_dir, l0.lookup(hash)))))
+ os.path.join(self.__test_dir, l0.lookup(fhash)))))
# Re-create the FileManager using v0 as the preferred layout.
fm = file_manager.FileManager(self.__test_dir, False,
@@ -299,7 +293,52 @@
# Test that looking up a file stored under the v1 layout is
# correctly moved to the v0 layout.
- for hash in fm.walk():
- self.assertEqual(fm.lookup(hash),
- os.path.join(self.__test_dir, l0.lookup(hash)))
+ for fhash in fm.walk():
+ self.assertEqual(fm.lookup(fhash),
+ os.path.join(self.__test_dir, l0.lookup(fhash)))
+
+ def test_3_replace(self):
+ """Verify that insert will replace an existing file even though
+ the hashval is the same."""
+
+ # Verify that reverse layout migration works as expected.
+ hash1 = "584b6ab7d7eb446938a02e57101c3a2fecbfb3cb"
+ hash2 = "584b6ab7d7eb446938a02e57101c3a2fecbfb3cc"
+ hash3 = "994b6ab7d7eb446938a02e57101c3a2fecbfb3cc"
+ hash4 = "cc1f76cdad188714d1c3b92a4eebb4ec7d646166"
+
+ l1 = layout.V1Layout()
+
+ # Populate the managed location using the v0 layout.
+ for fhash in (hash1, hash2, hash3, hash4):
+ self.touch_old_file(fhash, data="old-%s" % fhash)
+ # Migrate it to the v1 layout and verify that each
+ # file contains the expected data.
+ fm = file_manager.FileManager(self.__test_dir, False)
+ for fhash in fm.walk():
+ loc = fm.lookup(fhash)
+ self.assertEqual(loc, os.path.join(self.__test_dir,
+ l1.lookup(fhash)))
+
+ f = open(loc, "rb")
+ self.assertEqual(f.read(), "old-%s" % fhash)
+ f.close()
+
+ # Now replace each file using the old hashnames and verify
+ # that the each contains the expected data.
+ for fhash in fm.walk():
+ loc = os.path.join(self.__test_dir, l1.lookup(fhash))
+ self.assertTrue(os.path.exists(loc))
+
+ npath = os.path.join(self.__test_dir, "new-%s" % fhash)
+ nfile = open(npath, "wb")
+ nfile.write("new-%s" % fhash)
+ nfile.close()
+ fm.insert(fhash, npath)
+
+ loc = fm.lookup(fhash)
+ f = open(loc, "rb")
+ self.assertEqual(f.read(), "new-%s" % fhash)
+ f.close()
+
--- a/src/tests/baseline.txt Tue Nov 10 15:42:33 2009 -0700
+++ b/src/tests/baseline.txt Tue Nov 10 18:24:21 2009 -0600
@@ -31,6 +31,7 @@
api.t_elf.py TestElf.test_is_elf_object|pass
api.t_file_manager.py TestFileManager.test_1|pass
api.t_file_manager.py TestFileManager.test_2_reverse|pass
+api.t_file_manager.py TestFileManager.test_3_replace|pass
api.t_filter.py TestFilter.test_01_debug_i386|pass
api.t_filter.py TestFilter.test_02_nondebug_i386|pass
api.t_filter.py TestFilter.test_03_i386|pass