From 1972a49b4159173d2d4e4dfc49864769f86d6200 Mon Sep 17 00:00:00 2001 From: Jim Borden Date: Fri, 27 Jul 2018 07:07:16 +0900 Subject: [PATCH] [CBSE-5347] Fixes long document expiration Closes #1029 --- src/Couchbase.Lite.Shared/Database.cs | 6 ++++- .../DocumentTest.cs | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Couchbase.Lite.Shared/Database.cs b/src/Couchbase.Lite.Shared/Database.cs index 03856b37e..030d65476 100644 --- a/src/Couchbase.Lite.Shared/Database.cs +++ b/src/Couchbase.Lite.Shared/Database.cs @@ -2175,7 +2175,11 @@ internal void SchedulePurgeExpired(TimeSpan delay) if (nextExpiration.HasValue) { var delta = (nextExpiration.Value - DateTime.UtcNow).Add(TimeSpan.FromSeconds(1)); var expirationTimeSpan = delta > delay ? delta : delay; - if (expirationTimeSpan.TotalSeconds <= Double.Epsilon) { + if (expirationTimeSpan.TotalMilliseconds >= UInt32.MaxValue) { + _expirePurgeTimer.Change(TimeSpan.FromMilliseconds(UInt32.MaxValue - 1), TimeSpan.FromMilliseconds(-1)); + Log.To.Database.I(Tag, "{0:F3} seconds is too far in the future to schedule a document expiration," + + " will run again at the maximum value of {0:F3} seconds", expirationTimeSpan.TotalSeconds, (UInt32.MaxValue - 1) / 1000); + } else if (expirationTimeSpan.TotalSeconds <= Double.Epsilon) { _expirePurgeTimer.Change(Timeout.Infinite, Timeout.Infinite); PurgeExpired(null); } else { diff --git a/src/Couchbase.Lite.Tests.Shared/DocumentTest.cs b/src/Couchbase.Lite.Tests.Shared/DocumentTest.cs index 957954ecb..56d3711c6 100644 --- a/src/Couchbase.Lite.Tests.Shared/DocumentTest.cs +++ b/src/Couchbase.Lite.Tests.Shared/DocumentTest.cs @@ -148,6 +148,33 @@ public void TestExpireDocument() Assert.IsTrue(Math.Abs((next.Value - future).TotalSeconds) < 1.0); } + [Category("issue/1029")] + [Test] + public void TestLongExpiration() + { + // Before the fix this would crash because timers cannot be scheduled so far + // in the future. Now the timer will fire early, do nothing and reschedule + // itself + var now = DateTime.UtcNow; + Trace.WriteLine($"Now is {now}"); + var doc = CreateDocumentWithProperties(database, new Dictionary { { "foo", 17 } }); + Assert.IsNull(doc.GetExpirationDate()); + database.RunInTransaction(() => + { + doc.ExpireAfter(TimeSpan.FromDays(60)); + return true; + }); + + var exp = doc.GetExpirationDate(); + Trace.WriteLine($"Doc expiration is {exp}"); + Assert.IsNotNull(exp); + Assert.IsTrue(Math.Abs((exp.Value - now).TotalDays - 60.0) < 1.0); + + var next = database.Storage.NextDocumentExpiry(); + Trace.WriteLine($"Next expiry at {next}"); + Assert.IsTrue(Math.Abs((next.Value - now).TotalDays - 60.0) < 1.0); + } + [Test] // #447 public void TestDocumentArraysMaintainOrder() {