Skip to content

Commit

Permalink
Merge pull request #178 from jaredmoo/LookupFromCacheNetCore
Browse files Browse the repository at this point in the history
Ability to specify lookup options
  • Loading branch information
jaredmoo authored Mar 8, 2019
2 parents 328f446 + 8a95a37 commit 11f5683
Show file tree
Hide file tree
Showing 13 changed files with 563 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<AssemblyTitle>Microsoft Azure SQL Database: Elastic Database Client Library</AssemblyTitle>
<NeutralLanguage>en-US</NeutralLanguage>
<Version>2.0.0</Version>
<Version>2.1.0</Version>
<Authors>Microsoft</Authors>
<TargetFrameworks>net451;netstandard2.0</TargetFrameworks>
<PackageTags>Microsoft;Elastic;Scale;Azure;SQL;DB;Database;Shard;Sharding;Management;Query;azureofficial</PackageTags>
<PackageReleaseNotes>Added support for .NET Standard 2.0.

Added support for SecureString via SqlCredential.</PackageReleaseNotes>
<PackageReleaseNotes>Added support for LookupOptions in ListShardMap.GetMappingForKey(....) , ListShardMap.TryGetMappingForKey(....), RangeShardMap.GetMappingForKey(....), and RangeShardMap.TryGetMappingForKey(....). This gives the ability to lookup from cache instead of only from store, which can greatly improve performance.</PackageReleaseNotes>
<PackageIconUrl>http://go.microsoft.com/fwlink/?LinkID=288890</PackageIconUrl>
<PackageProjectUrl>https://github.com/Azure/elastic-db-tools</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/Azure/elastic-db-tools/blob/master/LICENSE</PackageLicenseUrl>
Expand Down
35 changes: 35 additions & 0 deletions Src/ElasticScale.Client/ShardManagement/Shard/LookupOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;

namespace Microsoft.Azure.SqlDatabase.ElasticScale.ShardManagement
{
/// <summary>
/// Specifies where mapping lookup operations will search for mappings.
/// </summary>
[Flags]
public enum LookupOptions : int
{
/// <summary>
/// Default invalid kind of lookup options.
/// </summary>
None = 0,

/// <summary>
/// Attempt to lookup in the local cache.
/// </summary>
/// <remarks>
/// If LookupInCache and LookupInStore are both specified, the cache will be searched first, then the store.
/// </remarks>
LookupInCache = 1 << 0,

/// <summary>
/// Attempt to lookup in the global shard map store.
/// </summary>
/// <remarks>
/// If LookupInCache and LookupInStore are both specified, the cache will be searched first, then the store.
/// </remarks>
LookupInStore = 1 << 1,
}
}
43 changes: 37 additions & 6 deletions Src/ElasticScale.Client/ShardManagement/ShardMap/ListShardMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -382,38 +382,69 @@ public void DeleteMapping(PointMapping<TKey> mapping)

/// <summary>
/// Looks up the key value and returns the corresponding mapping.
/// Only the global shard map store is searched, not the local cache.
/// </summary>
/// <remarks>
/// This is equivalent to <c>GetMappingForKey(key, LookupOptions.LookupInStore)</c>.
/// </remarks>
/// <param name="key">Input key value.</param>
/// <returns>Mapping that contains the key value.</returns>
public PointMapping<TKey> GetMappingForKey(TKey key)
{
return GetMappingForKey(key, LookupOptions.LookupInStore);
}

/// <summary>
/// Looks up the key value and returns the corresponding mapping.
/// </summary>
/// <param name="key">Input key value.</param>
/// <param name="lookupOptions">Whether to search in the cache and/or store.</param>
/// <returns>Mapping that contains the key value.</returns>
public PointMapping<TKey> GetMappingForKey(TKey key, LookupOptions lookupOptions)
{
using (ActivityIdScope activityIdScope = new ActivityIdScope(Guid.NewGuid()))
{
Tracer.TraceInfo(TraceSourceConstants.ComponentNames.ListShardMap,
"LookupPointMapping", "Start; ShardMap name: {0}; Point Mapping Key Type: {1}",
this.Name, typeof(TKey));
"LookupPointMapping", "Start; ShardMap name: {0}; Point Mapping Key Type: {1}; Lookup Options: {2}",
this.Name, typeof(TKey), lookupOptions);

Stopwatch stopwatch = Stopwatch.StartNew();

PointMapping<TKey> pointMapping = _lsm.Lookup(key, false);
PointMapping<TKey> pointMapping = _lsm.Lookup(key, lookupOptions);

stopwatch.Stop();

Tracer.TraceInfo(TraceSourceConstants.ComponentNames.ListShardMap,
"LookupPointMapping", "Complete; ShardMap name: {0}; Point Mapping Key Type: {1}; Duration: {2}",
this.Name, typeof(TKey), stopwatch.Elapsed);
"LookupPointMapping", "Complete; ShardMap name: {0}; Point Mapping Key Type: {1}; Lookup Options: {2}; Duration: {3}",
this.Name, typeof(TKey), lookupOptions, stopwatch.Elapsed);

return pointMapping;
}
}

/// <summary>
/// Tries to looks up the key value and place the corresponding mapping in <paramref name="pointMapping"/>.
/// Only the global shard map store is searched, not the local cache.
/// </summary>
/// <remarks>
/// This is equivalent to <c>TryGetMappingForKey(key, LookupOptions.LookupInStore, out pointMapping)</c>.
/// </remarks>
/// <param name="key">Input key value.</param>
/// <param name="pointMapping">Mapping that contains the key value.</param>
/// <returns><c>true</c> if mapping is found, <c>false</c> otherwise.</returns>
public bool TryGetMappingForKey(TKey key, out PointMapping<TKey> pointMapping)
{
return TryGetMappingForKey(key, LookupOptions.LookupInStore, out pointMapping);
}

/// <summary>
/// Tries to looks up the key value and place the corresponding mapping in <paramref name="pointMapping"/>.
/// </summary>
/// <param name="key">Input key value.</param>
/// <param name="lookupOptions">Whether to search in the cache and/or store.</param>
/// <param name="pointMapping">Mapping that contains the key value.</param>
/// <returns><c>true</c> if mapping is found, <c>false</c> otherwise.</returns>
public bool TryGetMappingForKey(TKey key, LookupOptions lookupOptions, out PointMapping<TKey> pointMapping)
{
using (ActivityIdScope activityIdScope = new ActivityIdScope(Guid.NewGuid()))
{
Expand All @@ -423,7 +454,7 @@ public bool TryGetMappingForKey(TKey key, out PointMapping<TKey> pointMapping)

Stopwatch stopwatch = Stopwatch.StartNew();

bool result = _lsm.TryLookup(key, false, out pointMapping);
bool result = _lsm.TryLookup(key, lookupOptions, out pointMapping);

stopwatch.Stop();

Expand Down
42 changes: 37 additions & 5 deletions Src/ElasticScale.Client/ShardManagement/ShardMap/RangeShardMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -342,37 +342,69 @@ public void DeleteMapping(RangeMapping<TKey> mapping, MappingLockToken mappingLo

/// <summary>
/// Looks up the key value and returns the corresponding mapping.
/// Only the global shard map store is searched, not the local cache.
/// </summary>
/// <remarks>
/// This is equivalent to <c>GetMappingForKey(key, LookupOptions.LookupInStore)</c>.
/// </remarks>
/// <param name="key">Input key value.</param>
/// <returns>Mapping that contains the key value.</returns>
public RangeMapping<TKey> GetMappingForKey(TKey key)
{
return GetMappingForKey(key, LookupOptions.LookupInStore);
}

/// <summary>
/// Looks up the key value and returns the corresponding mapping.
/// </summary>
/// <param name="key">Input key value.</param>
/// <param name="lookupOptions">Whether to search in the cache and/or store.</param>
/// <returns>Mapping that contains the key value.</returns>
public RangeMapping<TKey> GetMappingForKey(TKey key, LookupOptions lookupOptions)
{
using (ActivityIdScope activityIdScope = new ActivityIdScope(Guid.NewGuid()))
{
Tracer.TraceInfo(TraceSourceConstants.ComponentNames.RangeShardMap,
"GetMapping", "Start; Range Mapping Key Type: {0}", typeof(TKey));
"GetMapping", "Start; Shard Map name: {0}, Range Mapping Key Type: {1}; Lookup Options: {2}",
this.Name, typeof(TKey), lookupOptions);

Stopwatch stopwatch = Stopwatch.StartNew();

RangeMapping<TKey> rangeMapping = this.rsm.Lookup(key, false);
RangeMapping<TKey> rangeMapping = this.rsm.Lookup(key, lookupOptions);

stopwatch.Stop();

Tracer.TraceInfo(TraceSourceConstants.ComponentNames.RangeShardMap,
"GetMapping", "Complete; Range Mapping Key Type: {0} Duration: {1}",
typeof(TKey), stopwatch.Elapsed);
"GetMapping", "Start; Shard Map name: {0}, Range Mapping Key Type: {1}; Lookup Options: {2}; Duration: {3}",
this.Name, typeof(TKey), lookupOptions, stopwatch.Elapsed);

return rangeMapping;
}
}

/// <summary>
/// Tries to looks up the key value and place the corresponding mapping in <paramref name="rangeMapping"/>.
/// Only the global shard map store is searched, not the local cache.
/// </summary>
/// <remarks>
/// This is equivalent to <c>TryGetMappingForKey(key, LookupOptions.LookupInStore, out rangeMapping)</c>.
/// </remarks>
/// <param name="key">Input key value.</param>
/// <param name="rangeMapping">Mapping that contains the key value.</param>
/// <returns><c>true</c> if mapping is found, <c>false</c> otherwise.</returns>
public bool TryGetMappingForKey(TKey key, out RangeMapping<TKey> rangeMapping)
{
return TryGetMappingForKey(key, LookupOptions.LookupInStore, out rangeMapping);
}

/// <summary>
/// Tries to looks up the key value and place the corresponding mapping in <paramref name="rangeMapping"/>.
/// </summary>
/// <param name="key">Input key value.</param>
/// <param name="lookupOptions">Whether to search in the cache and/or store.</param>
/// <param name="rangeMapping">Mapping that contains the key value.</param>
/// <returns><c>true</c> if mapping is found, <c>false</c> otherwise.</returns>
public bool TryGetMappingForKey(TKey key, LookupOptions lookupOptions, out RangeMapping<TKey> rangeMapping)
{
using (ActivityIdScope activityIdScope = new ActivityIdScope(Guid.NewGuid()))
{
Expand All @@ -382,7 +414,7 @@ public bool TryGetMappingForKey(TKey key, out RangeMapping<TKey> rangeMapping)

Stopwatch stopwatch = Stopwatch.StartNew();

bool result = this.rsm.TryLookup(key, false, out rangeMapping);
bool result = this.rsm.TryLookup(key, lookupOptions, out rangeMapping);

stopwatch.Stop();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -535,66 +535,83 @@ protected void Remove<TMapping>(
/// <typeparam name="TMapping">Mapping type.</typeparam>
/// <typeparam name="TKey">Key type.</typeparam>
/// <param name="key">Input key value.</param>
/// <param name="useCache">Whether to use cache for lookups.</param>
/// <param name="lookupOptions">Whether to use cache and/or storage for lookups.</param>
/// <param name="constructMapping">Delegate to construct a mapping object.</param>
/// <param name="errorCategory">Category under which errors must be thrown.</param>
/// <returns>Mapping that contains the key value.</returns>
protected TMapping Lookup<TMapping, TKey>(
TKey key,
bool useCache,
LookupOptions lookupOptions,
Func<ShardMapManager, ShardMap, IStoreMapping, TMapping> constructMapping,
ShardManagementErrorCategory errorCategory)
where TMapping : class, IShardProvider
{
ShardKey sk = new ShardKey(ShardKey.ShardKeyTypeFromType(typeof(TKey)), key);

if (useCache)
// Try to lookup in cache. Note the interation with cache removal later in this method.
bool tryLookupInCache = lookupOptions.HasFlag(LookupOptions.LookupInCache);
if (tryLookupInCache)
{
ICacheStoreMapping cachedMapping = this.Manager.Cache.LookupMappingByKey(this.ShardMap.StoreShardMap, sk);

if (cachedMapping != null)
{
return constructMapping(this.Manager, this.ShardMap, cachedMapping.Mapping);
}
}

// Cache-miss, find mapping for given key in GSM.
TMapping m = null;
// Cache-miss (or didn't use cache), find mapping for given key in GSM.
if (lookupOptions.HasFlag(LookupOptions.LookupInStore))
{
IStoreResults gsmResult;

IStoreResults gsmResult;
Stopwatch stopwatch = Stopwatch.StartNew();

Stopwatch stopwatch = Stopwatch.StartNew();
using (IStoreOperationGlobal op = this.Manager.StoreOperationFactory.CreateFindMappingByKeyGlobalOperation(
this.Manager,
"Lookup",
this.ShardMap.StoreShardMap,
sk,
CacheStoreMappingUpdatePolicy.OverwriteExisting,
errorCategory,
true,
false))
{
gsmResult = op.Do();
}

using (IStoreOperationGlobal op = this.Manager.StoreOperationFactory.CreateFindMappingByKeyGlobalOperation(
this.Manager,
"Lookup",
this.ShardMap.StoreShardMap,
sk,
CacheStoreMappingUpdatePolicy.OverwriteExisting,
errorCategory,
true,
false))
{
gsmResult = op.Do();
}
stopwatch.Stop();

stopwatch.Stop();
Tracer.TraceVerbose(
TraceSourceConstants.ComponentNames.BaseShardMapper,
"Lookup",
"Lookup key from GSM complete; Key type : {0}; Result: {1}; Duration: {2}",
typeof(TKey),
gsmResult.Result,
stopwatch.Elapsed);

Tracer.TraceVerbose(
TraceSourceConstants.ComponentNames.BaseShardMapper,
"Lookup",
"Lookup key from GSM complete; Key type : {0}; Result: {1}; Duration: {2}",
typeof(TKey),
gsmResult.Result,
stopwatch.Elapsed);
// If mapping was found, return it.
if (gsmResult.Result != StoreResult.MappingNotFoundForKey)
{
return gsmResult.StoreMappings.Select(sm => constructMapping(this.Manager, this.ShardMap, sm)).Single();
}

// If we could not locate the mapping, we return null and do nothing here.
if (gsmResult.Result != StoreResult.MappingNotFoundForKey)
{
return gsmResult.StoreMappings.Select(sm => constructMapping(this.Manager, this.ShardMap, sm)).Single();
// If we could not locate the mapping, then we might need to update the cache to remove it.
//
// Only do this if we didn't already try to return the mapping from the cache (since, if it was found,
// we would have already returned it earlier).
if (!tryLookupInCache)
{
ICacheStoreMapping cachedMapping =
this.Manager.Cache.LookupMappingByKey(this.ShardMap.StoreShardMap, sk);
if (cachedMapping != null)
{
this.Manager.Cache.DeleteMapping(cachedMapping.Mapping);
}
}
}

return m;
// Mapping not found - return null
return null;
}

/// <summary>
Expand Down
Loading

0 comments on commit 11f5683

Please sign in to comment.