Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (8.5 kB)

1
#region
2
/* -----------------------------------------------------------------------
3
 * <copyright file="SnapshotDifferencer.cs" company="GRNet">
4
 * 
5
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or
8
 * without modification, are permitted provided that the following
9
 * conditions are met:
10
 *
11
 *   1. Redistributions of source code must retain the above
12
 *      copyright notice, this list of conditions and the following
13
 *      disclaimer.
14
 *
15
 *   2. Redistributions in binary form must reproduce the above
16
 *      copyright notice, this list of conditions and the following
17
 *      disclaimer in the documentation and/or other materials
18
 *      provided with the distribution.
19
 *
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
 * POSSIBILITY OF SUCH DAMAGE.
33
 *
34
 * The views and conclusions contained in the software and
35
 * documentation are those of the authors and should not be
36
 * interpreted as representing official policies, either expressed
37
 * or implied, of GRNET S.A.
38
 * </copyright>
39
 * -----------------------------------------------------------------------
40
 */
41
#endregion
42
using System.Collections.Concurrent;
43
using System.Diagnostics.Contracts;
44
using Pithos.Interfaces;
45
using Pithos.Network;
46
using System.Collections.Generic;
47
using System.Linq;
48

    
49
namespace Pithos.Core.Agents
50
{
51

    
52
    /// <summary>
53
    /// Calculates the differences between two ObjectInfo snapshots.
54
    /// </summary>
55
    public class SnapshotDifferencer
56
    {
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 ObjectInfo[] Previous;
68

    
69
            /// <summary>
70
            /// The current snapshot listing
71
            /// </summary>
72
            public readonly ObjectInfo[] Current;
73

    
74
            public readonly Dictionary<string, ObjectInfo> CurrentDict;
75

    
76
            public readonly Dictionary<string, ObjectInfo> PreviousDict;
77

    
78

    
79
            /// <summary>
80
            /// Common objects, lazily evalueated. 
81
            /// The common objects are used to calculate both the Changed and Unchanged objects
82
            /// </summary>
83
            public readonly IEnumerable<ObjectInfo> Common;
84

    
85
            private readonly static ObjectInfo[] Empty = new ObjectInfo[0];
86

    
87
            [ContractInvariantMethod]
88
            private void StatInvariant()
89
            {
90
// ReSharper disable InvocationIsSkipped
91
                Contract.Invariant(Current!=null);
92
                Contract.Invariant(Previous!=null);
93
                Contract.Invariant(CurrentDict!=null);
94
                Contract.Invariant(PreviousDict!=null);
95
                Contract.Invariant(Common!=null);
96
// ReSharper restore InvocationIsSkipped
97
            }
98

    
99
            public State(ObjectInfo[] previous, ObjectInfo[] current)
100
            {
101
                Previous = previous ?? Empty;
102
                Current = current ?? Empty;
103
                CurrentDict = Current.ToDictionary(info => info.UUID);
104
                PreviousDict = Previous.ToDictionary(info => info.UUID);
105

    
106
                //Attach the previous version to the current listings
107
                foreach (var info in Current)
108
                {
109
                    ObjectInfo prev;
110
                    if (PreviousDict.TryGetValue(info.UUID, out prev))
111
                        info.SetPrevious(prev);
112
                }
113

    
114
                Common=Current.Where(c=>c.Previous !=null);
115
            }
116
        }
117

    
118

    
119
        private State _state;
120

    
121
        /// <summary>
122
        /// Default constructor. Initializes the Current and Previous listings to empty lists
123
        /// </summary>
124
        public SnapshotDifferencer()
125
        {                        
126
            _state = new State(null, null);
127
        }
128

    
129
        /// <summary>
130
        /// Posts a new listing
131
        /// </summary>
132
        /// <param name="list"></param>
133
        /// <returns></returns>
134
        public SnapshotDifferencer Post(IEnumerable<ObjectInfo> list)
135
        {
136
            ObjectInfo[] newCurrent=null;
137
            if (list != null)
138
            {
139
                //The state field holds the old state
140
                var oldState = _state;
141
                //Replace any NoModification entries with previous values that have
142
                //the same account, container and possibly, folder
143
                newCurrent = list.Replace(
144
                    info => info is NoModificationInfo,
145
                    noMod => oldState.Current.Where(noMod.CorrespondsTo))
146
                    .ToArray();
147
            }
148
            //Set the new state
149
            _state = new State(_state.Current, newCurrent);
150

    
151
            return this;
152
        }
153
        
154
        /// <summary>
155
        /// Deleted objects are those that existed in the Previous listing
156
        /// but are not found in the Current listing
157
        /// </summary>
158
        public IEnumerable<ObjectInfo> Deleted
159
        {
160
            get { return _state.Previous
161
                .Where(info=>!_state.CurrentDict.ContainsKey(info.UUID)); }
162
        }
163

    
164
        /// <summary>
165
        /// Created objects are those that exist in the Current listing
166
        /// but are not found in the Previous listing 
167
        /// </summary>
168
        public IEnumerable<ObjectInfo> Created
169
        {
170
            get { return _state.Current
171
                .Where(info=>!_state.PreviousDict.ContainsKey(info.UUID)); }
172
        }
173
                
174
        public IEnumerable<ObjectInfo> Common
175
        {
176
            get { return _state.Common; }
177
        }
178

    
179
        public IEnumerable<ObjectInfo> Changed
180
        {
181
            get
182
            {
183
                return Common.Where(info => 
184
                    //The hash is different
185
                    info.PreviousHash != info.Hash 
186
                    //And the Uri is unchanged or there is no previous version
187
                    && (info.Previous == null ||  info.Uri == info.Previous.Uri));
188
            }
189
        }
190

    
191
        /// <summary>
192
        /// Unchanged objects have the same current and previous hash
193
        /// </summary>
194
        public IEnumerable<ObjectInfo> Unchanged
195
        {
196
            get{ return Common.Where(i => i.PreviousHash == i.Hash);}
197
        }
198

    
199
        /// <summary>
200
        /// Moved objects have a previous version with a different name
201
        /// </summary>
202
        public IEnumerable<ObjectInfo>  Moved
203
        {
204
            get
205
            {                                
206
                return Common.Where(info=>
207
                    //A previous version exists
208
                    info.Previous!= null 
209
                    //and the Uri is different
210
                    && info.Uri!=info.Previous.Uri);                    
211
            }
212
        }
213
    }
214

    
215
    public class AccountsDifferencer
216
    {
217
        readonly ConcurrentDictionary<string, SnapshotDifferencer> _differencers = new ConcurrentDictionary<string, SnapshotDifferencer>();
218

    
219
        public ConcurrentDictionary<string, SnapshotDifferencer> Differencers { get { return _differencers; } }
220

    
221
        public SnapshotDifferencer PostSnapshot(AccountInfo accountInfo, List<ObjectInfo> cleanRemotes)
222
        {
223
            SnapshotDifferencer differencer;
224
            if (!_differencers.TryGetValue(accountInfo.UserName, out differencer))
225
            {
226
                differencer = new SnapshotDifferencer();
227
                _differencers[accountInfo.UserName] = differencer;
228
            }
229
            differencer.Post(cleanRemotes);
230
            return differencer;
231
        }
232

    
233
    }
234
}