Skip to content

Commit 5820ba6

Browse files
Delete meta-data of redeclared variables
1 parent db437cc commit 5820ba6

File tree

7 files changed

+57
-48
lines changed

7 files changed

+57
-48
lines changed

Diff for: src/main/kotlin/org/jetbrains/kotlinx/jupyter/repl.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,8 @@ class ReplForJupyterImpl(
402402

403403
val compiledData: SerializedCompiledScriptsData
404404
val newImports: List<String>
405+
val oldDeclarations: MutableMap<String, Int> = mutableMapOf()
406+
oldDeclarations.putAll(internalEvaluator.getVariablesDeclarationInfo())
405407
val result = try {
406408
log.debug("Current cell id: $jupyterId")
407409
executor.execute(code, displayHandler, currentCellId = jupyterId - 1) { internalId, codeToExecute ->
@@ -431,7 +433,7 @@ class ReplForJupyterImpl(
431433
// printVars()
432434
// printUsagesInfo(jupyterId, cellVariables[jupyterId - 1])
433435
val variablesCells: Map<String, Int> = notebook.variablesState.mapValues { internalEvaluator.findVariableCell(it.key) }
434-
val serializedData = variablesSerializer.serializeVariables(jupyterId - 1, notebook.variablesState, variablesCells, notebook.unchangedVariables())
436+
val serializedData = variablesSerializer.serializeVariables(jupyterId - 1, notebook.variablesState, oldDeclarations, variablesCells, notebook.unchangedVariables())
435437

436438
GlobalScope.launch(Dispatchers.Default) {
437439
variablesSerializer.tryValidateCache(jupyterId - 1, notebook.cellVariables)

Diff for: src/main/kotlin/org/jetbrains/kotlinx/jupyter/repl/InternalEvaluator.kt

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ interface InternalEvaluator {
3636
*/
3737
fun findVariableCell(variableName: String): Int
3838

39+
fun getVariablesDeclarationInfo(): Map<String, Int>
40+
3941
/**
4042
* Returns a set of unaffected variables after execution
4143
*/

Diff for: src/main/kotlin/org/jetbrains/kotlinx/jupyter/repl/impl/InternalEvaluatorImpl.kt

+2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ internal class InternalEvaluatorImpl(
5252
return variablesWatcher.findDeclarationAddress(variableName) ?: -1
5353
}
5454

55+
override fun getVariablesDeclarationInfo(): Map<String, Int> = variablesWatcher.variablesDeclarationInfo
56+
5557
override fun getUnchangedVariables(): Set<String> {
5658
return variablesWatcher.getUnchangedVariables()
5759
}

Diff for: src/main/kotlin/org/jetbrains/kotlinx/jupyter/serializationUtils.kt

+37-26
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@ class ProcessedSerializedVarsState(
5656
data class ProcessedDescriptorsState(
5757
val processedSerializedVarsToJavaProperties: MutableMap<SerializedVariablesState, PropertiesData?> = mutableMapOf(),
5858
val processedSerializedVarsToKTProperties: MutableMap<SerializedVariablesState, KPropertiesData?> = mutableMapOf(),
59-
val instancesPerState: MutableMap<SerializedVariablesState, Any?> = mutableMapOf(),
60-
val parent: ProcessedDescriptorsState? = null
59+
val instancesPerState: MutableMap<SerializedVariablesState, Any?> = mutableMapOf()
6160
)
6261

6362
data class RuntimeObjectWrapper(
@@ -73,6 +72,7 @@ data class RuntimeObjectWrapper(
7372
return objectInstance === other
7473
}
7574

75+
// TODO: it's not changing after recreation
7676
override fun hashCode(): Int {
7777
return if (isRecursive) Random.nextInt() else objectInstance?.hashCode() ?: 0
7878
}
@@ -93,7 +93,7 @@ fun Any?.getToStringValue(isRecursive: Boolean = false): String {
9393
}
9494

9595
fun Any?.getUniqueID(isRecursive: Boolean = false): String {
96-
return if (this != null) {
96+
return if (this != null && this !is Map.Entry<*, *>) {
9797
val hashCode = if (isRecursive) {
9898
Random.nextLong()
9999
} else {
@@ -197,8 +197,9 @@ class VariablesSerializer(
197197
val isRecursive = stringedValue.contains(": recursive structure")
198198
if (!isRecursive && simpleTypeName == "LinkedEntrySet") {
199199
getProperEntrySetRepresentation(value)
200-
} else
201-
value.getUniqueID(isRecursive)
200+
} else {
201+
value.getUniqueID(isRecursive)
202+
}
202203
} else {
203204
""
204205
}
@@ -285,12 +286,12 @@ class VariablesSerializer(
285286
}
286287

287288
/**
288-
* Map of Map of seen objects.
289-
* First Key: cellId
289+
* Map of Map of seen objects related to a particular variable serialization
290+
* First Key: topLevel variable Name
290291
* Second Key: actual value
291292
* Value: serialized VariableState
292293
*/
293-
private val seenObjectsPerCell: MutableMap<Int, MutableMap<RuntimeObjectWrapper, SerializedVariablesState>> = mutableMapOf()
294+
private val seenObjectsPerVariable: MutableMap<String, MutableMap<RuntimeObjectWrapper, SerializedVariablesState>> = mutableMapOf()
294295

295296
private var currentSerializeCount: Int = 0
296297

@@ -355,18 +356,19 @@ class VariablesSerializer(
355356

356357
override suspend fun clearStateInfo(currentState: Int) {
357358
computedDescriptorsPerCell.remove(currentState)
358-
seenObjectsPerCell.remove(currentState)
359+
// seenObjectsPerVariable.remove(currentState)
359360
}
360361

361362
suspend fun tryValidateCache(currentCellId: Int, cellVariables: Map<Int, Set<String>>) {
362363
if (!isShouldRemove(currentCellId)) return
363364
clearOldData(currentCellId, cellVariables)
364365
}
365366

366-
fun serializeVariables(cellId: Int, variablesState: Map<String, VariableState>, variablesCells: Map<String, Int>, unchangedVariables: Set<String>): Map<String, SerializedVariablesState> {
367+
fun serializeVariables(cellId: Int, variablesState: Map<String, VariableState>, oldDeclarations: Map<String, Int>, variablesCells: Map<String, Int>, unchangedVariables: Set<String>): Map<String, SerializedVariablesState> {
367368
fun removeNonExistingEntries() {
368369
val toRemoveSet = mutableSetOf<String>()
369370
serializedVariablesCache.forEach { (name, _) ->
371+
// seems like this never gonna happen
370372
if (!variablesState.containsKey(name)) {
371373
toRemoveSet.add(name)
372374
}
@@ -376,9 +378,6 @@ class VariablesSerializer(
376378

377379
if (!isSerializationActive) return emptyMap()
378380

379-
if (seenObjectsPerCell.containsKey(cellId)) {
380-
seenObjectsPerCell[cellId]!!.clear()
381-
}
382381
if (variablesState.isEmpty()) {
383382
return emptyMap()
384383
}
@@ -388,21 +387,26 @@ class VariablesSerializer(
388387
if (wasRedeclared) {
389388
removedFromSightVariables.remove(it)
390389
}
391-
// todo: might consider self-recursive elements always to recompute since it's non comparable via strings
390+
// TODO: might consider self-recursive elements always to recompute since it's non comparable via strings
392391
if (serializedVariablesCache.isEmpty()) {
393392
true
394-
} else
395-
(!unchangedVariables.contains(it) || serializedVariablesCache[it]?.value != variablesState[it]?.stringValue) &&
396-
!removedFromSightVariables.contains(it)
393+
} else {
394+
(!unchangedVariables.contains(it) || serializedVariablesCache[it]?.value != variablesState[it]?.stringValue) &&
395+
!removedFromSightVariables.contains(it)
396+
}
397397
}
398398
log.debug("Variables state as is: $variablesState")
399399
log.debug("Serializing variables after filter: $neededEntries")
400400
log.debug("Unchanged variables: ${unchangedVariables - neededEntries.keys}")
401401

402402
// remove previous data
403-
// computedDescriptorsPerCell[cellId]?.instancesPerState?.clear()
404403
val serializedData = neededEntries.mapValues {
405404
val actualCell = variablesCells[it.key] ?: cellId
405+
if (oldDeclarations.containsKey(it.key)) {
406+
val oldCell = oldDeclarations[it.key]!!
407+
computedDescriptorsPerCell[oldCell]?.remove(it.key)
408+
seenObjectsPerVariable.remove(it.key)
409+
}
406410
serializeVariableState(actualCell, it.key, it.value)
407411
}
408412

@@ -467,10 +471,13 @@ class VariablesSerializer(
467471
return doActualSerialization(cellId, topLevelName, processedData, wrapper, isRecursive, isOverride)
468472
}
469473

470-
private fun doActualSerialization(cellId: Int, topLevelName:String, processedData: ProcessedSerializedVarsState, value: RuntimeObjectWrapper, isRecursive: Boolean, isOverride: Boolean = true): SerializedVariablesState {
474+
private fun doActualSerialization(cellId: Int, topLevelName: String, processedData: ProcessedSerializedVarsState, value: RuntimeObjectWrapper, isRecursive: Boolean, isOverride: Boolean = true): SerializedVariablesState {
475+
fun checkIsNotStandardDescriptor(descriptor: MutableMap<String, SerializedVariablesState?>): Boolean {
476+
return descriptor.isNotEmpty() && !descriptor.containsKey("size") && !descriptor.containsKey("data")
477+
}
471478
val serializedVersion = processedData.serializedVariablesState
472479

473-
seenObjectsPerCell.putIfAbsent(cellId, mutableMapOf())
480+
seenObjectsPerVariable.putIfAbsent(topLevelName, mutableMapOf())
474481
computedDescriptorsPerCell.putIfAbsent(cellId, mutableMapOf())
475482

476483
if (isOverride) {
@@ -482,17 +489,21 @@ class VariablesSerializer(
482489
}
483490
val currentCellDescriptors = computedDescriptorsPerCell[cellId]?.get(topLevelName)
484491
// TODO should we stack?
492+
// i guess, not
485493
currentCellDescriptors!!.processedSerializedVarsToJavaProperties[serializedVersion] = processedData.propertiesData
486494
currentCellDescriptors.processedSerializedVarsToKTProperties[serializedVersion] = processedData.kPropertiesData
487495

488496
if (value.objectInstance != null) {
489-
seenObjectsPerCell[cellId]!!.putIfAbsent(value, serializedVersion)
497+
seenObjectsPerVariable[topLevelName]!!.putIfAbsent(value, serializedVersion)
490498
}
491499
if (serializedVersion.isContainer) {
492500
// check for seen
493-
if (seenObjectsPerCell[cellId]!!.containsKey(value)) {
494-
val previouslySerializedState = seenObjectsPerCell[cellId]!![value] ?: return processedData.serializedVariablesState
501+
if (seenObjectsPerVariable[topLevelName]!!.containsKey(value)) {
502+
val previouslySerializedState = seenObjectsPerVariable[topLevelName]!![value] ?: return processedData.serializedVariablesState
495503
serializedVersion.fieldDescriptor += previouslySerializedState.fieldDescriptor
504+
if (checkIsNotStandardDescriptor(serializedVersion.fieldDescriptor)) {
505+
return serializedVersion
506+
}
496507
}
497508
val type = processedData.propertiesType
498509
if (type == PropertiesType.KOTLIN) {
@@ -535,8 +546,8 @@ class VariablesSerializer(
535546

536547
val serializedIteration = mutableMapOf<String, ProcessedSerializedVarsState>()
537548

538-
seenObjectsPerCell.putIfAbsent(cellId, mutableMapOf())
539-
val seenObjectsPerCell = seenObjectsPerCell[cellId]
549+
seenObjectsPerVariable.putIfAbsent(topLevelName, mutableMapOf())
550+
val seenObjectsPerCell = seenObjectsPerVariable[topLevelName]
540551
val currentCellDescriptors = computedDescriptorsPerCell[cellId]!![topLevelName]!!
541552
// ok, it's a copy on the left for some reason
542553
val instancesPerState = currentCellDescriptors.instancesPerState
@@ -645,7 +656,7 @@ class VariablesSerializer(
645656
getSimpleTypeNameFrom(elem, value.objectInstance) ?: "null"
646657
}
647658
serializedIteration[name] = if (standardContainersUtilizer.isStandardType(simpleType)) {
648-
// todo might add isRecursive
659+
// TODO might add isRecursive
649660
standardContainersUtilizer.serializeContainer(simpleType, value.objectInstance, true)
650661
} else {
651662
createSerializeVariableState(name, simpleType, value)

Diff for: src/main/kotlin/org/jetbrains/kotlinx/jupyter/util.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class VariablesUsagesPerCellWatcher<K : Any, V : Any> {
8181
/**
8282
* Tells in which cell a variable was declared
8383
*/
84-
private val variablesDeclarationInfo: MutableMap<V, K> = mutableMapOf()
84+
val variablesDeclarationInfo: MutableMap<V, K> = mutableMapOf()
8585

8686
private val unchangedVariables: MutableSet<V> = mutableSetOf()
8787

Diff for: src/test/kotlin/org/jetbrains/kotlinx/jupyter/test/repl/ReplTests.kt

+8-20
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,7 @@ class ReplVarsTest : AbstractSingleReplTest() {
666666
""".trimIndent(),
667667
jupyterId = 1
668668
)
669-
val state = repl.notebook.cellVariables
669+
var state = repl.notebook.cellVariables
670670
assertTrue(state.isNotEmpty())
671671

672672
// f is not accessible from here
@@ -677,10 +677,10 @@ class ReplVarsTest : AbstractSingleReplTest() {
677677
""".trimIndent(),
678678
jupyterId = 2
679679
)
680+
state = repl.notebook.cellVariables
680681
assertTrue(state.isNotEmpty())
681-
682-
// TODO discuss if we really want "z", "f", "x"
683-
val setOfCell = setOf("z")
682+
// ignore primitive references precise check for Java > 8
683+
val setOfCell = setOf("z", "x")
684684
assertTrue(state.containsValue(setOfCell))
685685
}
686686

@@ -808,7 +808,7 @@ class ReplVarsTest : AbstractSingleReplTest() {
808808
jupyterId = 2
809809
).metadata.evaluatedVariablesState
810810
val innerList = res["l"]!!.fieldDescriptor["elementData"]!!.fieldDescriptor["data"]
811-
val newData = serializer.doIncrementalSerialization(0, "l","data", innerList!!)
811+
val newData = serializer.doIncrementalSerialization(0, "l", "data", innerList!!)
812812
assertTrue(newData.isContainer)
813813
assertTrue(newData.fieldDescriptor.size > 4)
814814
}
@@ -860,17 +860,6 @@ class ReplVarsTest : AbstractSingleReplTest() {
860860
var state = repl.notebook.unchangedVariables()
861861
assertEquals(3, state.size)
862862

863-
eval(
864-
"""
865-
private val x = "abcd"
866-
internal val z = 47
867-
""".trimIndent(),
868-
jupyterId = 2
869-
)
870-
state = repl.notebook.unchangedVariables()
871-
assertEquals(1, state.size)
872-
assertTrue(state.contains("f"))
873-
874863
eval(
875864
"""
876865
private val x = "abcd"
@@ -889,7 +878,7 @@ class ReplVarsTest : AbstractSingleReplTest() {
889878
jupyterId = 3
890879
)
891880
state = repl.notebook.unchangedVariables()
892-
assertEquals(2, state.size)
881+
assertEquals(1, state.size)
893882
}
894883
}
895884

@@ -924,7 +913,7 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
924913
assertEquals(listOf(1, 2, 3, 4).toString().substring(1, actualContainer.value!!.length + 1), actualContainer.value)
925914

926915
val serializer = repl.variablesSerializer
927-
val newData = serializer.doIncrementalSerialization(0, "x","data", actualContainer)
916+
val newData = serializer.doIncrementalSerialization(0, "x", "data", actualContainer)
928917
}
929918

930919
@Test
@@ -1382,8 +1371,7 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
13821371
"""
13831372
val x = listOf(1, 2, 3, 4)
13841373
""".trimIndent(),
1385-
jupyterId = 2
1374+
jupyterId = 2
13861375
).metadata.evaluatedVariablesState
1387-
val a = 1
13881376
}
13891377
}

Diff for: src/test/kotlin/org/jetbrains/kotlinx/jupyter/test/repl/TrackedCellExecutor.kt

+4
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ internal class MockedInternalEvaluator : TrackedInternalEvaluator {
6868
return -1
6969
}
7070

71+
override fun getVariablesDeclarationInfo(): Map<String, Int> {
72+
return variablesWatcher.variablesDeclarationInfo
73+
}
74+
7175
override fun getUnchangedVariables(): Set<String> {
7276
return variablesWatcher.getUnchangedVariables()
7377
}

0 commit comments

Comments
 (0)