Statistics
| Branch: | Revision:

root / trunk / Pithos.Core / Agents / SnapshotDifferencer.cs @ 6ef37eeb

History | View | Annotate | Download (6.8 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 Pithos.Interfaces;
44
using Pithos.Network;
45
using System;
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
            /// <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
            private readonly static ObjectInfo[] Empty = new ObjectInfo[0];
81

    
82
            public State(ObjectInfo[] previous, ObjectInfo[] current)
83
            {
84
                Previous = previous ?? Empty;
85
                Current = current ?? Empty;
86

    
87
                Common=new Lazy<IEnumerable<ObjectInfo>>(() =>
88
                    Current.Join(Previous,
89
                                outKey => new { outKey.Account, outKey.Container, outKey.Name },
90
                                inKey => new { inKey.Account, inKey.Container, inKey.Name },
91
                                (outer, inner) =>
92
                                {
93
                                    outer.PreviousHash = inner.Hash;
94
                                    return outer;
95
                                }));            
96
            }
97
        }
98

    
99

    
100
        private State _state;
101

    
102
        /// <summary>
103
        /// The comparer used to identify common objects.
104
        /// Objects are considered common when they have the same Account, Container and Name
105
        /// </summary>
106
        private readonly ObjectInfoComparer _comparer = new ObjectInfoComparer();
107

    
108
        /// <summary>
109
        /// Default constructor. Initializes the Current and Previous listings to empty lists
110
        /// </summary>
111
        public SnapshotDifferencer()
112
        {                        
113
            _state = new State(null, null);
114
        }
115

    
116
        /// <summary>
117
        /// Posts a new listing
118
        /// </summary>
119
        /// <param name="list"></param>
120
        /// <returns></returns>
121
        public SnapshotDifferencer Post(IEnumerable<ObjectInfo> list)
122
        {
123
            ObjectInfo[] newCurrent=null;
124
            if (list != null)
125
            {
126
                //The state field holds the old state
127
                var oldState = _state;
128
                //Replace any NoModification entries with previous values that have
129
                //the same account, container and possibly, folder
130
                newCurrent = list.Replace(
131
                    info => info is NoModificationInfo,
132
                    noMod => oldState.Current.Where(noMod.CorrespondsTo))
133
                    .ToArray();
134
            }
135
            //Set the new state
136
            _state = new State(_state.Current, newCurrent);
137

    
138
            return this;
139
        }
140
        
141
        public IEnumerable<ObjectInfo> Deleted
142
        {
143
            get { return _state.Previous.Except(_state.Current,_comparer); }
144
        }
145
        public IEnumerable<ObjectInfo> Created
146
        {
147
            get { return _state.Current.Except(_state.Previous,_comparer); }
148
        }
149
                
150
        public IEnumerable<ObjectInfo> Common
151
        {
152
            get { return _state.Common.Value; }
153
        }
154

    
155
        public IEnumerable<ObjectInfo> Changed
156
        {
157
            get{return Common.Where(i=>i.PreviousHash!=i.Hash);}
158
        }
159
        public IEnumerable<ObjectInfo> Unchanged
160
        {
161
            get{ return Common.Where(i => i.PreviousHash == i.Hash);}
162
        }
163
    }
164

    
165
    public class AccountsDifferencer
166
    {
167
        readonly ConcurrentDictionary<string, SnapshotDifferencer> _differencers = new ConcurrentDictionary<string, SnapshotDifferencer>();
168

    
169
        public ConcurrentDictionary<string, SnapshotDifferencer> Differencers { get { return _differencers; } }
170

    
171
        public SnapshotDifferencer PostSnapshot(AccountInfo accountInfo, List<ObjectInfo> cleanRemotes)
172
        {
173
            SnapshotDifferencer differencer;
174
            if (!_differencers.TryGetValue(accountInfo.UserName, out differencer))
175
            {
176
                differencer = new SnapshotDifferencer();
177
                _differencers[accountInfo.UserName] = differencer;
178
            }
179
            differencer.Post(cleanRemotes);
180
            return differencer;
181
        }
182

    
183
    }
184
}