service.cs

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;

namespace ZLocation
{
    [ServiceContract()]
    public interface IService
    {
        [OperationContract()]
        void Add(string path, double weight);

        [OperationContract()]
        void Remove(string path);

        [OperationContract()]
        IEnumerable<KeyValuePair<string, double>> Get();

        [OperationContract()]
        void Noop();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class Service : IService
    {
        private ConcurrentDictionary<string, double> _data;
        private string _backupFileFullPath;
        private readonly TimeSpan _backupThreshold;
        private DateTime _lastBackupTime;


        /// <summary>
        /// Create the Service with backup threshold time 1 sec.
        /// </summary>
        /// <param name="backupFileFullPath"></param>
        public Service(string backupFileFullPath)
            : this(backupFileFullPath, TimeSpan.FromSeconds(1))
        {
        }

        public Service(string backupFileFullPath, TimeSpan backupThreshold)
        {
            this._backupFileFullPath = backupFileFullPath;
            this._backupThreshold = backupThreshold;
            this._data = new ConcurrentDictionary<string, double>(StringComparer.OrdinalIgnoreCase);
            if (File.Exists(_backupFileFullPath))
            {
                foreach (var line in File.ReadAllLines(_backupFileFullPath))
                {
                    var items = line.Split('\t');
                    double weight;
                    if (items.Length == 2 && Double.TryParse(items[1], out weight))
                    {
                        _data[items[0]] = weight;
                    }
                }
            }
            _lastBackupTime = DateTime.Now;
        }

        public void Add(string path, double weight)
        {
            double oldWeight = 0;
            _data.TryGetValue(path, out oldWeight);
            _data[path] = oldWeight + weight;
            this.Backup();
        }

        public void Remove(string path)
        {
            double oldWeight = 0;
            _data.TryRemove(path, out oldWeight);
            this.Backup();
        }

        private void Backup()
        {
            if (DateTime.Now.Subtract(_lastBackupTime).CompareTo(_backupThreshold) > 0)
            {
                var lines = _data.Select(pair => pair.Key + "\t" + pair.Value);
                File.WriteAllLines(_backupFileFullPath, lines);
                _lastBackupTime = DateTime.Now;
            }
        }

        public IEnumerable<KeyValuePair<string, double>> Get()
        {
            return _data.ToArray();
        }

        public void Noop()
        {
        }
    }
}