https://kotlinlang.org logo
Title
m

MJegorovas

10/23/2020, 8:49 AM
Is
offset
variable in this method safe to use in multiple threads?
suspend fun InputStream.readByChunks(
    fileSize: Long,
    chunkSize: Int,
    block: suspend (bytes: ByteArray, offset: Long) -> Unit
) {
    var offset = 0L

    this.buffered().use { input ->
        while (offset != fileSize) {
            val buffer = if (offset + chunkSize < fileSize) {
                ByteArray(chunkSize)
            } else {
                ByteArray((fileSize - offset).toInt())
            }

            val read = input.read(buffer)
            block(buffer, offset)
            offset += read
        }
    }
}
Use case:
val semaphore = Semaphore(4)

fileInputStream.readByChunks(size, BYTE_SPLIT_SIZE_SERVER) { bytes, offset ->
    semaphore.acquire()
    launch(Dispatchers.Default) {
        val encryptedBytes = encrypt(bytes, password)
        val storeResult = server.storeFileContent(encryptedBytes, itemId, offset)
        if (storeResult.isError()) {
            // Cancel reading and report about unsuccessful operation
        }

        progress.updatePrimaryProgress()
        semaphore.release()
    }
}
Any other code improvement suggestions are welcome as well.
b

bezrukov

10/23/2020, 8:55 AM
yes offset is passed by value (so it's copied), if it's compiled as primitive. If it complied as Long object, it's safe as well because it's immutable.
m

MJegorovas

10/23/2020, 10:29 AM
@bezrukov Thank you!
Regarding the case above what would be the best way to stop the read operation from the use case below (from
storeResult.isError()
block)
e

ephemient

10/23/2020, 12:10 PM
if you defined it as
fun InputStream.chunks(): Flow<Chunk>
cold flow instead, you could stop collecting at any point