42 |
42 |
using System.Collections.Concurrent;
|
43 |
43 |
using Pithos.Interfaces;
|
44 |
44 |
using Pithos.Network;
|
|
45 |
using System;
|
|
46 |
using System.Collections.Generic;
|
|
47 |
using System.Linq;
|
45 |
48 |
|
46 |
49 |
namespace Pithos.Core.Agents
|
47 |
50 |
{
|
48 |
|
using System;
|
49 |
|
using System.Collections.Generic;
|
50 |
|
using System.Linq;
|
51 |
|
using System.Text;
|
52 |
51 |
|
53 |
52 |
/// <summary>
|
54 |
|
/// TODO: Update summary.
|
|
53 |
/// Calculates the differences between two ObjectInfo snapshots.
|
55 |
54 |
/// </summary>
|
56 |
55 |
public class SnapshotDifferencer
|
57 |
56 |
{
|
58 |
|
private IEnumerable<ObjectInfo> _previous;
|
59 |
|
private IEnumerable<ObjectInfo> _current;
|
60 |
|
private static ObjectInfo[] _empty = new ObjectInfo[0];
|
61 |
|
private ObjectInfoComparer _comparer = new ObjectInfoComparer();
|
|
57 |
/// <summary>
|
|
58 |
/// Contains the previous and current listings.
|
|
59 |
/// Using a separate class for the state simplifies the Post method
|
|
60 |
/// which has to modify the listings
|
|
61 |
/// </summary>
|
|
62 |
private class State
|
|
63 |
{
|
|
64 |
/// <summary>
|
|
65 |
/// The previous snapshot listing
|
|
66 |
/// </summary>
|
|
67 |
public readonly IEnumerable<ObjectInfo> Previous;
|
|
68 |
|
|
69 |
/// <summary>
|
|
70 |
/// The current snapshot listing
|
|
71 |
/// </summary>
|
|
72 |
public readonly IEnumerable<ObjectInfo> Current;
|
|
73 |
|
|
74 |
/// <summary>
|
|
75 |
/// Common objects, lazily evalueated.
|
|
76 |
/// The common objects are used to calculate both the Changed and Unchanged objects
|
|
77 |
/// </summary>
|
|
78 |
public readonly Lazy<IEnumerable<ObjectInfo>> Common;
|
|
79 |
|
|
80 |
public State(IEnumerable<ObjectInfo> previous, IEnumerable<ObjectInfo> current)
|
|
81 |
{
|
|
82 |
Previous = previous ?? new List<ObjectInfo>();
|
|
83 |
Current = current ?? new List<ObjectInfo>();
|
|
84 |
|
|
85 |
Common=new Lazy<IEnumerable<ObjectInfo>>(() =>
|
|
86 |
Current.Join(Previous,
|
|
87 |
outKey => new { outKey.Account, outKey.Container, outKey.Name },
|
|
88 |
inKey => new { inKey.Account, inKey.Container, inKey.Name },
|
|
89 |
(outer, inner) =>
|
|
90 |
{
|
|
91 |
outer.PreviousHash = inner.Hash;
|
|
92 |
return outer;
|
|
93 |
}));
|
|
94 |
}
|
|
95 |
}
|
|
96 |
|
62 |
97 |
|
|
98 |
private State _state;
|
|
99 |
|
|
100 |
/// <summary>
|
|
101 |
/// The comparer used to identify common objects.
|
|
102 |
/// Objects are considered common when they have the same Account, Container and Name
|
|
103 |
/// </summary>
|
|
104 |
private readonly ObjectInfoComparer _comparer = new ObjectInfoComparer();
|
|
105 |
|
|
106 |
/// <summary>
|
|
107 |
/// Default constructor. Initializes the Current and Previous listings to empty lists
|
|
108 |
/// </summary>
|
63 |
109 |
public SnapshotDifferencer()
|
|
110 |
:this(new List<ObjectInfo>(),new List<ObjectInfo>())
|
64 |
111 |
{
|
65 |
|
_previous = new List<ObjectInfo>();
|
66 |
|
_current= new List<ObjectInfo>();
|
67 |
112 |
}
|
68 |
113 |
|
69 |
|
|
|
114 |
/// <summary>
|
|
115 |
/// Creates a new differencer using the specified previous and current list. Null lists
|
|
116 |
/// are replaced with empty lists
|
|
117 |
/// </summary>
|
|
118 |
/// <param name="previous"></param>
|
|
119 |
/// <param name="current"></param>
|
70 |
120 |
public SnapshotDifferencer(IEnumerable<ObjectInfo> previous,IEnumerable<ObjectInfo> current )
|
71 |
121 |
{
|
72 |
|
_previous = previous ?? new List<ObjectInfo>();
|
73 |
|
_current= current ?? new List<ObjectInfo>();
|
|
122 |
_state=new State(previous,current);
|
74 |
123 |
}
|
|
124 |
|
|
125 |
/// <summary>
|
|
126 |
/// Posts a new listing
|
|
127 |
/// </summary>
|
|
128 |
/// <param name="list"></param>
|
|
129 |
/// <returns></returns>
|
75 |
130 |
public SnapshotDifferencer Post(IEnumerable<ObjectInfo> list)
|
76 |
131 |
{
|
77 |
|
_previous = _current;
|
78 |
|
if (list == null)
|
|
132 |
List<ObjectInfo> newCurrent=null;
|
|
133 |
if (list != null)
|
79 |
134 |
{
|
80 |
|
_current = new List<ObjectInfo>();
|
81 |
|
return this;
|
|
135 |
//The state field holds the old state
|
|
136 |
var oldState = _state;
|
|
137 |
//Replace any NoModification entries with previous values that have
|
|
138 |
//the same account, container and possibly, folder
|
|
139 |
newCurrent = list.Replace(
|
|
140 |
info => info is NoModificationInfo,
|
|
141 |
noMod => oldState.Current.Where(noMod.CorrespondsTo))
|
|
142 |
.ToList();
|
82 |
143 |
}
|
83 |
|
|
84 |
|
|
85 |
|
//The previous values that correspond to a NoModification object
|
86 |
|
//have the same account, container and possibly the same folder
|
87 |
|
Func<ObjectInfo, ObjectInfo, bool> correspondsTo = (info, noMod) =>
|
88 |
|
info.Account == noMod.Account
|
89 |
|
&& info.Container == noMod.Container
|
90 |
|
&& (noMod.Name == null || info.Name.StartsWith(noMod.Name));
|
91 |
|
|
92 |
|
//Replace any NoModification entries with previous values that have
|
93 |
|
//the same account, container and possibly, folder
|
94 |
|
_current=list.Replace(
|
95 |
|
info => info is NoModificationInfo,
|
96 |
|
noMod => _previous.Where(info => correspondsTo(info, noMod)))
|
97 |
|
.ToList();
|
|
144 |
//Set the new state
|
|
145 |
_state = new State(_state.Current, newCurrent);
|
98 |
146 |
|
99 |
147 |
return this;
|
100 |
148 |
}
|
101 |
149 |
|
102 |
150 |
public IEnumerable<ObjectInfo> Deleted
|
103 |
151 |
{
|
104 |
|
get { return _previous.Except(_current,_comparer); }
|
|
152 |
get { return _state.Previous.Except(_state.Current,_comparer); }
|
105 |
153 |
}
|
106 |
154 |
public IEnumerable<ObjectInfo> Created
|
107 |
155 |
{
|
108 |
|
get { return _current.Except(_previous,_comparer); }
|
|
156 |
get { return _state.Current.Except(_state.Previous,_comparer); }
|
|
157 |
}
|
|
158 |
|
|
159 |
public IEnumerable<ObjectInfo> Common
|
|
160 |
{
|
|
161 |
get { return _state.Common.Value; }
|
109 |
162 |
}
|
|
163 |
|
110 |
164 |
public IEnumerable<ObjectInfo> Changed
|
111 |
165 |
{
|
112 |
|
get
|
113 |
|
{
|
114 |
|
var changes = from newItem in _current
|
115 |
|
let oldItem=_previous.FirstOrDefault(old=>_comparer.Equals(old,newItem))
|
116 |
|
where oldItem !=null &&
|
117 |
|
newItem.Hash != oldItem.Hash
|
118 |
|
select newItem;
|
119 |
|
return changes;
|
120 |
|
}
|
|
166 |
get{return Common.Where(i=>i.PreviousHash!=i.Hash);}
|
121 |
167 |
}
|
122 |
168 |
public IEnumerable<ObjectInfo> Unchanged
|
123 |
169 |
{
|
124 |
|
get
|
125 |
|
{
|
126 |
|
var unChanged = from newItem in _current
|
127 |
|
let oldItem = _previous.FirstOrDefault(old => _comparer.Equals(old, newItem))
|
128 |
|
where oldItem != null &&
|
129 |
|
newItem.Hash == oldItem.Hash
|
130 |
|
select newItem;
|
131 |
|
return unChanged;
|
132 |
|
}
|
|
170 |
get{ return Common.Where(i => i.PreviousHash == i.Hash);}
|
133 |
171 |
}
|
134 |
172 |
}
|
135 |
173 |
|
136 |
174 |
public class AccountsDifferencer
|
137 |
175 |
{
|
138 |
|
ConcurrentDictionary<string, SnapshotDifferencer> _differencers = new ConcurrentDictionary<string, SnapshotDifferencer>();
|
|
176 |
readonly ConcurrentDictionary<string, SnapshotDifferencer> _differencers = new ConcurrentDictionary<string, SnapshotDifferencer>();
|
139 |
177 |
|
140 |
178 |
public ConcurrentDictionary<string, SnapshotDifferencer> Differencers { get { return _differencers; } }
|
141 |
179 |
|