public void StringInterning() { var s = new ReusableStream(100); var strings = new[] { "cat", "deer", "snail", "dog", "frog", "human" }; const int max = 4; const string exclude = "frog"; foreach (var str in strings) { s.WriteString(str, false); } s.ResetForReading(); // we're not interning yet - make sure new strings were returned foreach (var str in strings) { var read = s.ReadString(false); Assert.AreEqual(str, read); Assert.AreNotSame(str, read); } s.ResetForReading(); var options = new StringSetOptions(); options.MaxEncodedSizeToLookupInSet = max; Assert.Throws <InvalidOperationException>(() => s.SetDefaultStringSetOptions(options)); var set = new StringSet(10); s.StringSet = set; s.SetDefaultStringSetOptions(options); s.StringSet = null; // should throw because no StringSet has been provided Assert.Throws <InvalidOperationException>(() => s.ReadString(false)); foreach (var str in strings) { if (str != exclude) { set.Add(str); } } s.StringSet = set; // read with interning (but no auto-interning) foreach (var str in strings) { var read = s.ReadString(false); Assert.AreEqual(str, read); if (str.Length <= max && str != exclude) { Assert.AreSame(str, read); } else { Assert.AreNotSame(str, read); } } // make sure the excluded string didn't get added to the set Assert.AreEqual(null, set.GetExistingString(exclude.ToCharArray(), 0, exclude.Length)); s.ResetForReading(); options.PerformDangerousAutoAddToSet = true; s.SetDefaultStringSetOptions(options); // read with auto-interning foreach (var str in strings) { var read = s.ReadString(false); Assert.AreEqual(str, read); if (str.Length <= max && str != exclude) { Assert.AreSame(str, read); } else { Assert.AreNotSame(str, read); } } // make sure the excluded string got added to the set Assert.AreEqual(exclude, set.GetExistingString(exclude.ToCharArray(), 0, exclude.Length)); }
/// <summary> /// Add datas /// </summary> /// <typeparam name="T">Data type</typeparam> /// <param name="query">Query condition</param> /// <param name="datas">Datas</param> protected virtual void AddCacheData <T>(QueryDataCallbackContext <T> queryDataCallbackContext) where T : BaseEntity <T>, new() { if (queryDataCallbackContext == null) { return; } #region Add cache data var datas = queryDataCallbackContext.Datas; List <CacheKey> dataPrimaryKeys = null; List <CacheKey> dataOtherKeys = null; List <CacheEntry> storeItems = new List <CacheEntry>(); Type entityType = typeof(T); string objectName = entityType.Name; var cacheObject = new CacheObject() { ObjectName = objectName }; int dataCount = 0; if (!datas.IsNullOrEmpty()) { dataPrimaryKeys = new List <CacheKey>(); dataOtherKeys = new List <CacheKey>(); var entityConfiguration = EntityManager.GetEntityConfiguration(entityType); if (entityConfiguration == null) { LogManager.LogError <DefaultDataCachePolicy>($"Entity :{entityType.FullName} configuration is null"); return; } //primary keys var primaryKeys = entityConfiguration.PrimaryKeys; if (primaryKeys.IsNullOrEmpty()) { LogManager.LogError <DefaultDataCachePolicy>($"Data type:{entityType.FullName} no primary key,unable to set cache data"); return; } //cache keys var cacheKeys = entityConfiguration.CacheKeys ?? new List <string>(0); cacheKeys = cacheKeys.Except(primaryKeys).ToList(); //cache prefix keys var cachePrefixKeys = entityConfiguration.CachePrefixKeys ?? new List <string>(0); foreach (var data in datas) { if (data == null) { continue; } dataCount++; bool keyValueSuccess = true; //expiration TimeSpan? dataExpirationValue = DataCacheManager.Configuration.GetExpiration(entityType); DateTimeOffset?dataExpirationTime = null; if (dataExpirationValue != null) { dataExpirationTime = DateTimeOffset.Now.Add(dataExpirationValue.Value).AddSeconds(randomSecondPrivider.TakeNextValues(1).FirstOrDefault()); } CacheExpiration dataExpiration = new CacheExpiration() { SlidingExpiration = false, AbsoluteExpiration = dataExpirationTime }; //prefix cache keys var dataPrefixKey = new CacheKey(); if (!cachePrefixKeys.IsNullOrEmpty()) { foreach (var preKey in cachePrefixKeys) { var preKeyVal = data.GetValue(preKey)?.ToString() ?? string.Empty; if (string.IsNullOrWhiteSpace(preKeyVal)) { LogManager.LogError <DefaultDataCachePolicy>($"Data type :{entityType.FullName},Identity value:{data.GetIdentityValue()},Cache prefix key:{preKey},value is null or empty,unable to set cache data"); keyValueSuccess = false; break; } dataPrefixKey.AddName(preKey, preKeyVal); } if (!keyValueSuccess) { continue; } } //primary data cache keys var dataCacheKey = new CacheKey(cacheObject, dataPrefixKey); foreach (string pk in primaryKeys) { var pkValue = data.GetValue(pk)?.ToString() ?? string.Empty; if (string.IsNullOrWhiteSpace(pkValue)) { LogManager.LogError <DefaultDataCachePolicy>($"Data type :{entityType.FullName},Identity value:{data.GetIdentityValue()},Primary key:{pk},value is null or empty,unable to set cache data"); keyValueSuccess = false; break; } dataCacheKey.AddName(pk, pkValue); } if (!keyValueSuccess) { continue; } string primaryFullCacheKey = dataCacheKey.GetActualKey(); if (primaryFullCacheKey.IsNullOrEmpty()) { continue; } dataPrimaryKeys.Add(primaryFullCacheKey); storeItems.Add(new CacheEntry() { Key = primaryFullCacheKey, Value = JsonSerializeHelper.ObjectToJson(data), Expiration = dataExpiration }); if (!cacheKeys.IsNullOrEmpty()) { foreach (string key in cacheKeys) { var otherCacheKey = new CacheKey(cacheObject, dataPrefixKey); var cacheKeyValue = data.GetValue(key)?.ToString() ?? string.Empty; if (string.IsNullOrWhiteSpace(cacheKeyValue)) { LogManager.LogError <DefaultDataCachePolicy>($"Data type :{entityType.FullName},Identity value:{data.GetIdentityValue()},Cache key:{key},value is null or empty,unable to set cache data"); keyValueSuccess = false; break; } otherCacheKey.AddName(key, cacheKeyValue?.ToString() ?? string.Empty); dataOtherKeys.Add(otherCacheKey); storeItems.Add(new CacheEntry() { Key = otherCacheKey.GetActualKey(), Value = primaryFullCacheKey, Expiration = dataExpiration }); } if (!keyValueSuccess) { continue; } } } } #endregion #region Null data int querySize = queryDataCallbackContext.Query?.QuerySize ?? 0; if (DataCacheManager.Configuration.EnableCacheNullData && (querySize < 1 || dataCount < querySize)) { IEnumerable <CacheKey> queryPrimaryKeys = queryDataCallbackContext.PrimaryCacheKeys; IEnumerable <CacheKey> queryOtherKeys = queryDataCallbackContext.OtherCacheKeys; string nullDataValue = JsonSerializeHelper.ObjectToJson <T>(null); TimeSpan? nullDataExpirationValue = DataCacheManager.Configuration.GetNullDataExpiration(entityType); DateTimeOffset?nullDataExpiration = null; if (nullDataExpirationValue != null) { nullDataExpiration = DateTimeOffset.Now.Add(nullDataExpirationValue.Value); } CacheExpiration nullDataExp = new CacheExpiration() { SlidingExpiration = false, AbsoluteExpiration = nullDataExpiration }; if (!queryPrimaryKeys.IsNullOrEmpty()) { if (!dataPrimaryKeys.IsNullOrEmpty()) { queryPrimaryKeys = queryPrimaryKeys.Except(dataPrimaryKeys); } foreach (var primaryKey in queryPrimaryKeys) { storeItems.Add(new CacheEntry() { Key = primaryKey.GetActualKey(), Value = nullDataValue, Expiration = nullDataExp }); } } if (!queryOtherKeys.IsNullOrEmpty()) { if (!dataOtherKeys.IsNullOrEmpty()) { queryOtherKeys = queryOtherKeys.Except(dataOtherKeys); } if (!queryOtherKeys.IsNullOrEmpty()) { storeItems.Add(new CacheEntry() { Key = DataCacheManager.Configuration.NullDataCacheKey, Value = nullDataValue, Expiration = nullDataExp }); foreach (var otherKey in queryOtherKeys) { storeItems.Add(new CacheEntry() { Key = otherKey, Value = DataCacheManager.Configuration.NullDataCacheKey, Expiration = nullDataExp }); } } } } #endregion StringSetOptions option = new StringSetOptions() { CacheObject = cacheObject, Items = storeItems, CommandFlags = CacheCommandFlags.FireAndForget }; var cacheResult = CacheManager.String.Set(option); if (cacheResult != null && !cacheResult.Responses.IsNullOrEmpty()) { foreach (var response in cacheResult.Responses) { if (!string.IsNullOrWhiteSpace(response?.Message)) { LogManager.LogInformation <DefaultDataCachePolicy>(response.Message); } } } }