2014-05-15 50 views
3

我有一個Perl腳本,調用「的gsutil CP」複製選定從GCS到本地文件夾:的gsutil CP:併發執行導致本地文件損壞

$cmd = "[bin-path]/gsutil cp -n gs://[gcs-file-path] [local-folder]"; 
$output = `$cmd 2>&1`; 

腳本通過HTTP,並呼籲因此可以多次啓動(例如通過雙擊鏈接)。發生這種情況時,本地文件最終可能會是正確大小的兩倍,因此顯然會損壞。三件事情出現奇怪:

  1. 的gsutil似乎並沒有被鎖定本地文件正在寫入到 它,讓另一個線程(在這種情況下的gsutil的另一個實例) 寫入同一個文件。

  2. '-n'似乎沒有效果。我預料它會阻止 gsutil的第二個實例嘗試複製操作。

  3. MD5簽名檢查失敗:正常的gsutil刪除 目標文件,如果有一個簽名不匹配,但這顯然 並不總是發生。

有問題的文件大於2MB(通常大約5MB),因此可能會與自動恢復功能進行一些交互。如果本地文件尚不存在,那麼Perl腳本只會調用gsutil,但由於GCS傳輸身份驗證的時間延遲,這並不能捕獲雙擊。

的gsutil版本:3.42在FreeBSD 8.2

任何人都遇到類似的問題?任何人有任何見解?

Edward Leigh

回答

2

1)你是對的,我沒有看到來源鎖。

2)這可能是由競爭條件引起的 - 進程1檢查,發現文件不存在。進程2檢查,看到該文件不存在。過程1開始上傳。過程2開始上傳。文檔說這是在實際上傳過程之前的HEAD操作 - 這與實際上傳不是原子的。

3)對此沒有輸入。

你可以有你的腳本保持某種上開始轉移之前文件的原子鎖解決這個問題 - 即你的檢查將是沿着線的東西:

use Lock::File qw(lockfile); 

if (my $lock = lockfile("$localfile.lock", { blocking => 0 })) { 
    ... perform transfer ... 
    undef $lock; 
} 
else { 
    die "Unable to retrieve $localfile, file is locked"; 
} 
1

1)的gsutil目前不執行文件鎖定。

2)-n不能防止其他g​​sutil實例與重疊目標同時運行。

3)哈希摘要計算字節,因爲他們正在下載作爲性能優化。一旦下載完成,這可以避免長時間運行的計算。如果哈希驗證成功,則保證字節在一個點上成功寫入。但是如果某個東西(甚至是gsutil的另一個實例)在進程運行時就地修改了內容,那麼消化器就不會檢測到這一點。

0

感謝Oesor和Travis回答他們之間的所有問題。作爲Oesor建議的解決方案的附錄,我爲缺少Lock :: File的系統提供此替代方案:

use Fcntl ':flock'; # import LOCK_* constants 

# if lock file exists ... 
if (-e($lockFile)) 
{ 
    # abort if lock file still locked (or sleep and re-check) 
    abort() if !unlink($lockFile); 
    # otherwise delete local file and download again 
    unlink($filePath); 
} 

# if file has not been downloaded already ... 
if (!-e($filePath)) 
{ 
    $cmd = "[bin-path]/gsutil cp -n gs://[gcs-file-path] [local-dir]"; 

    abort() if !open(LOCKFILE, ">$lockFile"); 
    flock(LOCKFILE, LOCK_EX); 
    my $output = `$cmd 2>&1`; 
    flock(LOCKFILE, LOCK_UN); 
    unlink($lockFile); 
}