public void UpdateParity(bool force = false) { if (!force && !DataModified && ParityWritten) { return; } int dataClustersPerTrack = Configuration.Geometry.DataClustersPerTrack; int parityClustersPerTrack = Configuration.Geometry.ParityClustersPerTrack; int bytesPerCluster = Configuration.Geometry.BytesPerCluster; using (var p = new Parity(dataClustersPerTrack, parityClustersPerTrack, bytesPerCluster / 2)) { int codewordExponent = dataClustersPerTrack + parityClustersPerTrack - 1; byte[] emptyCluster = null; foreach (var absoluteClusterNumber in DataClusters) { ClusterState state = _fileSystem.GetClusterState(absoluteClusterNumber); if (!state.IsSystem()) { if ((state & ClusterState.Unwritten) != 0) { if (emptyCluster == null) { EmptyCluster c = new EmptyCluster(absoluteClusterNumber); Console.WriteLine($"Saving empty cluster {absoluteClusterNumber}"); _fileSystem.ClusterIO.Save(c); emptyCluster = new byte[bytesPerCluster]; c.Save(emptyCluster, 0); } p.Calculate(emptyCluster, 0, codewordExponent); state &= ~ClusterState.Unwritten; _fileSystem.SetClusterState(absoluteClusterNumber, state); } else { Cluster c = new Cluster(absoluteClusterNumber, bytesPerCluster); Console.WriteLine($"Loading cluster {absoluteClusterNumber}"); _fileSystem.ClusterIO.Load(c); byte[] bytes = new byte[bytesPerCluster]; c.Save(bytes, 0); p.Calculate(bytes, 0, codewordExponent); } } codewordExponent--; } for (int i = 0; i < parityClustersPerTrack; i++) { ParityCluster c = new ParityCluster(_fileSystem.BlockSize, _trackNumber, i); byte[] bytes = new byte[bytesPerCluster]; p.GetParity(bytes, 0, parityClustersPerTrack - 1 - i); c.Data.Set(0, bytes); Console.WriteLine($"Saving Parity Cluster {c.ClusterAddress}"); _fileSystem.ClusterIO.Save(c); _fileSystem.SetClusterState(c.ClusterAddress, ClusterState.Parity); } } // Update states after the parity is modified in case there is an error foreach (var i in DataClusters) { ClusterState state = _fileSystem.GetClusterState(i) & (~ClusterState.Modified); _fileSystem.SetClusterState(i, state); } }
public void ReedsolomonRepairTest() { int nData = 100; int nParity = 25; int nMessages = 1000; int nErrors = 20; Random r = new Random(1234); byte[][] data = new byte[nData][]; byte[][] original = new byte[nData][]; for (int i = 0; i < nData; i++) { data[i] = new byte[nMessages]; original[i] = new byte[nMessages]; r.NextBytes(data[i]); for (int j = 0; j < nMessages; j++) { original[i][j] = data[i][j]; } } byte[][] parity = new byte[nParity][]; for (int i = 0; i < nParity; i++) { parity[i] = new byte[nMessages * sizeof(ushort)]; } using (Parity p = new Parity(nData, nParity, nMessages / 2)) { for (int i = 0; i < nData; i++) { p.Calculate(data[i], 0, nData + nParity - 1 - i); } for (int i = 0; i < nParity; i++) { p.GetParity(parity[i], 0, nParity - 1 - i); } } List <int> choices = Enumerable.Range(0, nData + nParity).ToList(); List <int> errorExponents = new List <int>(); for (int i = 0; i < nErrors; i++) { int l = r.Next(choices.Count); errorExponents.Add(choices[l]); choices.RemoveAt(l); } foreach (var errorExponent in errorExponents) { byte[] d = errorExponent < nParity ? parity[nParity - 1 - errorExponent] : data[nData + nParity - 1 - errorExponent]; r.NextBytes(d); } using (Syndrome s = new Syndrome(nData, nParity, nMessages / 2)) { for (int i = 0; i < nData; i++) { s.AddCodewordSlice(data[i], 0, nData + nParity - 1 - i); } for (int i = 0; i < nParity; i++) { s.AddCodewordSlice(parity[i], 0, nParity - 1 - i); } using (Repair repair = new Repair(s, nData + nParity, errorExponents)) { int index = 0; foreach (var errorExponent in errorExponents) { byte[] d = errorExponent < nParity ? parity[nParity - 1 - errorExponent] : data[nData + nParity - 1 - errorExponent]; repair.Correction(index, d, 0); index++; } } } for (int i = 0; i < nData; i++) { Assert.IsTrue(data[i].SequenceEqual(original[i])); } }
private void updateParityAsyncInternal(bool force, UpdateParityStatus status, CancellationToken token) { if (!force && !DataModified && ParityWritten) { return; } int dataClustersPerTrack = Configuration.Geometry.DataClustersPerTrack; int parityClustersPerTrack = Configuration.Geometry.ParityClustersPerTrack; int bytesPerCluster = Configuration.Geometry.BytesPerCluster; using (var p = new Parity(dataClustersPerTrack, parityClustersPerTrack, bytesPerCluster / 2)) { int codewordExponent = dataClustersPerTrack + parityClustersPerTrack - 1; byte[] emptyCluster = null; int clustersComplete = -1; foreach (var absoluteClusterNumber in DataClusters) { ClusterState state = _fileSystem.GetClusterState(absoluteClusterNumber); if (!state.IsSystem()) { if ((state & ClusterState.Unwritten) != 0) { if (emptyCluster == null) { EmptyCluster c = new EmptyCluster(absoluteClusterNumber); _fileSystem.ClusterIO.Save(c); emptyCluster = new byte[bytesPerCluster]; c.Save(emptyCluster, 0); } p.Calculate(emptyCluster, 0, codewordExponent); state &= ~ClusterState.Unwritten; _fileSystem.SetClusterState(absoluteClusterNumber, state); } else { Cluster c = new Cluster(absoluteClusterNumber, bytesPerCluster); _fileSystem.ClusterIO.Load(c); byte[] bytes = new byte[bytesPerCluster]; c.Save(bytes, 0); p.Calculate(bytes, 0, codewordExponent); } } clustersComplete++; status.Cluster = clustersComplete; codewordExponent--; if (token.IsCancellationRequested) { return; } } for (int i = 0; i < parityClustersPerTrack; i++) { ParityCluster c = new ParityCluster(_fileSystem.BlockSize, _trackNumber, i); byte[] bytes = new byte[bytesPerCluster]; p.GetParity(bytes, 0, parityClustersPerTrack - 1 - i); c.Data.Set(0, bytes); _fileSystem.ClusterIO.Save(c); _fileSystem.SetClusterState(c.ClusterAddress, ClusterState.Parity); clustersComplete++; status.Cluster = clustersComplete; if (token.IsCancellationRequested) { return; } } } // Update states after the parity is modified in case there is an error foreach (var i in DataClusters) { ClusterState state = _fileSystem.GetClusterState(i) & (~ClusterState.Modified); _fileSystem.SetClusterState(i, state); } _fileSystem.Flush(); }