@@ -23,6 +23,47 @@ package kotlinx.io
2323import kotlin.jvm.JvmField
2424import kotlin.jvm.JvmSynthetic
2525
26+ /* *
27+ * Tracks shared segment copies.
28+ *
29+ * A new [SegmentCopyTracker] instance should be not shared by default (i.e. `shared == false`).
30+ * Any further [addCopy] calls should move the tracker to a shared state (i.e. `shared == true`).
31+ * Once a shared segment copy is recycled, [removeCopy] should be called.
32+ * Depending on implementation, calling [removeCopy] the same number of times as [addCopy] may
33+ * or may not transition the tracked back to unshared stated.
34+ *
35+ * The class is not intended for public use and currently designed to fit the only use case - within JVM SegmentPool
36+ * implementation.
37+ */
38+ internal abstract class SegmentCopyTracker {
39+ /* *
40+ * `true` if a tracker shared by multiple segment copies.
41+ */
42+ abstract val shared: Boolean
43+
44+ /* *
45+ * Track a new copy created by sharing an associated segment.
46+ */
47+ abstract fun addCopy ()
48+
49+ /* *
50+ * Records reclamation of a shared segment copy associated with this tracker.
51+ * If a tracker was in unshared state, this call should not affect an internal state.
52+ *
53+ * @return `true` if the segment was not shared *before* this called.
54+ */
55+ abstract fun removeCopy (): Boolean
56+ }
57+
58+ /* *
59+ * Simple [SegmentCopyTracker] that always reports shared state.
60+ */
61+ internal object AlwaysSharedCopyTracker : SegmentCopyTracker() {
62+ override val shared: Boolean = true
63+ override fun addCopy () = Unit
64+ override fun removeCopy (): Boolean = true
65+ }
66+
2667/* *
2768 * A segment of a buffer.
2869 *
@@ -59,8 +100,17 @@ public class Segment {
59100 internal var limit: Int = 0
60101
61102 /* * True if other segments or byte strings use the same byte array. */
62- @JvmField
63- internal var shared: Boolean = false
103+ internal val shared: Boolean
104+ get() = copyTracker?.shared ? : false
105+
106+ /* *
107+ * Tracks number shared copies
108+ *
109+ * Note that this reference is not `@Volatile` as segments are not thread-safe and it's an error
110+ * to modify the same segment concurrently.
111+ * At the same time, an object [copyTracker] refers to could be modified concurrently.
112+ */
113+ internal var copyTracker: SegmentCopyTracker ? = null
64114
65115 /* * True if this segment owns the byte array and can append to it, extending `limit`. */
66116 @JvmField
@@ -81,14 +131,14 @@ public class Segment {
81131 private constructor () {
82132 this .data = ByteArray (SIZE )
83133 this .owner = true
84- this .shared = false
134+ this .copyTracker = null
85135 }
86136
87- private constructor (data: ByteArray , pos: Int , limit: Int , shared : Boolean , owner: Boolean ) {
137+ private constructor (data: ByteArray , pos: Int , limit: Int , shareToken : SegmentCopyTracker ? , owner: Boolean ) {
88138 this .data = data
89139 this .pos = pos
90140 this .limit = limit
91- this .shared = shared
141+ this .copyTracker = shareToken
92142 this .owner = owner
93143 }
94144
@@ -98,8 +148,10 @@ public class Segment {
98148 * prevents it from being pooled.
99149 */
100150 internal fun sharedCopy (): Segment {
101- shared = true
102- return Segment (data, pos, limit, true , false )
151+ val t = copyTracker ? : SegmentPool .tracker().also {
152+ copyTracker = it
153+ }
154+ return Segment (data, pos, limit, t.also { it.addCopy() }, false )
103155 }
104156
105157 /* *
@@ -284,8 +336,13 @@ public class Segment {
284336 internal fun new (): Segment = Segment ()
285337
286338 @JvmSynthetic
287- internal fun new (data : ByteArray , pos : Int , limit : Int , shared : Boolean , owner : Boolean ): Segment
288- = Segment (data, pos, limit, shared, owner)
339+ internal fun new (
340+ data : ByteArray ,
341+ pos : Int ,
342+ limit : Int ,
343+ copyTracker : SegmentCopyTracker ? ,
344+ owner : Boolean
345+ ): Segment = Segment (data, pos, limit, copyTracker, owner)
289346 }
290347}
291348
0 commit comments