@@ -15,20 +15,6 @@ base class Postponable {
15
15
fun perform(context: mutable Context): void;
16
16
}
17
17
18
- class ToWrite(
19
- dirName: DirName,
20
- key: Key,
21
- values: readonly Context ~> Array<File>,
22
- ) extends Postponable {
23
- //
24
- fun perform(context: mutable Context): void {
25
- context.unsafeMaybeGetEagerDir(this.dirName) match {
26
- | Some(dir) -> dir.writeArray(context, this.key, this.values(context))
27
- | _ -> void
28
- }
29
- }
30
- }
31
-
32
18
/*****************************************************************************/
33
19
/* Sessions. */
34
20
/*****************************************************************************/
@@ -233,6 +219,13 @@ value class Tick(value: Int) uses Orderable, Show {
233
219
234
220
class TickFile(value: Tick) extends File uses Orderable
235
221
222
+ /* Time refers to the creation time of a directory.
223
+ Context#time is increased using Context#timeStamp() when a directory is created.
224
+ It is stored in the last element of the TimeStack of the directory.
225
+
226
+ Times and TimeStacks are used to order directory updates.
227
+ Context#toUpdate is used as a priority queue.
228
+ */
236
229
value class Time(value: Int) uses Orderable, Show {
237
230
fun next(): this {
238
231
!this.value = genSym(this.value + 1);
@@ -248,7 +241,9 @@ value class Time(value: Int) uses Orderable, Show {
248
241
}
249
242
}
250
243
251
- class TimeStack private (private values: Array<Time>) uses Orderable {
244
+ class TimeStack private (
245
+ private values: /* Invariant: non-empty array */ Array<Time>,
246
+ ) uses Orderable {
252
247
static fun createInput(time: Time): this {
253
248
static(Array[time])
254
249
}
@@ -265,25 +260,14 @@ class TimeStack private (private values: Array<Time>) uses Orderable {
265
260
this
266
261
}
267
262
268
- fun negate(): this {
269
- !this.values = this.values.map(x -> -x);
270
- this
263
+ fun getLast(): Time {
264
+ this.values.last()
271
265
}
272
266
273
- fun maxMinus (): this {
274
- !this.values = this.values.map(x -> Time(Int::max - x.value) );
267
+ fun negate (): this {
268
+ !this.values = this.values.map(x -> -x );
275
269
this
276
270
}
277
-
278
- fun compare(other: TimeStack): Order {
279
- for (i in Range(0, this.values.size())) {
280
- if (i >= other.values.size()) return GT();
281
- cmp = this.values[i].compare(other.values[i]);
282
- if (cmp != EQ()) return cmp;
283
- };
284
- if (other.values.size() > this.values.size()) return LT();
285
- EQ()
286
- }
287
271
}
288
272
289
273
/*****************************************************************************/
@@ -341,7 +325,10 @@ mutable class Context private {
341
325
mutable globals: SortedMap<String, File> = SortedMap[],
342
326
private mutable persistents: SortedMap<String, File> = SortedMap[],
343
327
private mutable dirty: SortedMap<DirName, SortedSet<Key>> = SortedMap[],
344
- private mutable dirtyReaders: List<ArrowKey> = List[],
328
+ private mutable dirtyReaders: /* parentName => childName => keys */ SortedMap<
329
+ DirName,
330
+ SortedMap<DirName, SortedSet<Key>>,
331
+ > = SortedMap[],
345
332
mutable canReuse: CanReuse = CRIfMatch(),
346
333
private mutable arrowStack: List<(ArrowKey, TimeStack)> = List[],
347
334
private mutable lazyGets: SortedSet<Path> = SortedSet[],
@@ -352,7 +339,7 @@ mutable class Context private {
352
339
private mutable dirsWithSharedSubDirs: SortedSet<DirName> = SortedSet[],
353
340
private mutable sharedSubDirsRefCount: SortedMap<DirName, Int> = SortedMap[],
354
341
mutable writeChecker: ?(mutable WriteChecker) = None(),
355
- mutable purgeFrom: (mutable Context, Dir) ~> Tick = (ctx, _) ~>
342
+ mutable purgeFrom: (readonly Context, Dir) ~> Tick = (ctx, _) ~>
356
343
Tick(ctx.getTick().value - 1000),
357
344
mutable sourceOverride: ?Path = None(),
358
345
} {
@@ -559,11 +546,9 @@ mutable class Context private {
559
546
this.!newDirs = this.newDirs.add(preDirName);
560
547
time = this.timeStamp();
561
548
preDir = EagerDir::create{
562
- time,
563
549
input => false,
564
550
timeStack => TimeStack::createInput(time),
565
551
dirName => preDirName,
566
- totalSize => 0,
567
552
creator => this.currentArrow(),
568
553
};
569
554
dir.unsafeIterKeys((key, _time) -> {
@@ -573,8 +558,7 @@ mutable class Context private {
573
558
!preDir = preDir.writeEntry(this, source, source, key, values);
574
559
});
575
560
this.setDir(preDir);
576
- this.updateDirtyReaders(Path::dirTag(preDirName));
577
- this.setDir(preDir)
561
+ this.updateDirtyReaders(Path::dirTag(preDirName))
578
562
| Some(preDir) ->
579
563
(isReset, changes) = dir.getChangesAfter(this.tick.prev());
580
564
for (key in changes) {
@@ -612,7 +596,15 @@ mutable class Context private {
612
596
| None() -> continue
613
597
| Some(x) -> x
614
598
};
615
- this.!dirtyReaders = List.Cons(reader, this.dirtyReaders);
599
+ this.!dirtyReaders[reader.parentName] = {
600
+ map = this.dirtyReaders.maybeGet(reader.parentName).default(
601
+ SortedMap[],
602
+ );
603
+ map.set(
604
+ reader.childName,
605
+ map.maybeGet(reader.childName).default(SortedSet[]).set(reader.key),
606
+ )
607
+ };
616
608
time = if (reader.parentName == reader.childName) {
617
609
-child.getTimeStack()
618
610
} else {
@@ -697,53 +689,36 @@ mutable class Context private {
697
689
print_debug(`------------ UPDATE (TICK: ${this.tick}) ------------`);
698
690
};
699
691
700
- _ = this.timeStamp();
701
-
702
692
this.updateLazyGets();
703
693
704
- dirtyReaders = mutable Map<DirName, mutable Map<DirName, SortedSet<Key>>>[];
705
-
706
694
loop {
707
- for (reader in this.dirtyReaders) {
708
- if (!dirtyReaders.containsKey(reader.parentName)) {
709
- dirtyReaders![reader.parentName] = mutable Map[];
710
- };
711
-
712
- if (!dirtyReaders[reader.parentName].containsKey(reader.childName)) {
713
- dirtyReaders[reader.parentName]![reader.childName] = SortedSet[];
714
- };
715
- dirtyReaders[reader.parentName]![reader.childName] = dirtyReaders[
716
- reader.parentName,
717
- ][reader.childName].set(reader.key);
718
- };
719
- this.!dirtyReaders = List[];
720
- toUpdate = this.toUpdate.minimum();
721
- toUpdate match {
695
+ this.toUpdate.removeMin() match {
722
696
| None() ->
723
697
this.!dirty = SortedMap[];
724
- invariant( this.dirtyReaders.isEmpty()) ;
698
+ this.! dirtyReaders = SortedMap[] ;
725
699
withPostponables = this.checkPostponables();
726
700
withPre = this.updatePre();
727
701
withChanges = withPostponables || withPre;
728
702
this.!tick = this.tick.next();
729
703
break withChanges
730
- | Some((time , Arrow(parentName, childName))) ->
731
- this.!toUpdate = this. toUpdate.remove(time) ;
704
+ | Some((_time , Arrow(parentName, childName), toUpdate )) ->
705
+ this.!toUpdate = toUpdate;
732
706
this.unsafeMaybeGetDir(childName) match {
733
707
| None()
734
708
| Some(DeletedDir _) ->
735
709
void
736
- | Some(child @ LazyDir _) ->
737
- child.update(this, dirtyReaders.maybeGet(child.dirName))
710
+ | Some(dir @ LazyDir _) ->
711
+ invariant(parentName == childName);
712
+ dir.update(this, this.dirtyReaders.maybeGet(dir.dirName))
738
713
| Some(child @ EagerDir _) ->
739
714
parentMaps = child.parents.maybeGet(parentName) match {
740
715
| None() -> invariant_violation("Could not find parent")
741
716
| Some(f) -> f
742
717
};
743
718
EagerDir::update(
744
719
this,
745
- this.dirty,
746
- dirtyReaders,
720
+ this.dirty.maybeGet(parentName) ,
721
+ this. dirtyReaders.maybeGet(parentName) ,
747
722
parentName,
748
723
parentMaps,
749
724
child,
@@ -805,8 +780,7 @@ mutable class Context private {
805
780
};
806
781
if (producedAnyOutput) {
807
782
// then we need to produce a checkpoint for flushing and committing
808
- ourTime = this.tick.value.toString();
809
- writer.write(`:${ourTime}\n`);
783
+ writer.write(`:${this.tick}\n`);
810
784
writer.flush();
811
785
flushStdout();
812
786
};
@@ -886,6 +860,8 @@ mutable class Context private {
886
860
optOnDelete: ?Postponable = None(),
887
861
): EHandle<K, V> {
888
862
this.mkdirMulti(
863
+ convKey,
864
+ convValue,
889
865
dirName,
890
866
content.map(kv -> {
891
867
(key, value) = kv;
@@ -894,17 +870,18 @@ mutable class Context private {
894
870
ignoreIfExists,
895
871
optOnCreate,
896
872
optOnDelete,
897
- );
898
- EHandle(convKey, convValue, dirName)
873
+ )
899
874
}
900
875
901
- mutable fun mkdirMulti(
876
+ mutable fun mkdirMulti<K: Key, V: File>(
877
+ convKey: Key ~> K,
878
+ convValue: File ~> V,
902
879
dirName: DirName,
903
- content: Array<(Key , Array<File >)> = Array[],
880
+ content: Array<(K , Array<V >)> = Array[],
904
881
ignoreIfExists: Bool = false,
905
882
optOnCreate: ?Postponable = None(),
906
883
optOnDelete: ?Postponable = None(),
907
- ): void {
884
+ ): EHandle<K, V> {
908
885
this.unsafeMaybeGetEagerDir(dirName) match {
909
886
| Some(dir) ->
910
887
if (dir.creator != this.currentArrow()) {
@@ -913,7 +890,7 @@ mutable class Context private {
913
890
throw DirAlreadyExists(dirName);
914
891
} else if (ignoreIfExists) {
915
892
this.!newDirs = this.newDirs.add(dirName);
916
- return void
893
+ return EHandle(convKey, convValue, dirName)
917
894
}
918
895
| _ -> void
919
896
};
@@ -929,8 +906,7 @@ mutable class Context private {
929
906
}
930
907
});
931
908
932
- vector: mutable Vector<FixedRow<Array<File>>> = mutable Vector[];
933
- time = this.timeStamp();
909
+ vector: mutable Vector<FixedRow<Array<V>>> = mutable Vector[];
934
910
935
911
n = content.size();
936
912
if (n > 0) {
@@ -954,21 +930,20 @@ mutable class Context private {
954
930
};
955
931
fixedData = FixedDataMap::create(vector);
956
932
957
- totalSize = fixedData.data.size();
958
933
creator = this.currentArrow();
934
+ time = this.timeStamp();
959
935
dir = EagerDir::create{
960
- time,
961
936
timeStack => TimeStack::create(this, time),
962
937
input => true,
963
938
dirName,
964
939
fixedData,
965
- totalSize,
966
940
creator,
967
941
optOnDelete,
968
942
};
969
943
this.setDir(dir);
970
944
this.!newDirs = this.newDirs.add(dirName);
971
- optOnCreate.each(this.postpone)
945
+ optOnCreate.each(this.postpone);
946
+ EHandle(convKey, convValue, dirName)
972
947
}
973
948
974
949
mutable fun setDir(dir: Dir): void {
@@ -981,6 +956,15 @@ mutable class Context private {
981
956
this.dirs.get(dirName);
982
957
}
983
958
959
+ mutable fun maybeGetDir<T: File>(dirName: DirName): ?Dir {
960
+ this.addRead(Path::dirTag(dirName));
961
+ this.dirs.maybeGet(dirName);
962
+ }
963
+
964
+ readonly fun unsafeMaybeGetDir<T: File>(dirName: DirName): ?Dir {
965
+ this.dirs.maybeGet(dirName);
966
+ }
967
+
984
968
readonly fun unsafeGetDir(dirName: DirName): Dir {
985
969
this.dirs.get(dirName);
986
970
}
@@ -1045,7 +1029,7 @@ mutable class Context private {
1045
1029
1046
1030
mutable fun removeDir(dirName: DirName): void {
1047
1031
if (this.debugMode) {
1048
- print_debug(" REMOVED: " + dirName);
1032
+ print_debug(` REMOVED: ${ dirName}` );
1049
1033
};
1050
1034
this.unsafeMaybeGetEagerDir(dirName) match {
1051
1035
| None() -> void
@@ -1082,15 +1066,6 @@ mutable class Context private {
1082
1066
}
1083
1067
}
1084
1068
1085
- mutable fun maybeGetDir<T: File>(dirName: DirName): ?Dir {
1086
- this.addRead(Path::dirTag(dirName));
1087
- this.dirs.maybeGet(dirName);
1088
- }
1089
-
1090
- readonly fun unsafeMaybeGetDir<T: File>(dirName: DirName): ?Dir {
1091
- this.dirs.maybeGet(dirName);
1092
- }
1093
-
1094
1069
mutable fun addRead(path: Path): void {
1095
1070
this.!reads = this.reads.set(path);
1096
1071
}
@@ -1157,7 +1132,7 @@ private class Dirs{private state: DMap<DirName, Dir> = DMap::empty()} {
1157
1132
this.maybeGet(key) match {
1158
1133
| None() ->
1159
1134
// printBacktrace();
1160
- invariant_violation(" Directory not found: " + key)
1135
+ invariant_violation(` Directory not found: ${ key}` )
1161
1136
| Some(x) -> x
1162
1137
}
1163
1138
}
@@ -1205,15 +1180,11 @@ fun import(
1205
1180
targetCtx.setDir(dir);
1206
1181
}
1207
1182
| Some(inputDir) ->
1208
- ! inputDir = inputDir.writeArraySourceManyReturnDir (
1183
+ inputDir.writeArraySourceMany (
1209
1184
targetCtx,
1210
1185
entries.iterator(),
1211
- );
1212
- if (isReset) {
1213
- writerPath = Path::gen(dir.dirName);
1214
- !inputDir = inputDir.reset(targetCtx, writerPath, changedKeys);
1215
- };
1216
- targetCtx.setDir(inputDir)
1186
+ if (isReset) Some((dir.dirName, changedKeys)) else None(),
1187
+ )
1217
1188
}
1218
1189
| Some(_) -> invariant_violation("Error import: incompatible dir types")
1219
1190
}
0 commit comments