Scala 调试lmdbjni访问冲突的下一步
我正在使用LMDBjni的这个分支:来 在scala中形成一个中型数据库项目的后端 我在这个LMDB的JNI代码中遇到了一个Scala 调试lmdbjni访问冲突的下一步,scala,java-native-interface,lmdb,Scala,Java Native Interface,Lmdb,我正在使用LMDBjni的这个分支:来 在scala中形成一个中型数据库项目的后端 我在这个LMDB的JNI代码中遇到了一个异常\u访问\u冲突(0xc0000005),我想知道是否有明显的错误,或者调试的下一步应该是什么。我不太确定我在寻找什么,所以我将尽可能多地列出正在发生的事情的信息,并希望这些症状对某人有意义 访问冲突发生在具有单个键映射到单个8字节值的数据库中,大约在对该数据库进行第4000次访问时(每次运行的确切数字似乎相同),这表明这是一个确定性问题 我相信我一次只有一个线程访问数
异常\u访问\u冲突(0xc0000005)
,我想知道是否有明显的错误,或者调试的下一步应该是什么。我不太确定我在寻找什么,所以我将尽可能多地列出正在发生的事情的信息,并希望这些症状对某人有意义
访问冲突发生在具有单个键映射到单个8字节值的数据库中,大约在对该数据库进行第4000次访问时(每次运行的确切数字似乎相同),这表明这是一个确定性问题
我相信我一次只有一个线程访问数据库,而且无论如何,在我的理解中,由于操作是封装在事务中的,并发访问无论如何都不重要
通过查看堆栈跟踪和打印值,问题来自我为构建事务编写的这个通用构造
导致问题的代码在这里,崩溃发生在标记的db.get()
调用中:
def transactionalGetAndSet[A](
key: Key,
db: Database
)(
compute: A => LMDBEither[A]
)(
implicit sa: Storeable[A],
env: Env
): LMDBEither[A] = {
import org.fusesource.lmdbjni.Transaction
// get a new transaction
val tx: Transaction = instance.env.createWriteTransaction()
println("tx = " + tx + " id = " + tx.getId)
// get the key as an Array[Byte]. This is done by converting the key to a base64 string then converting that to bytes (so arbitary objects can be made into keys)
val k = key.render
println("Key = " + key + " Rendered = " + new String(k))
// instantiate a result value, so there is something if it fails
var res: LMDBEither[A] = NoResult.left // initialise the result as a failure to begin with
try {
res = for { // This for construction chains together operations that return LMDBEithers into one LMDBEither
bytes <- LMDBEither(db.get(tx, k)) // error occurs in this Database.get() call
_ = println("bytes = " + bytes)
a <- sa.fromBytes(safeRetrieve(bytes)) // sa is effectively an unmarshaller/unmarshaller object which converts Vector[Byte] => LMDBEither[A]
_ = println("a = " + a)
res <- compute(a) // get the next value for the value at the key
_ = println("res = " + res)
_ <- LMDBEither(db.put(tx, k, sa.toBytes(res).toArray))
} yield a // effectively, if all these steps worked, res == Right(a)
res // return the result
} finally {
// Make sure you either commit or rollback to avoid resource leaks.
if (res.isRight) tx.commit() // if the result is not an error (ie Either.isRight is true)
else tx.abort()
tx.close()
}
}
据我所知,这不会修改存储阵列的内存(LMDB的受保护内存)
碰撞前打印的值(包括碰撞)如下所示:
private def safeRetrieve(bytes: Array[Byte]): Vector[Byte] =
Option(bytes).fold(Vector[Byte]()){ // if the array is null, convert to an empty vector, otherwise call the array's wrapper's vector
arr =>
println("Vector = " + arr.toVector)
arr.toVector
}
tx = org.fusesource.lmdbjni.Transaction@391cec1f id = 15104
Key = Vector(Objects) Rendered = 84507411390877848991196161
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000018002453f, pid=10220, tid=7268
#
# JRE version: Java(TM) SE Runtime Environment (8.0_60-b27) (build 1.8.0_60-b27)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.60-b23 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# C [lmdbjni-64-0-7710432736670562378.4+0x2453f]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\dev\PartIIProject\hs_err_pid10220.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
这是mdb_get()失败的更多证据。
参考文件的完整内容如下所示:
再一次,我非常感谢有这么小的机会,任何人都能为我指明正确的方向。接下来我应该采取什么措施?我想我应该澄清一下,我不希望看到魔杖的答案,但我非常感谢您帮助我了解访问冲突的含义、常见原因,以及其他更有经验使用LMDB+JVM语言的人是否也有类似的问题,等等,“访问冲突”表示程序试图访问一些无效的内存位置。通常这意味着直接内存损坏或试图使用已释放的指针。如果您使用JNI,那么LMDB必须用某种基于VM的语言实现,在这种语言中,两种错误都很可能发生。然而,这也可能是LMDB JNI中的一个bug,或者是由于错误使用它而引入的bug。如何帮助你真的很难提出建议。最好的方法可能是制作并发布一个非常小的文件,这样每个人都可以复制和调试这个问题。一个可能的原因是LMDB环境/db在不同的线程中关闭。正在进行的读/写操作将访问无效的内存位置。