Skip to content

Commit 4f85e22

Browse files
committed
Fix partitioned session window bug, where restoring from checkpoint triggers exception
1 parent dc69f56 commit 4f85e22

2 files changed

Lines changed: 99 additions & 1 deletion

File tree

Sources/Core/Microsoft.StreamProcessing/Operators/SessionWindow/PartitionedSessionWindowPipe.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,18 @@ protected override void UpdatePointers()
253253
var temp = new List<Tuple<TKey, long, TPartitionKey>>();
254254
while (this.lastDataTimeDictionary.Iterate(ref iter))
255255
{
256+
var partitionKey = this.getPartitionKey(this.lastDataTimeDictionary.entries[iter].key);
257+
256258
if (this.stateDictionary.entries[iter].value.Any())
257259
{
258260
temp.Add(Tuple.Create(
259261
this.lastDataTimeDictionary.entries[iter].key,
260-
Math.Min(this.lastDataTimeDictionary.entries[iter].value + this.sessionTimeout, this.windowEndTimeDictionary.entries[iter].value), this.getPartitionKey(this.lastDataTimeDictionary.entries[iter].key)));
262+
Math.Min(this.lastDataTimeDictionary.entries[iter].value + this.sessionTimeout, this.windowEndTimeDictionary.entries[iter].value),
263+
partitionKey));
264+
}
265+
else if (!this.orderedKeysDictionary.ContainsKey(partitionKey))
266+
{
267+
this.orderedKeysDictionary.Add(partitionKey, new LinkedList<TKey>());
261268
}
262269
}
263270
foreach (var item in temp.OrderBy(o => o.Item2))
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// *********************************************************************
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License
4+
// *********************************************************************
5+
using System;
6+
using System.Collections.Generic;
7+
using System.IO;
8+
using System.Linq;
9+
using System.Reactive.Linq;
10+
using System.Reactive.Subjects;
11+
using Microsoft.StreamProcessing;
12+
using Microsoft.VisualStudio.TestTools.UnitTesting;
13+
14+
namespace SimpleTesting
15+
{
16+
[TestClass]
17+
public class PartitionedStreamCheckpointTests : TestWithConfigSettingsWithoutMemoryLeakDetection
18+
{
19+
[TestMethod, TestCategory("Gated")]
20+
public void CheckpointPartitionedSessionWindow()
21+
{
22+
Config.DataBatchSize = 1;
23+
24+
var data = new PartitionedStreamEvent<int, double>[]
25+
{
26+
PartitionedStreamEvent.CreatePoint(0, 5, 1.0),
27+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 8),
28+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 11),
29+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 14),
30+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 17),
31+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 21),
32+
PartitionedStreamEvent.CreatePoint(0, 24, 1.0),
33+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 100),
34+
};
35+
36+
var expected = new PartitionedStreamEvent<int, double>[]
37+
{
38+
PartitionedStreamEvent.CreateStart(0, 5, 1.0),
39+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 8),
40+
PartitionedStreamEvent.CreateEnd(0, 9, 5, 1.0),
41+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 11),
42+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 14),
43+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 17),
44+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 21),
45+
PartitionedStreamEvent.CreateStart(0, 24, 1.0),
46+
PartitionedStreamEvent.CreateEnd(0, 28, 24, 1.0),
47+
PartitionedStreamEvent.CreatePunctuation<int, double>(0, 100),
48+
};
49+
50+
// This index represents after series of punctions and just before new data arrives
51+
const int checkpointIndex = 6;
52+
53+
var subject = new Subject<PartitionedStreamEvent<int, double>>();
54+
var output = new List<PartitionedStreamEvent<int, double>>();
55+
var process = CreateQueryContainerForPartitionedStream(subject, output);
56+
57+
for (int i = 0; i < data.Length; i++)
58+
{
59+
if (i == checkpointIndex)
60+
{
61+
using (var ms = new MemoryStream())
62+
{
63+
process.Checkpoint(ms);
64+
ms.Seek(0, SeekOrigin.Begin);
65+
66+
subject = new Subject<PartitionedStreamEvent<int, double>>();
67+
process = CreateQueryContainerForPartitionedStream(subject, output, ms);
68+
}
69+
}
70+
71+
subject.OnNext(data[i]);
72+
}
73+
74+
Assert.IsTrue(expected.SequenceEqual(output));
75+
}
76+
77+
private Process CreateQueryContainerForPartitionedStream(
78+
Subject<PartitionedStreamEvent<int, double>> subject,
79+
List<PartitionedStreamEvent<int, double>> output,
80+
Stream stream = null)
81+
{
82+
var qc = new QueryContainer();
83+
var input = qc.RegisterInput(subject);
84+
var streamableOutput = input.SessionTimeoutWindow(4, 5).Sum(o => o);
85+
var egress = qc.RegisterOutput(streamableOutput).ForEachAsync(o => output.Add(o));
86+
var process = qc.Restore(stream);
87+
88+
return process;
89+
}
90+
}
91+
}

0 commit comments

Comments
 (0)