Skip to content

Commit b38011b

Browse files
committed
feat: improve write performance and update benckmark
1 parent 440e848 commit b38011b

File tree

3 files changed

+59
-14
lines changed

3 files changed

+59
-14
lines changed

README.md

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -256,14 +256,43 @@ puffer.apply {
256256

257257
## Benchmark
258258

259+
### Write & Read
259260
| | Write 1k strings (ms) | Read 1k strings (ms) |
260261
|-------------------|-----------------------|----------------------|
261-
| **PufferDB** | **28** | **9** |
262-
| [SharedPreferences](https://developer.android.com/training/data-storage/shared-preferences) | 291 | 14 |
263-
| [MMKV](https://github.com/Tencent/MMKV) | 16 | 10 |
264-
| [Paper](https://github.com/pilgr/Paper) | 780 | 170 |
265-
| [Binary Prefs](https://github.com/yandextaxitech/binaryprefs) | 65 | 9 |
266-
| [Hawk](https://github.com/orhanobut/hawk) | 12053 | 192 |
262+
| **PufferDB** | **20** | **5** |
263+
| [SharedPreferences](https://developer.android.com/training/data-storage/shared-preferences) | 278 | 7 |
264+
| [MMKV](https://github.com/Tencent/MMKV) | 13 | 8 |
265+
| [Paper](https://github.com/pilgr/Paper) | 818 | 169 |
266+
| [Binary Prefs](https://github.com/yandextaxitech/binaryprefs) | 121 | 9 |
267+
| [Hawk](https://github.com/orhanobut/hawk) | 15183 | 207 |
268+
269+
| | Write 100k strings (ms) | Read 100k strings (ms) |
270+
|-------------------|-----------------------|----------------------|
271+
| **PufferDB** | **259** | **32** |
272+
| [SharedPreferences](https://developer.android.com/training/data-storage/shared-preferences) | 💥 | 💥 |
273+
| [MMKV](https://github.com/Tencent/MMKV) | 871 | 516 |
274+
| [Paper](https://github.com/pilgr/Paper) | 💥 | 💥 |
275+
| [Binary Prefs](https://github.com/yandextaxitech/binaryprefs) | 1082 | 101 |
276+
| [Hawk](https://github.com/orhanobut/hawk) | 💥 | 💥 |
277+
278+
### File size
279+
| | 1k strings (kb) |
280+
|-------------------|-----------------------|
281+
| **PufferDB** | **25** |
282+
| [SharedPreferences](https://developer.android.com/training/data-storage/shared-preferences) | 20 |
283+
| [MMKV](https://github.com/Tencent/MMKV) | 40 |
284+
| [Paper](https://github.com/pilgr/Paper) | 61 |
285+
| [Binary Prefs](https://github.com/yandextaxitech/binaryprefs) | 53 |
286+
| [Hawk](https://github.com/orhanobut/hawk) | 27 |
287+
288+
| | 100k strings (kb) |
289+
|-------------------|-----------------------|
290+
| **PufferDB** | **2.907** |
291+
| [SharedPreferences](https://developer.android.com/training/data-storage/shared-preferences) | 💥 |
292+
| [MMKV](https://github.com/Tencent/MMKV) | 4.104 |
293+
| [Paper](https://github.com/pilgr/Paper) | 💥 |
294+
| [Binary Prefs](https://github.com/yandextaxitech/binaryprefs) | 5.175 |
295+
| [Hawk](https://github.com/orhanobut/hawk) | 💥 |
267296

268297
*Tested on Moto Z2 Plus*
269298

core/src/main/kotlin/cafe/adriel/pufferdb/core/PufferDB.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,20 @@ import kotlinx.coroutines.CoroutineScope
1010
import kotlinx.coroutines.Dispatchers
1111
import kotlinx.coroutines.GlobalScope
1212
import kotlinx.coroutines.Job
13+
import kotlinx.coroutines.async
14+
import kotlinx.coroutines.coroutineScope
1315
import kotlinx.coroutines.flow.MutableStateFlow
1416
import kotlinx.coroutines.flow.drop
1517
import kotlinx.coroutines.flow.flowOn
1618
import kotlinx.coroutines.flow.launchIn
1719
import kotlinx.coroutines.flow.onEach
18-
import kotlinx.coroutines.flow.onStart
1920
import kotlinx.coroutines.isActive
20-
import kotlinx.coroutines.launch
2121
import kotlinx.coroutines.sync.Mutex
2222
import kotlinx.coroutines.sync.withLock
2323

2424
class PufferDB private constructor(
2525
private val pufferFile: File,
26-
private val scope: CoroutineScope,
26+
scope: CoroutineScope,
2727
private val dispatcher: CoroutineContext
2828
) : Puffer {
2929

@@ -43,17 +43,18 @@ class PufferDB private constructor(
4343
private var writeJob: Job? = null
4444

4545
init {
46+
loadProto()
47+
4648
stateFlow
4749
.drop(1)
48-
.onStart { loadProto() }
4950
.onEach { saveProto(state) }
5051
.flowOn(dispatcher)
5152
.launchIn(scope)
5253
}
5354

5455
@Suppress("UNCHECKED_CAST")
5556
override fun <T : Any> get(key: String, defaultValue: T?): T = try {
56-
val value = state.getOrDefault(key, null)
57+
val value = state[key]
5758
if (value == null) {
5859
throw PufferException("The key '$key' has no value saved")
5960
} else {
@@ -124,9 +125,9 @@ class PufferDB private constructor(
124125
}
125126
.toMap()
126127

127-
private fun saveProto(state: Map<String, Any>) {
128+
private suspend fun saveProto(state: Map<String, Any>) = coroutineScope {
128129
writeJob?.cancel()
129-
writeJob = scope.launch(dispatcher) {
130+
writeJob = async(dispatcher) {
130131
writeMutex.withLock {
131132
if (isActive) {
132133
val newNest = state.mapValues { it.value.getProtoValue() }

sample/src/main/kotlin/cafe/adriel/pufferdb/sample/Benchmark.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import com.ironz.binaryprefs.BinaryPreferencesBuilder
99
import com.orhanobut.hawk.Hawk
1010
import com.tencent.mmkv.MMKV
1111
import io.paperdb.Paper
12+
import java.io.File
1213
import kotlin.system.measureTimeMillis
1314

1415
class Benchmark(context: Context) {
@@ -21,11 +22,20 @@ class Benchmark(context: Context) {
2122
private val keys = Array(REPEAT_COUNT) { "Key $it" }
2223
private val values = Array(REPEAT_COUNT) { "Value $it" }
2324

25+
private val pufferFile = AndroidPufferDB.getInternalFile("puffer.db")
2426
private val puffer = AndroidPufferDB.withDefault()
27+
28+
private val sharedPreferencesDir = File(context.filesDir, "preferences")
2529
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
30+
31+
private val mmkvDir = File(MMKV.getRootDir())
2632
private val mmkv = MMKV.defaultMMKV()
33+
2734
private val paper = Paper.book()
28-
private val binaryPrefs = BinaryPreferencesBuilder(context).build()
35+
private val paperDir = File(paper.path)
36+
37+
private val binaryPrefsDir = File(context.filesDir, "binaryPrefs")
38+
private val binaryPrefs = BinaryPreferencesBuilder(context).customDirectory(binaryPrefsDir).build()
2939

3040
fun run() {
3141
reset()
@@ -170,4 +180,9 @@ class Benchmark(context: Context) {
170180
}
171181
Log.i("HAWK READ", "$duration ms")
172182
}
183+
184+
private fun File.lengthRecursively(): Long =
185+
walk().fold(0L) { acc, file ->
186+
acc + file.length()
187+
}
173188
}

0 commit comments

Comments
 (0)