示例#1
0
        public async Task CreateMissingTile(string tileDetail)
        {
            var cacheKey = GetCacheKey(tileDetail);
            var fileUid  = tileDetail.Split(new[] { DataOceanFileUtil.GENERATED_TILE_FOLDER_SUFFIX }, StringSplitOptions.None)[0];

            using (await MemCacheLock.LockAsync(cacheKey))
            {
                await _dataCache.GetOrCreate(cacheKey, async entry =>
                {
                    entry.SetOptions(_options);
                    return(new CacheItem <string>(cacheKey, new [] { fileUid }));
                });
            }
        }
示例#2
0
    /// <summary>
    ///   Execute statement with MemoryCache
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="uid">The uid.</param>
    /// <param name="userId">The user identifier.</param>
    /// <param name="cacheLifeKey">The cache life key.</param>
    /// <param name="customHeaders">The custom headers.</param>
    /// <param name="action">The action.</param>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException">
    ///   This method requires a cache; use the correct constructor
    ///   or
    ///   Incorrect expiration time parameter
    /// </exception>
    protected async Task<T> WithMemoryCacheExecute<T>(string uid, string userId, object cacheLifeKey, IHeaderDictionary customHeaders, Func<Task<T>> action, string uniqueIdCacheKey = null) where T : class, IMasterDataModel
    {
      if (_dataCache == null)
        throw new InvalidOperationException("This method requires a cache; use the correct constructor");

      if (string.IsNullOrEmpty(uid) && string.IsNullOrEmpty(userId))
      {
        log.LogWarning("Attempting to execute method with cache, but cannot generate a cache key - not caching the result.");
        var noCacheResult = await action.Invoke();
        if (noCacheResult != null)
          return noCacheResult;
      }
      else
      {
        var opts = new MemoryCacheEntryOptions();

        switch (cacheLifeKey)
        {
          case string s:
            opts.GetCacheOptions(s, configurationStore, log);
            break;
          case TimeSpan t:
            opts.SlidingExpiration = t;
            break;
          default:
            throw new InvalidOperationException("Incorrect expiration time parameter");
        }

        var keyPrefix = typeof(T).Name;
        var cacheKey = string.IsNullOrEmpty(userId) ? $"{keyPrefix} {uid}" : $"{keyPrefix} {uid} {userId}";
        // Allow for extra cache keys, eg page 1 or 2 would need a separate key 
        if (!string.IsNullOrEmpty(uniqueIdCacheKey))
          cacheKey = $"{cacheKey} {uniqueIdCacheKey}";

        T result = default;

        using (await _memCacheLock.LockAsync(cacheKey))
        {
          if (!IfCacheNeedsToBeInvalidated(customHeaders))
          {
            return await _dataCache.GetOrCreate(cacheKey, async entry =>
            {
              log.LogDebug($"{nameof(WithMemoryCacheExecute)}: Item for key {cacheKey} not found in cache, getting from web api");
              result = await action.Invoke();
              if (result != null)
              {
                entry.SetOptions(opts);
                // We need to support clearing cache by the user - the model doesn't know about the user info
                var identifiers = result.GetIdentifiers() ?? new List<string>();
                if (!string.IsNullOrEmpty(uid))
                  identifiers.Add(uid);
                if (!string.IsNullOrEmpty(userId))
                  identifiers.Add(userId);
                return new CacheItem<T>(result, identifiers);
              }

              throw new ServiceException(HttpStatusCode.BadRequest,
                new ContractExecutionResult(ContractExecutionStatesEnum.FailedToGetResults,
                  "Unable to request data from a webapi"));
            });
          }

          log.LogDebug($"{nameof(WithMemoryCacheExecute)}: Item for key {cacheKey} is requested to be invalidated, getting from web api");
          result = await action.Invoke();
          if (result != null)
          {
            // We need to support clearing cache by the user - the model doesn't know about the user info
            var identifiers = result.GetIdentifiers() ?? new List<string>();
            if (!string.IsNullOrEmpty(uid))
              identifiers.Add(uid);
            if (!string.IsNullOrEmpty(userId))
              identifiers.Add(userId);
            return _dataCache.Set(cacheKey, result, identifiers, opts);
          }
        }
      }

      throw new ServiceException(HttpStatusCode.BadRequest,
          new ContractExecutionResult(ContractExecutionStatesEnum.FailedToGetResults,
            "Unable to request data from a webapi"));
    }
示例#3
0
        /// <summary>
        /// Gets the elevation statistics for the given filter from Raptor
        /// </summary>
        /// <param name="projectId">Legacy project ID</param>
        /// <param name="filter">Compaction filter</param>
        /// <param name="projectSettings">Project settings</param>
        /// <returns>Elevation statistics</returns>
        public async Task <ElevationStatisticsResult> GetElevationRange(long projectId, Guid projectUid, FilterResult filter,
                                                                        CompactionProjectSettings projectSettings, IHeaderDictionary customHeaders, string userId)
        {
            const double NO_ELEVATION = 10000000000.0;

            var cacheKey  = ElevationCacheKey(projectUid, filter);
            var strFilter = filter != null?JsonConvert.SerializeObject(filter) : "";

            var opts = new MemoryCacheEntryOptions().GetCacheOptions(elevationExtentsCacheLifeKey, configStore, log);

            // User Story: 88271 - when the UI makes calls requiring elevation, we can bombard Raptor with duplicate calls to retrieve elevation
            // This can cause raptor to take longer than expected to query the same data over and over again.
            // This only ever happens when there is no cached item here, as once the item is cached for a given filter the cached item is returned.
            // To fix this, we will lock per cache key here, so only one call can be made to raptor, blocking all other calls requesting the same info until the cache item is ready
            // Overall the call time should not change for any request, however the number of calls will be reduced to 1 for each unique projectid / filter.
            ElevationStatisticsResult resultElevationStatisticsResult = null;

            using (await memCacheLock.LockAsync(cacheKey))
            {
                resultElevationStatisticsResult = await elevationExtentsCache.GetOrCreate(cacheKey, async entry =>
                {
                    ElevationStatisticsResult result;
                    entry.SetOptions(opts);

                    var projectStatisticsResult = await ProjectStatisticsHelper.GetProjectStatisticsWithProjectSsExclusions(projectUid, projectId, userId, customHeaders);

                    if (projectStatisticsResult?.extents != null)
                    {
                        var extents = projectStatisticsResult.extents;

                        result = new ElevationStatisticsResult
                                 (
                            new BoundingBox3DGrid(extents.MinX, extents.MinY, extents.MinZ, extents.MaxX, extents.MaxY, extents.MaxZ),
                            extents.MinZ,
                            extents.MaxZ,
                            0.0
                                 );
                    }
                    else
                    {
                        result = new ElevationStatisticsResult(null, 0.0, 0.0, 0.0);
                    }

                    //Check for 'No elevation range' result
                    if (Math.Abs(result.MinElevation - NO_ELEVATION) < 0.001 &&
                        Math.Abs(result.MaxElevation + NO_ELEVATION) < 0.001)
                    {
                        result = null;
                    }

                    // We need to tag the result as this filter and project for cache invalidation
                    var identifiers = new List <string> {
                        projectUid.ToString()
                    };
                    if (filter?.Uid != null)
                    {
                        identifiers.Add(filter.Uid.Value.ToString());
                    }

                    log.LogDebug($"Done elevation request");
                    return(new CacheItem <ElevationStatisticsResult>(result, identifiers));
                });
            }

            return(resultElevationStatisticsResult);
        }