xenadmin/XenModel/Network/StorageLink/StorageLinkCache.cs

312 lines
10 KiB
C#
Raw Normal View History

/* Copyright (c) Citrix Systems Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using XenAPI;
namespace XenAdmin.Network.StorageLink
{
public class StorageLinkCache
{
private readonly object _syncObject = new object();
private readonly List<StorageLinkSystem> _systems = new List<StorageLinkSystem>();
private readonly List<StorageLinkPool> _pools = new List<StorageLinkPool>();
private readonly List<StorageLinkAdapter> _adapters = new List<StorageLinkAdapter>();
private readonly List<StorageLinkVolume> _volumes = new List<StorageLinkVolume>();
private readonly List<StorageLinkRepository> _srs = new List<StorageLinkRepository>();
private StorageLinkServer _server;
public StorageLinkServer Server
{
get
{
lock (_syncObject)
{
return _server;
}
}
private set
{
lock (_syncObject)
{
_server = value;
}
}
}
/// <summary>
/// Occurs when the cache changes or any property of any item in the cache changes.
/// </summary>
public event EventHandler Changed;
public ReadOnlyCollection<StorageLinkSystem> StorageSystems
{
get
{
lock (_syncObject)
{
return new ReadOnlyCollection<StorageLinkSystem>(new List<StorageLinkSystem>(_systems));
}
}
}
public ReadOnlyCollection<StorageLinkPool> StoragePools
{
get
{
lock (_syncObject)
{
return new ReadOnlyCollection<StorageLinkPool>(new List<StorageLinkPool>(_pools));
}
}
}
public ReadOnlyCollection<StorageLinkAdapter> StorageAdapters
{
get
{
lock (_syncObject)
{
return new ReadOnlyCollection<StorageLinkAdapter>(new List<StorageLinkAdapter>(_adapters));
}
}
}
public ReadOnlyCollection<StorageLinkVolume> StorageVolumes
{
get
{
lock (_syncObject)
{
return new ReadOnlyCollection<StorageLinkVolume>(new List<StorageLinkVolume>(_volumes));
}
}
}
public ReadOnlyCollection<StorageLinkRepository> StorageRespositories
{
get
{
lock (_syncObject)
{
return new ReadOnlyCollection<StorageLinkRepository>(new List<StorageLinkRepository>(_srs));
}
}
}
public IEnumerable<IXenObject> XenSearchableObjects(IEnumerable<IXenConnection> connections)
{
StorageLinkServer server = Server;
if (server != null)
{
yield return server;
if (StorageSystems.Count == 0)
{
yield break;
}
foreach (StorageLinkSystem system in StorageSystems)
{
yield return system;
}
foreach (StorageLinkPool pool in StoragePools)
{
// only return top level storage-pools
if (pool.Parent == null)
{
yield return pool;
}
}
foreach (StorageLinkRepository repo in StorageRespositories)
{
// only display it if it belongs to a managed server. StorageLink is to be changed so that it won't listen to
// xapi events telling about an SR being forgotten (for xapi performance reasons.)
if (repo.SR(connections) != null)
{
yield return repo;
}
}
}
}
public void Update(string hostGroupId, List<StorageLinkRepository> repositories)
{
Util.ThrowIfStringParameterNullOrEmpty(hostGroupId, "hostGroupId");
Util.ThrowIfParameterNull(repositories, "repositories");
bool changed;
lock (_syncObject)
{
changed = UpdateItems(_srs, repositories, r => r.HostGroupId == hostGroupId);
}
if (changed)
{
OnChanged(EventArgs.Empty);
}
}
public void Update(string storageSystemId, List<StorageLinkPool> pools, List<StorageLinkVolume> volumes)
{
Util.ThrowIfParameterNull(pools, "pools");
Util.ThrowIfParameterNull(volumes, "volumes");
bool changed;
lock (_syncObject)
{
changed = UpdateItems(_pools, pools, p => p.StorageLinkSystemId == storageSystemId);
changed |= UpdateItems(_volumes, volumes, v => v.StorageLinkSystemId == storageSystemId);
}
if (changed)
{
OnChanged(EventArgs.Empty);
}
}
public void Update(StorageLinkServer server, List<StorageLinkSystem> systems, List<StorageLinkPool> pools, List<StorageLinkAdapter> adapters, List<StorageLinkVolume> volumes, List<StorageLinkRepository> srs)
{
Util.ThrowIfParameterNull(systems, "systems");
Util.ThrowIfParameterNull(pools, "pools");
Util.ThrowIfParameterNull(adapters, "adapters");
Util.ThrowIfParameterNull(volumes, "volumes");
Util.ThrowIfParameterNull(srs, "srs");
bool changed = false;
lock (_syncObject)
{
if (Server == null || server == null)
{
changed = Server != server;
Server = server;
}
else
{
PropertyChangedEventHandler handler = (s, e) => changed = true;
Server.PropertyChanged += handler;
Server.UpdateFrom(server);
Server.PropertyChanged -= handler;
}
changed |= UpdateItems(_systems, systems);
changed |= UpdateItems(_pools, pools);
changed |= UpdateItems(_adapters, adapters);
changed |= UpdateItems(_volumes, volumes);
changed |= UpdateItems(_srs, srs);
}
if (changed)
{
OnChanged(EventArgs.Empty);
}
}
private static bool UpdateItems<T>(List<T> to, List<T> from) where T : StorageLinkObject<T>
{
return UpdateItems<T>(to, from, t => true);
}
private static bool UpdateItems<T>(List<T> to, List<T> from, Predicate<T> match) where T : StorageLinkObject<T>
{
bool changed = false;
foreach (T existingItem in to)
{
T newItem = from.Find(o => o.Equals(existingItem));
if (newItem != null)
{
PropertyChangedEventHandler handler = null;
if (!changed)
{
handler = (s, e) => changed = true;
existingItem.PropertyChanged += handler;
}
existingItem.UpdateFrom(newItem);
if (handler != null)
{
existingItem.PropertyChanged -= handler;
}
}
}
changed |= to.RemoveAll(o => match(o) && !from.Contains(o)) > 0;
List<T> newItems = from.FindAll(s => !to.Contains(s));
changed |= newItems.Count > 0;
to.AddRange(newItems);
return changed;
}
protected virtual void OnChanged(EventArgs e)
{
EventHandler handler = Changed;
if (handler != null)
{
handler(this, e);
}
}
public T Resolve<T>(string opaque_ref) where T : class
{
foreach (System.Collections.IEnumerable enumerable in new System.Collections.IEnumerable[] { StoragePools, StorageVolumes, StorageAdapters, StorageRespositories, StorageSystems })
{
foreach (IStorageLinkObject x in enumerable)
{
if (!(x is T))
{
break;
}
if (x.opaque_ref == opaque_ref)
{
return x as T;
}
}
}
return null;
}
}
}