Files
duplicati/Duplicati/Library/Main/Database/LocalBlocklistUpdateDatabase.cs
T

120 lines
5.7 KiB
C#
Raw Normal View History

2013-04-03 21:06:27 +02:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Duplicati.Library.Main.Database
2013-04-03 21:06:27 +02:00
{
public partial class LocalBlocklistUpdateDatabase : LocalRestoreDatabase
{
2013-03-08 22:24:54 +01:00
protected string m_tempblockvolumetable;
2013-04-03 21:06:27 +02:00
protected string m_temphashtable;
public LocalBlocklistUpdateDatabase(string path, long blocksize)
: base(new LocalDatabase(path, "Rebuild"), blocksize)
{
}
public LocalBlocklistUpdateDatabase(LocalDatabase parentdb, long blocksize)
: base(parentdb, blocksize)
2013-04-03 21:06:27 +02:00
{
}
public void FindMissingBlocklistHashes()
{
2013-05-08 21:29:59 +02:00
m_tempblockvolumetable = "MissingBlocks-" + Library.Utility.Utility.ByteArrayAsHexString(Guid.NewGuid().ToByteArray());
m_temphashtable = "Hashlist-" + Library.Utility.Utility.ByteArrayAsHexString(Guid.NewGuid().ToByteArray());
2013-04-03 21:06:27 +02:00
using (var cmd = m_connection.CreateCommand())
{
cmd.ExecuteNonQuery(string.Format(@"CREATE TEMPORARY TABLE ""{0}"" AS SELECT DISTINCT ""Block"".""VolumeID"" AS ""VolumeID"", ""BlocklistHash"".""Hash"" AS ""Hash"", 0 AS ""Restored"" FROM ""Block"", ""BlocklistHash"" WHERE ""Block"".""Hash"" = ""BlocklistHash"".""Hash"" ", m_tempblockvolumetable));
2013-03-08 22:24:54 +01:00
cmd.ExecuteNonQuery(string.Format(@"INSERT INTO ""BlocksetEntry"" (""BlocksetID"", ""Index"", ""BlockID"") SELECT DISTINCT ""Blockset"".""ID"", 0, ""Block"".""ID"" FROM ""Blockset"", ""Block"" WHERE ""Blockset"".""Fullhash"" = ""Block"".""Hash"" AND ""Blockset"".""Length"" < {0} AND ""Blockset"".""ID"" NOT IN (SELECT ""BlocksetID"" FROM ""BlocksetEntry"") ", m_blocksize));
cmd.ExecuteNonQuery(string.Format(@"CREATE TEMPORARY TABLE ""{0}"" (""Hash"" TEXT NOT NULL, ""Index"" INTEGER NOT NULL)", m_temphashtable));
2013-04-03 21:06:27 +02:00
}
}
public IEnumerable<string> GetBlockLists(long volumeid)
{
return new BlocklistsEnumerable(m_connection, m_tempblockvolumetable, volumeid);
}
public void UpdateBlocklist(string hash, IEnumerable<string> hashes, long hashsize, System.Data.IDbTransaction transaction)
{
using (var cmd = m_connection.CreateCommand())
{
cmd.Transaction = transaction;
cmd.CommandText = string.Format(@"UPDATE ""{0}"" SET ""Restored"" = 1 WHERE ""Restored"" = 0 AND ""Hash"" = ? ", m_tempblockvolumetable);
cmd.AddParameter(hash);
var c = cmd.ExecuteNonQuery();
if (c != 1)
2013-03-08 22:24:54 +01:00
throw new Exception(string.Format("Blocklist not found {0}", hash));
cmd.ExecuteNonQuery(string.Format(@"DELETE FROM ""{0}""", m_temphashtable));
cmd.CommandText = string.Format(@"INSERT INTO ""{0}"" (""Hash"", ""Index"") VALUES (?, ?)", m_temphashtable);
long ix = 0;
foreach (var h in hashes)
2013-04-03 21:06:27 +02:00
{
2013-03-08 22:24:54 +01:00
c = cmd.ExecuteNonQuery(null, h, ix);
if (c != 1)
throw new Exception(string.Format("Insert row error {0}", h));
ix++;
}
cmd.CommandText = string.Format(@"INSERT INTO ""BlocksetEntry"" (""BlocksetID"", ""Index"", ""BlockID"") SELECT ""A"".""BlocksetID"", (""A"".""Index"" * ?) + ""B"".""Index"", ""C"".""ID"" FROM ""BlocklistHash"" A, ""{0}"" B, ""Block"" C WHERE ""A"".""Hash"" = ? AND ""C"".""Hash"" = ""B"".""Hash"" ", m_temphashtable);
2013-04-03 21:06:27 +02:00
c = cmd.ExecuteNonQuery(null, (m_blocksize / hashsize), hash);
2013-03-08 22:24:54 +01:00
if (c == 0 || c % ix != 0)
2013-04-03 21:06:27 +02:00
throw new Exception(string.Format("Wrong number of inserts, got {0} records from {1} hashes!", c, ix));
}
}
public IList<IRemoteVolume> GetMissingBlockListVolumes()
{
using (var cmd = m_connection.CreateCommand())
{
List<IRemoteVolume> result = new List<IRemoteVolume>();
cmd.CommandText = string.Format(@"SELECT DISTINCT ""RemoteVolume"".""Name"", ""RemoteVolume"".""Hash"", ""RemoteVolume"".""Size"" FROM ""RemoteVolume"" WHERE ""ID"" IN (SELECT DISTINCT ""VolumeID"" FROM ""{0}"")", m_tempblockvolumetable);
using (var rd = cmd.ExecuteReader())
{
object[] r = new object[3];
while (rd.Read())
{
rd.GetValues(r);
result.Add(new RemoteVolume(
r[0] == null ? null : r[0].ToString(),
r[1] == null ? null : r[1].ToString(),
r[2] == null ? -1 : Convert.ToInt64(r[2])
));
}
}
return result;
}
}
public override void Dispose()
{
base.Dispose();
using (var cmd = m_connection.CreateCommand())
{
if (m_tempblockvolumetable != null)
try
{
cmd.CommandText = string.Format(@"DROP TABLE ""{0}""", m_tempblockvolumetable);
cmd.ExecuteNonQuery();
}
2013-03-08 22:24:54 +01:00
finally { m_tempblockvolumetable = null; }
if (m_temphashtable != null)
try
{
cmd.CommandText = string.Format(@"DROP TABLE ""{0}""", m_temphashtable);
cmd.ExecuteNonQuery();
}
finally { m_temphashtable = null; }
2013-04-03 21:06:27 +02:00
}
}
}
}