This also removes all multi-threaded calls to the database as they were not working as expected. The transactions are now used to keep the database in a sane state, but as far as possible log all messages from the connection to the database without using cross-thread requests. Also fixed some errors with cleanup and rewrote some of the remote filename parsing and validation.
87 lines
3.2 KiB
C#
87 lines
3.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Duplicati.Library.Main.ForestHash.Database;
|
|
using Duplicati.Library.Main.ForestHash.Volumes;
|
|
|
|
namespace Duplicati.Library.Main.ForestHash.Operation
|
|
{
|
|
internal class FindLastFileVersionHandler : IDisposable
|
|
{
|
|
private string m_backendurl;
|
|
private FhOptions m_options;
|
|
private CommunicationStatistics m_stat;
|
|
|
|
public FindLastFileVersionHandler(string backend, FhOptions options, CommunicationStatistics stat)
|
|
{
|
|
m_backendurl = backend;
|
|
m_options = options;
|
|
m_stat = stat;
|
|
}
|
|
|
|
public List<KeyValuePair<string, DateTime>> Run()
|
|
{
|
|
var filelist = m_options.FileToRestore.Split(new char[] { System.IO.Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries);
|
|
var dtnull = new DateTime(0);
|
|
#if DEBUG
|
|
if (!m_options.NoLocalDb)
|
|
#endif
|
|
//Use a speedy local query
|
|
if (System.IO.File.Exists(m_options.Fhdbpath))
|
|
using (var db = new LocalDatabase(m_options.Fhdbpath, "FindLastFileVersion"))
|
|
{
|
|
var found = db.GetNewestFileset(filelist, m_options.RestoreTime).ToDictionary(x => x.Key, x => x.Value);
|
|
return (from n in filelist select new KeyValuePair<string, DateTime>(n, found.ContainsKey(n) ? found[n] : dtnull)).ToList();
|
|
}
|
|
|
|
m_stat.LogWarning("No local database, accessing remote store", null);
|
|
|
|
// Otherwise, grab info from remote location
|
|
using (var tmpdb = new Utility.TempFile())
|
|
using (var db = new LocalDatabase(tmpdb, "FindLastFileVersion"))
|
|
using (var backend = new FhBackend(m_backendurl, m_options, m_stat, db))
|
|
{
|
|
var filter = RestoreHandler.FilterFilelist(m_options.RestoreTime);
|
|
var volumes = filter(from n in backend.List()
|
|
let p = VolumeBase.ParseFilename(n)
|
|
where p != null && p.FileType == RemoteVolumeType.Files
|
|
orderby p.Time
|
|
select p).ToArray();
|
|
|
|
if (volumes.Length == 0)
|
|
throw new Exception("No filesets found on remote target");
|
|
|
|
var res = new Dictionary<string, DateTime>();
|
|
foreach(var s in filelist)
|
|
res[s] = dtnull;
|
|
|
|
foreach(var p in volumes)
|
|
{
|
|
using(var tmpfile = backend.Get(p.File.Name, p.File.Size, null))
|
|
using(var r = new FilesetVolumeReader(p.CompressionModule, tmpfile, m_options))
|
|
foreach(var f in r.Files)
|
|
{
|
|
DateTime n;
|
|
if (res.TryGetValue(f.Path, out n))
|
|
if (n == dtnull)
|
|
res[f.Path] = p.Time;
|
|
}
|
|
|
|
// We are done early
|
|
if (!res.Values.Contains(dtnull))
|
|
break;
|
|
}
|
|
|
|
backend.WaitForComplete(db, null);
|
|
|
|
return res.ToList();
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
}
|
|
}
|
|
}
|