Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace ICache interface by a CacheBase class #1777

Merged
merged 2 commits into from
Oct 31, 2018

Conversation

fredericDelaporte
Copy link
Member

In order to ease adding cache features, and provide default implementations for them, use an abstract base class instead of an interface.

This is similar to DbConnection, DbCommand and the like pattern.

It allows to reduce the needs for "transitional interfaces" and simplifies implementing new features as it allows to abstract away whether the implementation is obsolete or not, actually supports the new features or not.

@fredericDelaporte fredericDelaporte added this to the 5.2 milestone Jun 27, 2018
@hazzik hazzik changed the title Replace ICache interface by a BaseCache class Replace ICache interface by a CacheBase class Jun 27, 2018
@hazzik

This comment has been minimized.

{

public Task<object> GetAsync(object key, CancellationToken cancellationToken)
public override Task<object> GetAsync(object key, CancellationToken cancellationToken)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These overrides are not really needed since the base do the same, but I guess it would be a bit hard for the async generator to detect that case.

/// </para>
/// <para>
/// This base class provides minimal async method implementations delegating their work to their
/// synchronous counterparts. Override them for supplying actual async operations.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same pattern as DbConnection: a default async implementation calling the synchronous methods is provided for relieving implementors of doing that themselves, if their cache has no async operations.

try
{
impl = settings.CacheProvider.BuildCache(name, properties);
ccs.Cache = settings.CacheProvider.BuildCache(name, properties);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property setter has no logic, doing the assignment outside of the try was just complicating the code for no reasons.

try
{
impl = settings.CacheProvider.BuildCache(name, properties);
ccs.Cache = settings.CacheProvider.BuildCache(name, properties);
}
catch (CacheException e)
Copy link
Member Author

@fredericDelaporte fredericDelaporte Jun 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway I do not know of any cache implementation throwing this exception... Those from NHibernate-Caches never throw it.

@@ -134,13 +135,17 @@ public partial interface ICacheConcurrencyStrategy
/// </summary>
string RegionName { get; }

// 6.0 TODO: type as BaseCache instead
#pragma warning disable 618
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementors will be warned by the ICache obsolete message about that, but they will not be able to actually prepare for it. I do not see a way to avoid this. The HashtableCacheProvider.BuildCache implementation pattern commented previously is not usable here, as we may have a cache not deriving from CacheBase here.

// PreferMultipleGet yields false if !IBatchableCacheConcurrencyStrategy, no GetMany call should be done
// in such case.
return ReflectHelper
.CastOrThrow<IBatchableCacheConcurrencyStrategy>(cache, "batching")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This GetMany is currently called only in case of lazy batch fetches (using batch-size). The cases where NHibernate calls GetMany even if PreferMultipleGet is false do not use this GetMany.

var concreteCache = cache.Cache;
if (concreteCache == null)
return null;
return concreteCache as CacheBase ?? new ObsoleteCacheWrapper(concreteCache);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows a simplification, by always yielding a CacheBase provided there is a cache, even if it does not implement itself CacheBase.
In most cases it will yield the wrapper held by the cache concurrency, avoiding the instantiation here. (The instantiation will occur only if the user uses a custom cache concurrency, which looks very unlikely to me, since the mapping does not allow specifying a custom implementation.)

try
{
cache.Lock(key);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The finally is done for unlocking, but there is nothing to unlock if the locking has failed. This line should have been before the try, even without having the lockValue to handle. All similar cases have been changed likewise.

/// <exception cref="CacheException"></exception>
bool[] PutMany(CacheKey[] keys, object[] values, long timestamp, object[] versions, IComparer[] versionComparers,
bool[] minimalPuts);

// 6.0 TODO: remove for using ICacheConcurrencyStrategy.Cache re-typed CacheBase instead
CacheBase CacheBase { get; }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can change this interface as it is not yet released.

This property is somewhat obsolete as soon as added. But it should not bother many implementors, since mapping does not allow to specify custom cache concurrency implementations.

@fredericDelaporte

This comment has been minimized.

@fredericDelaporte
Copy link
Member Author

Rebased and squashed.

@hazzik
Copy link
Member

hazzik commented Jul 7, 2018

One note: the XXXBase pattern is not found anywhere in the code base. Instead NH is tend to use Java borrowed pattern of AbstractXXX, not sure what I do prefer though.

@fredericDelaporte
Copy link
Member Author

One note: the XXXBase pattern is not found anywhere in the code base. Instead NH is tend to use Java borrowed pattern of AbstractXXX, not sure what I do prefer though.

83 matches for class Abstract in NHibernate project, 24 for class [a-zA-Z0-9_]+Base[^a-zA-Z0-9_]. So the Java pattern clearly dominates, but the .Net one is already there for around 20% of cases.

For the cache case, I dislike a bit both patterns indeed. I thought of naming it just Cache. After all DbCommand does not include Base in its name either. But the Db ones are well known classes. The purpose of a Cache class would be less obvious. So I have kept the Base suffix.

@fredericDelaporte
Copy link
Member Author

Squashed and rebased for resolving conflicts with #1788.

@fredericDelaporte
Copy link
Member Author

Rebased, and one additional adjustment suggested by @hazzik has been made.

As proposed on the development group, and since no continued grounded disagreement has been expressed there since one week after raised concerns being addressed, I intend to merge this PR next week (likely on Wednesday).

(I am issuing this notice on PR issued before starting to apply this handling of merges. I will not do it for new PR.)

@fredericDelaporte fredericDelaporte merged commit 6fedcb6 into nhibernate:master Oct 31, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants