Statistics
| Branch: | Revision:

root / trunk / Pithos.Core / Agents / SnapshotDifferencer.cs @ dccd340f

History | View | Annotate | Download (8.5 kB)

1 255f5f86 Panagiotis Kanavos
#region
2 255f5f86 Panagiotis Kanavos
/* -----------------------------------------------------------------------
3 255f5f86 Panagiotis Kanavos
 * <copyright file="SnapshotDifferencer.cs" company="GRNet">
4 255f5f86 Panagiotis Kanavos
 * 
5 255f5f86 Panagiotis Kanavos
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6 255f5f86 Panagiotis Kanavos
 *
7 255f5f86 Panagiotis Kanavos
 * Redistribution and use in source and binary forms, with or
8 255f5f86 Panagiotis Kanavos
 * without modification, are permitted provided that the following
9 255f5f86 Panagiotis Kanavos
 * conditions are met:
10 255f5f86 Panagiotis Kanavos
 *
11 255f5f86 Panagiotis Kanavos
 *   1. Redistributions of source code must retain the above
12 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
13 255f5f86 Panagiotis Kanavos
 *      disclaimer.
14 255f5f86 Panagiotis Kanavos
 *
15 255f5f86 Panagiotis Kanavos
 *   2. Redistributions in binary form must reproduce the above
16 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
17 255f5f86 Panagiotis Kanavos
 *      disclaimer in the documentation and/or other materials
18 255f5f86 Panagiotis Kanavos
 *      provided with the distribution.
19 255f5f86 Panagiotis Kanavos
 *
20 255f5f86 Panagiotis Kanavos
 *
21 255f5f86 Panagiotis Kanavos
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 255f5f86 Panagiotis Kanavos
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 255f5f86 Panagiotis Kanavos
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 255f5f86 Panagiotis Kanavos
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 255f5f86 Panagiotis Kanavos
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 255f5f86 Panagiotis Kanavos
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 255f5f86 Panagiotis Kanavos
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 255f5f86 Panagiotis Kanavos
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 255f5f86 Panagiotis Kanavos
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 255f5f86 Panagiotis Kanavos
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 255f5f86 Panagiotis Kanavos
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 255f5f86 Panagiotis Kanavos
 * POSSIBILITY OF SUCH DAMAGE.
33 255f5f86 Panagiotis Kanavos
 *
34 255f5f86 Panagiotis Kanavos
 * The views and conclusions contained in the software and
35 255f5f86 Panagiotis Kanavos
 * documentation are those of the authors and should not be
36 255f5f86 Panagiotis Kanavos
 * interpreted as representing official policies, either expressed
37 255f5f86 Panagiotis Kanavos
 * or implied, of GRNET S.A.
38 255f5f86 Panagiotis Kanavos
 * </copyright>
39 255f5f86 Panagiotis Kanavos
 * -----------------------------------------------------------------------
40 255f5f86 Panagiotis Kanavos
 */
41 255f5f86 Panagiotis Kanavos
#endregion
42 7f0e1c1e Panagiotis Kanavos
using System.Collections.Concurrent;
43 b666b39a Panagiotis Kanavos
using System.Diagnostics.Contracts;
44 039d89ea Panagiotis Kanavos
using Pithos.Interfaces;
45 a0622735 Panagiotis Kanavos
using Pithos.Network;
46 64171b56 Panagiotis Kanavos
using System.Collections.Generic;
47 64171b56 Panagiotis Kanavos
using System.Linq;
48 039d89ea Panagiotis Kanavos
49 039d89ea Panagiotis Kanavos
namespace Pithos.Core.Agents
50 039d89ea Panagiotis Kanavos
{
51 039d89ea Panagiotis Kanavos
52 039d89ea Panagiotis Kanavos
    /// <summary>
53 64171b56 Panagiotis Kanavos
    /// Calculates the differences between two ObjectInfo snapshots.
54 039d89ea Panagiotis Kanavos
    /// </summary>
55 039d89ea Panagiotis Kanavos
    public class SnapshotDifferencer
56 039d89ea Panagiotis Kanavos
    {
57 64171b56 Panagiotis Kanavos
        /// <summary>
58 64171b56 Panagiotis Kanavos
        /// Contains the previous and current listings.
59 64171b56 Panagiotis Kanavos
        /// Using a separate class for the state simplifies the Post method
60 64171b56 Panagiotis Kanavos
        /// which has to modify the listings
61 64171b56 Panagiotis Kanavos
        /// </summary>
62 64171b56 Panagiotis Kanavos
        private class State
63 64171b56 Panagiotis Kanavos
        {
64 64171b56 Panagiotis Kanavos
            /// <summary>
65 64171b56 Panagiotis Kanavos
            /// The previous snapshot listing
66 64171b56 Panagiotis Kanavos
            /// </summary>
67 2ea0ca4f Panagiotis Kanavos
            public readonly ObjectInfo[] Previous;
68 64171b56 Panagiotis Kanavos
69 64171b56 Panagiotis Kanavos
            /// <summary>
70 64171b56 Panagiotis Kanavos
            /// The current snapshot listing
71 64171b56 Panagiotis Kanavos
            /// </summary>
72 2ea0ca4f Panagiotis Kanavos
            public readonly ObjectInfo[] Current;
73 64171b56 Panagiotis Kanavos
74 b666b39a Panagiotis Kanavos
            public readonly Dictionary<string, ObjectInfo> CurrentDict;
75 b666b39a Panagiotis Kanavos
76 b666b39a Panagiotis Kanavos
            public readonly Dictionary<string, ObjectInfo> PreviousDict;
77 b666b39a Panagiotis Kanavos
78 b666b39a Panagiotis Kanavos
79 64171b56 Panagiotis Kanavos
            /// <summary>
80 64171b56 Panagiotis Kanavos
            /// Common objects, lazily evalueated. 
81 64171b56 Panagiotis Kanavos
            /// The common objects are used to calculate both the Changed and Unchanged objects
82 64171b56 Panagiotis Kanavos
            /// </summary>
83 89472316 Panagiotis Kanavos
            public readonly IEnumerable<ObjectInfo> Common;
84 64171b56 Panagiotis Kanavos
85 6ef37eeb Panagiotis Kanavos
            private readonly static ObjectInfo[] Empty = new ObjectInfo[0];
86 6ef37eeb Panagiotis Kanavos
87 b666b39a Panagiotis Kanavos
            [ContractInvariantMethod]
88 b666b39a Panagiotis Kanavos
            private void StatInvariant()
89 b666b39a Panagiotis Kanavos
            {
90 b666b39a Panagiotis Kanavos
// ReSharper disable InvocationIsSkipped
91 b666b39a Panagiotis Kanavos
                Contract.Invariant(Current!=null);
92 b666b39a Panagiotis Kanavos
                Contract.Invariant(Previous!=null);
93 b666b39a Panagiotis Kanavos
                Contract.Invariant(CurrentDict!=null);
94 b666b39a Panagiotis Kanavos
                Contract.Invariant(PreviousDict!=null);
95 b666b39a Panagiotis Kanavos
                Contract.Invariant(Common!=null);
96 b666b39a Panagiotis Kanavos
// ReSharper restore InvocationIsSkipped
97 b666b39a Panagiotis Kanavos
            }
98 b666b39a Panagiotis Kanavos
99 2ea0ca4f Panagiotis Kanavos
            public State(ObjectInfo[] previous, ObjectInfo[] current)
100 64171b56 Panagiotis Kanavos
            {
101 6ef37eeb Panagiotis Kanavos
                Previous = previous ?? Empty;
102 6ef37eeb Panagiotis Kanavos
                Current = current ?? Empty;
103 b666b39a Panagiotis Kanavos
                CurrentDict = Current.ToDictionary(info => info.UUID);
104 b666b39a Panagiotis Kanavos
                PreviousDict = Previous.ToDictionary(info => info.UUID);
105 64171b56 Panagiotis Kanavos
106 89472316 Panagiotis Kanavos
                //Attach the previous version to the current listings
107 89472316 Panagiotis Kanavos
                foreach (var info in Current)
108 89472316 Panagiotis Kanavos
                {
109 89472316 Panagiotis Kanavos
                    ObjectInfo prev;
110 89472316 Panagiotis Kanavos
                    if (PreviousDict.TryGetValue(info.UUID, out prev))
111 89472316 Panagiotis Kanavos
                        info.SetPrevious(prev);
112 89472316 Panagiotis Kanavos
                }
113 89472316 Panagiotis Kanavos
114 89472316 Panagiotis Kanavos
                Common=Current.Where(c=>c.Previous !=null);
115 64171b56 Panagiotis Kanavos
            }
116 64171b56 Panagiotis Kanavos
        }
117 64171b56 Panagiotis Kanavos
118 039d89ea Panagiotis Kanavos
119 64171b56 Panagiotis Kanavos
        private State _state;
120 64171b56 Panagiotis Kanavos
121 64171b56 Panagiotis Kanavos
        /// <summary>
122 64171b56 Panagiotis Kanavos
        /// Default constructor. Initializes the Current and Previous listings to empty lists
123 64171b56 Panagiotis Kanavos
        /// </summary>
124 039d89ea Panagiotis Kanavos
        public SnapshotDifferencer()
125 6ef37eeb Panagiotis Kanavos
        {                        
126 6ef37eeb Panagiotis Kanavos
            _state = new State(null, null);
127 039d89ea Panagiotis Kanavos
        }
128 64171b56 Panagiotis Kanavos
129 64171b56 Panagiotis Kanavos
        /// <summary>
130 64171b56 Panagiotis Kanavos
        /// Posts a new listing
131 64171b56 Panagiotis Kanavos
        /// </summary>
132 64171b56 Panagiotis Kanavos
        /// <param name="list"></param>
133 64171b56 Panagiotis Kanavos
        /// <returns></returns>
134 039d89ea Panagiotis Kanavos
        public SnapshotDifferencer Post(IEnumerable<ObjectInfo> list)
135 039d89ea Panagiotis Kanavos
        {
136 2ea0ca4f Panagiotis Kanavos
            ObjectInfo[] newCurrent=null;
137 64171b56 Panagiotis Kanavos
            if (list != null)
138 99e6329f Panagiotis Kanavos
            {
139 64171b56 Panagiotis Kanavos
                //The state field holds the old state
140 64171b56 Panagiotis Kanavos
                var oldState = _state;
141 64171b56 Panagiotis Kanavos
                //Replace any NoModification entries with previous values that have
142 64171b56 Panagiotis Kanavos
                //the same account, container and possibly, folder
143 64171b56 Panagiotis Kanavos
                newCurrent = list.Replace(
144 64171b56 Panagiotis Kanavos
                    info => info is NoModificationInfo,
145 64171b56 Panagiotis Kanavos
                    noMod => oldState.Current.Where(noMod.CorrespondsTo))
146 2ea0ca4f Panagiotis Kanavos
                    .ToArray();
147 99e6329f Panagiotis Kanavos
            }
148 64171b56 Panagiotis Kanavos
            //Set the new state
149 64171b56 Panagiotis Kanavos
            _state = new State(_state.Current, newCurrent);
150 99e6329f Panagiotis Kanavos
151 422c9598 Panagiotis Kanavos
            return this;
152 039d89ea Panagiotis Kanavos
        }
153 039d89ea Panagiotis Kanavos
        
154 b666b39a Panagiotis Kanavos
        /// <summary>
155 b666b39a Panagiotis Kanavos
        /// Deleted objects are those that existed in the Previous listing
156 89472316 Panagiotis Kanavos
        /// but are not found in the Current listing
157 b666b39a Panagiotis Kanavos
        /// </summary>
158 039d89ea Panagiotis Kanavos
        public IEnumerable<ObjectInfo> Deleted
159 039d89ea Panagiotis Kanavos
        {
160 89472316 Panagiotis Kanavos
            get { return _state.Previous
161 b666b39a Panagiotis Kanavos
                .Where(info=>!_state.CurrentDict.ContainsKey(info.UUID)); }
162 039d89ea Panagiotis Kanavos
        }
163 b666b39a Panagiotis Kanavos
164 b666b39a Panagiotis Kanavos
        /// <summary>
165 b666b39a Panagiotis Kanavos
        /// Created objects are those that exist in the Current listing
166 89472316 Panagiotis Kanavos
        /// but are not found in the Previous listing 
167 b666b39a Panagiotis Kanavos
        /// </summary>
168 039d89ea Panagiotis Kanavos
        public IEnumerable<ObjectInfo> Created
169 039d89ea Panagiotis Kanavos
        {
170 89472316 Panagiotis Kanavos
            get { return _state.Current
171 b666b39a Panagiotis Kanavos
                .Where(info=>!_state.PreviousDict.ContainsKey(info.UUID)); }
172 64171b56 Panagiotis Kanavos
        }
173 64171b56 Panagiotis Kanavos
                
174 64171b56 Panagiotis Kanavos
        public IEnumerable<ObjectInfo> Common
175 64171b56 Panagiotis Kanavos
        {
176 89472316 Panagiotis Kanavos
            get { return _state.Common; }
177 039d89ea Panagiotis Kanavos
        }
178 64171b56 Panagiotis Kanavos
179 039d89ea Panagiotis Kanavos
        public IEnumerable<ObjectInfo> Changed
180 039d89ea Panagiotis Kanavos
        {
181 5e10d44f Panagiotis Kanavos
            get
182 5e10d44f Panagiotis Kanavos
            {
183 89472316 Panagiotis Kanavos
                return Common.Where(info => 
184 89472316 Panagiotis Kanavos
                    //The hash is different
185 89472316 Panagiotis Kanavos
                    info.PreviousHash != info.Hash 
186 89472316 Panagiotis Kanavos
                    //And the Uri is unchanged or there is no previous version
187 89472316 Panagiotis Kanavos
                    && (info.Previous == null ||  info.Uri == info.Previous.Uri));
188 89472316 Panagiotis Kanavos
            }
189 039d89ea Panagiotis Kanavos
        }
190 89472316 Panagiotis Kanavos
191 89472316 Panagiotis Kanavos
        /// <summary>
192 89472316 Panagiotis Kanavos
        /// Unchanged objects have the same current and previous hash
193 89472316 Panagiotis Kanavos
        /// </summary>
194 039d89ea Panagiotis Kanavos
        public IEnumerable<ObjectInfo> Unchanged
195 039d89ea Panagiotis Kanavos
        {
196 64171b56 Panagiotis Kanavos
            get{ return Common.Where(i => i.PreviousHash == i.Hash);}
197 039d89ea Panagiotis Kanavos
        }
198 b666b39a Panagiotis Kanavos
199 89472316 Panagiotis Kanavos
        /// <summary>
200 89472316 Panagiotis Kanavos
        /// Moved objects have a previous version with a different name
201 89472316 Panagiotis Kanavos
        /// </summary>
202 b666b39a Panagiotis Kanavos
        public IEnumerable<ObjectInfo>  Moved
203 b666b39a Panagiotis Kanavos
        {
204 b666b39a Panagiotis Kanavos
            get
205 89472316 Panagiotis Kanavos
            {                                
206 89472316 Panagiotis Kanavos
                return Common.Where(info=>
207 89472316 Panagiotis Kanavos
                    //A previous version exists
208 89472316 Panagiotis Kanavos
                    info.Previous!= null 
209 89472316 Panagiotis Kanavos
                    //and the Uri is different
210 89472316 Panagiotis Kanavos
                    && info.Uri!=info.Previous.Uri);                    
211 b666b39a Panagiotis Kanavos
            }
212 b666b39a Panagiotis Kanavos
        }
213 039d89ea Panagiotis Kanavos
    }
214 a0622735 Panagiotis Kanavos
215 a0622735 Panagiotis Kanavos
    public class AccountsDifferencer
216 a0622735 Panagiotis Kanavos
    {
217 64171b56 Panagiotis Kanavos
        readonly ConcurrentDictionary<string, SnapshotDifferencer> _differencers = new ConcurrentDictionary<string, SnapshotDifferencer>();
218 a0622735 Panagiotis Kanavos
219 7f0e1c1e Panagiotis Kanavos
        public ConcurrentDictionary<string, SnapshotDifferencer> Differencers { get { return _differencers; } }
220 a0622735 Panagiotis Kanavos
221 a0622735 Panagiotis Kanavos
        public SnapshotDifferencer PostSnapshot(AccountInfo accountInfo, List<ObjectInfo> cleanRemotes)
222 a0622735 Panagiotis Kanavos
        {
223 a0622735 Panagiotis Kanavos
            SnapshotDifferencer differencer;
224 a0622735 Panagiotis Kanavos
            if (!_differencers.TryGetValue(accountInfo.UserName, out differencer))
225 a0622735 Panagiotis Kanavos
            {
226 a0622735 Panagiotis Kanavos
                differencer = new SnapshotDifferencer();
227 a0622735 Panagiotis Kanavos
                _differencers[accountInfo.UserName] = differencer;
228 a0622735 Panagiotis Kanavos
            }
229 a0622735 Panagiotis Kanavos
            differencer.Post(cleanRemotes);
230 a0622735 Panagiotis Kanavos
            return differencer;
231 a0622735 Panagiotis Kanavos
        }
232 a0622735 Panagiotis Kanavos
233 a0622735 Panagiotis Kanavos
    }
234 039d89ea Panagiotis Kanavos
}