Skip to content

Commit 425c462

Browse files
committed
Store progress so-far, deleted-item-accessing appears to be resolved (Only occurred on rare, very specific occasions, needs time and testing)
1 parent ba8ec05 commit 425c462

20 files changed

+4363
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
build
2+
BeefSpace_User.toml
3+
recovery

BeefProj.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FileVersion = 1
2+
3+
[Project]
4+
Name = "System.Caching"
5+
TargetType = "BeefLib"
6+
StartupObject = "System.Caching.Program"

BeefSpace.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FileVersion = 1
2+
Projects = {"System.Caching" = {Path = "."}, test_app = {Path = "./_test_app"}}
3+
4+
[Workspace]
5+
StartupProject = "test_app"

_test_app/BeefProj.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FileVersion = 1
2+
Dependencies = {corlib = "*", "System.Caching" = "*"}
3+
4+
[Project]
5+
Name = "test_app"
6+
StartupObject = "test_app.Program"

_test_app/src/Program.bf

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
using System;
2+
using System.Caching;
3+
using System.Caching.Timer;
4+
using System.Diagnostics;
5+
using System.Threading;
6+
7+
namespace test_app
8+
{
9+
class Program
10+
{
11+
private const int CCacheTimeMilliseconds = 1000;
12+
13+
private static int _iterations = 1;
14+
private static int _cahedItem = 0;
15+
private static int _prevCahedItem = 0;
16+
private static bool _needsUpdate = false;
17+
private static readonly Stopwatch _sw = new Stopwatch() ~ delete _;
18+
private static readonly MemoryCache _memCache = MemoryCache.Default ~ _.Dispose();
19+
private static readonly CacheItemPolicy _policy = new .() {
20+
RemovedCallback = new => CacheItemPolicy_RemovedCallback
21+
} ~ delete _;
22+
private static Object _object = new Object() ~ delete _;
23+
private static String _tmpStr = new String() ~ delete _;
24+
25+
static void Main()
26+
{
27+
_sw.Start();
28+
using (PeriodicCallback timer = new PeriodicCallback(new => DoStuff, TimeSpan(0, 0, 2))) {
29+
while (true) {
30+
Thread.Sleep(100);
31+
32+
/*
33+
if (_needsUpdate) {
34+
timer.UpdateInterval(TimeSpan(0, 0, 3));
35+
_needsUpdate = false;
36+
}
37+
*/
38+
}
39+
}
40+
}
41+
42+
private static void DoStuff(PeriodicCallback caller)
43+
{
44+
/*
45+
_sw.Stop();
46+
Console.Out.WriteLine(scope $"This is DoStuff iteration: {_iterations}\nElapsed ms: {_sw.ElapsedMilliseconds}");
47+
*/
48+
49+
if (_iterations % 5 == 0) {
50+
_policy.AbsoluteExpiration = DateTimeOffset.Now.AddMilliseconds(CCacheTimeMilliseconds);
51+
// Only add if it is not there already (swallow others)
52+
_tmpStr.Clear();
53+
_cahedItem.ToString(_tmpStr);
54+
_memCache.AddOrGetExisting("Timer Update", _tmpStr, _policy);
55+
_cahedItem++;
56+
}
57+
58+
/*
59+
if (_iterations == 5)
60+
_needsUpdate = true;
61+
62+
_sw.Restart();
63+
*/
64+
_iterations++;
65+
}
66+
67+
private static void CacheItemPolicy_RemovedCallback(CacheEntryRemovedArguments args)
68+
{
69+
int itemNo = TrySilent!(Int.Parse((String)args.CacheItem.Value));
70+
Console.Out.WriteLine(scope $"\nItem is removed from the cache\nReason: {args.RemovedReason}\nItem# {itemNo}\n");
71+
72+
if (itemNo - _prevCahedItem > 1)
73+
Runtime.FatalError("We missed a cache item");
74+
75+
_prevCahedItem = itemNo;
76+
}
77+
}
78+
}

src/CacheEntry.bf

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// This file contains portions of code released by Microsoft under the MIT license as part
2+
// of an open-sourcing initiative in 2014 of the C# core libraries.
3+
// The original source was submitted to https://github.com/Microsoft/referencesource
4+
5+
using System.Collections;
6+
7+
namespace System.Caching
8+
{
9+
public enum CacheEntryRemovedReason
10+
{
11+
Removed = 0, // Explicitly removed via API call
12+
Expired,
13+
Evicted, // Evicted to free up space
14+
ChangeMonitorChanged, // An associated programmatic dependency triggered eviction
15+
CacheSpecificEviction // Catch-all for custom providers
16+
}
17+
18+
public delegate void CacheEntryRemovedCallback(CacheEntryRemovedArguments arguments);
19+
20+
public delegate void CacheEntryUpdateCallback(CacheEntryUpdateArguments arguments);
21+
22+
public class CacheEntryRemovedArguments
23+
{
24+
private CacheItem _cacheItem ~ delete _; // Needs to be deleted here
25+
private ObjectCache _source;
26+
private CacheEntryRemovedReason _reason;
27+
28+
public CacheItem CacheItem
29+
{
30+
get { return _cacheItem; }
31+
}
32+
33+
public CacheEntryRemovedReason RemovedReason
34+
{
35+
get { return _reason; }
36+
}
37+
38+
public ObjectCache Source
39+
{
40+
get { return _source; }
41+
}
42+
43+
public this(ObjectCache source, CacheEntryRemovedReason reason, CacheItem cacheItem)
44+
{
45+
Runtime.Assert(source != null && cacheItem != null);
46+
_source = source;
47+
_reason = reason;
48+
_cacheItem = cacheItem;
49+
}
50+
}
51+
52+
public class CacheEntryUpdateArguments
53+
{
54+
private String _key;
55+
private CacheEntryRemovedReason _reason;
56+
private ObjectCache _source;
57+
private CacheItem _updatedCacheItem;
58+
private CacheItemPolicy _updatedCacheItemPolicy;
59+
60+
public String Key
61+
{
62+
get { return _key; }
63+
}
64+
65+
public CacheEntryRemovedReason RemovedReason
66+
{
67+
get { return _reason; }
68+
}
69+
70+
public ObjectCache Source
71+
{
72+
get { return _source; }
73+
}
74+
75+
public CacheItem UpdatedCacheItem
76+
{
77+
get { return _updatedCacheItem; }
78+
set { _updatedCacheItem = value; }
79+
}
80+
81+
public CacheItemPolicy UpdatedCacheItemPolicy
82+
{
83+
get { return _updatedCacheItemPolicy; }
84+
set { _updatedCacheItemPolicy = value; }
85+
}
86+
87+
public this(ObjectCache source, CacheEntryRemovedReason reason, String key)
88+
{
89+
Runtime.Assert(source != null && key != null);
90+
_source = source;
91+
_reason = reason;
92+
_key = key;
93+
}
94+
}
95+
96+
public abstract class CacheEntryChangeMonitor : ChangeMonitor
97+
{
98+
public abstract List<String> CacheKeys { get; }
99+
public abstract DateTimeOffset LastModified { get; }
100+
}
101+
}

src/CacheExpires.bf

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// This file contains portions of code released by Microsoft under the MIT license as part
2+
// of an open-sourcing initiative in 2014 of the C# core libraries.
3+
// The original source was submitted to https://github.com/Microsoft/referencesource
4+
5+
using System.Caching.Timer;
6+
using System.Threading;
7+
8+
namespace System.Caching
9+
{
10+
sealed class CacheExpires
11+
{
12+
public static readonly TimeSpan MIN_UPDATE_DELTA = TimeSpan(0, 0, 1);
13+
public static readonly TimeSpan MIN_FLUSH_INTERVAL = TimeSpan(0, 0, 1);
14+
public static readonly TimeSpan _tsPerBucket = TimeSpan(0, 0, 20);
15+
private const int NUMBUCKETS = 30;
16+
private static readonly TimeSpan s_tsPerCycle = TimeSpan(30L * _tsPerBucket.Ticks);
17+
private readonly MemoryCacheStore _cacheStore;
18+
private readonly ExpiresBucket[] _buckets = new .[30] ~ DeleteContainerAndItems!(_);
19+
private PeriodicCallback _timer = null ~ if (_ != null) delete _;
20+
private DateTime _utcLastFlush;
21+
private int _inFlush;
22+
23+
public this(MemoryCacheStore cacheStore)
24+
{
25+
DateTime utcNow = DateTime.UtcNow;
26+
_cacheStore = cacheStore;
27+
uint8 b = 0;
28+
29+
while ((int)b < _buckets.Count)
30+
{
31+
_buckets[(int)b] = new .(this, b, utcNow);
32+
b += 1;
33+
}
34+
}
35+
36+
private int UtcCalcExpiresBucket(DateTime utcDate) =>
37+
(int)(((utcDate.Ticks % s_tsPerCycle.Ticks) / _tsPerBucket.Ticks + 1L) % 30L);
38+
39+
private int FlushExpiredItems(bool checkDelta, bool useInsertBlock)
40+
{
41+
int flushedCount = 0;
42+
43+
if (Interlocked.Exchange(ref _inFlush, 1) == 0)
44+
{
45+
if (_timer == null)
46+
return 0;
47+
48+
DateTime utcNow = DateTime.UtcNow;
49+
50+
if (!checkDelta || (utcNow - _utcLastFlush) >= MIN_FLUSH_INTERVAL || utcNow < _utcLastFlush)
51+
{
52+
_utcLastFlush = utcNow;
53+
54+
for (ExpiresBucket expiresBucket in _buckets)
55+
flushedCount += expiresBucket.FlushExpiredItems(utcNow, useInsertBlock);
56+
}
57+
58+
Interlocked.Exchange(ref _inFlush, 0);
59+
}
60+
61+
return flushedCount;
62+
}
63+
64+
public int FlushExpiredItems(bool useInsertBlock) =>
65+
FlushExpiredItems(true, useInsertBlock);
66+
67+
private void TimerCallback(PeriodicCallback state) =>
68+
FlushExpiredItems(false, false);
69+
70+
public void EnableExpirationTimer(bool enable)
71+
{
72+
if (enable)
73+
{
74+
if (_timer == null)
75+
{
76+
DateTime utcNow = DateTime.UtcNow;
77+
TimeSpan timeSpan = _tsPerBucket - TimeSpan(utcNow.Ticks % _tsPerBucket.Ticks);
78+
_timer = new .(new => TimerCallback, timeSpan.Ticks / 10000L);
79+
return;
80+
}
81+
}
82+
else
83+
{
84+
PeriodicCallback timer = _timer;
85+
86+
if (timer != null && Interlocked.CompareExchange(ref _timer, null, timer) == timer)
87+
{
88+
timer.Dispose();
89+
90+
while (_inFlush != 0)
91+
Thread.Sleep(100);
92+
}
93+
}
94+
}
95+
96+
public MemoryCacheStore MemoryCacheStore
97+
{
98+
get { return _cacheStore; }
99+
}
100+
101+
public void Add(MemoryCacheEntry cacheEntry)
102+
{
103+
DateTime utcNow = DateTime.UtcNow;
104+
105+
if (utcNow > cacheEntry.UtcAbsExp)
106+
cacheEntry.UtcAbsExp = utcNow;
107+
108+
_buckets[UtcCalcExpiresBucket(cacheEntry.UtcAbsExp)].AddCacheEntry(cacheEntry);
109+
}
110+
111+
public void Remove(MemoryCacheEntry cacheEntry)
112+
{
113+
uint8 expiresBucket = cacheEntry.ExpiresBucket;
114+
115+
if (expiresBucket != 255)
116+
_buckets[(int)expiresBucket].RemoveCacheEntry(cacheEntry);
117+
}
118+
119+
public void UtcUpdate(MemoryCacheEntry cacheEntry, DateTime utcNewExpires)
120+
{
121+
int expiresBucket = (int)cacheEntry.ExpiresBucket;
122+
int bucketIdx = UtcCalcExpiresBucket(utcNewExpires);
123+
124+
if (expiresBucket != bucketIdx)
125+
{
126+
if (expiresBucket != 255)
127+
{
128+
_buckets[expiresBucket].RemoveCacheEntry(cacheEntry);
129+
cacheEntry.UtcAbsExp = utcNewExpires;
130+
_buckets[bucketIdx].AddCacheEntry(cacheEntry);
131+
return;
132+
}
133+
}
134+
else if (expiresBucket != 255)
135+
{
136+
_buckets[expiresBucket].UtcUpdateCacheEntry(cacheEntry, utcNewExpires);
137+
}
138+
}
139+
}
140+
}

0 commit comments

Comments
 (0)