juji-io / datalevin

A simple, fast and versatile Datalog database
https://github.com/juji-io/datalevin
Eclipse Public License 1.0
1.1k stars 61 forks source link

Unexpected `nil` value in cardinality many #265

Open oxalorg opened 1 month ago

oxalorg commented 1 month ago

Hey, we have faced a weird issue while working with datalevin and wanted to document this here. Maybe this is something obvious but it has really puzzled us.

This is my schema:

   :gab/id       {:db/unique :db.unique/identity}
   :gab/sources  {:db/cardinality :db.cardinality/many
                  :db/valueType   :db.type/ref}

When I call (d/entity ... [:gab/id #uuid "67af1667-6d39-455f-814a-bca8a45a4e71"])

I get back the entire entity, but an attribute with cardinality many returns like so:

{:gab/id ...
 ...
 ...
 :gab/sources #{nil}}

Running (d/transact! ... [[:db.fn/retractAttribute 1776 :gab/sources]]) does nothing.

Trying to d/touch on (:gab/sources (d/entity ...)) does not work as it literally returns a nil.

Trying to delete the entire entity (d/transact! [[:db.fn/retractEntity 1776]]) leads to this error BUT it does retract the entity:

   Fail to transact to LMDB: #error { :cause "Error putting r/w key buffer of
   \"datalevin/eav\"with value#datalevin/Indexable [1776 96 \"tempid\" -8 \"\"
   nil]: #error {\n :cause \"class java.lang.String cannot be cast to class
   java.lang.Number (java.lang.String and java.lang.Number are in module
   java.base of loader 'bootstrap')\"\n :via\n [{:type
   java.lang.ClassCastException\n :message \"class java.lang.String cannot be
   cast to class java.lang.Number (java.lang.String and java.lang.Number are in
   module java.base of loader 'bootstrap')\"\n :at [datalevin.bits$put_long
   invokeStatic \"bits.cljc\" 257]}]\n :trace\n [[datalevin.bits$put_long
   invokeStatic \"bits.cljc\" 257]\n [datalevin.bits$put_long invoke
   \"bits.cljc\" 257]\n [datalevin.bits$put_fixed invokeStatic \"bits.cljc\"
   527]\n [datalevin.bits$put_fixed invoke \"bits.cljc\" 515]\n
   [datalevin.bits$put_eav invokeStatic \"bits.cljc\" 807]\n
   [datalevin.bits$put_eav invoke \"bits.cljc\" 799]\n
   [datalevin.bits$put_buffer invokeStatic \"bits.cljc\" 928]\n
   [datalevin.bits$put_buffer invoke \"bits.cljc\" 871]\n
   [datalevin.binding.java.DBI put_key \"java.clj\" 180]\n
   [datalevin.binding.java$transact_STAR_ invokeStatic \"java.clj\" 262]\n
   [datalevin.binding.java$transact_STAR_ invoke \"java.clj\" 242]\n
   [datalevin.binding.java.LMDB transact_kv \"java.clj\" 479]\n
   [datalevin.storage.Store load_datoms \"storage.cljc\" 378]\n
   [datalevin.db$local_transact_tx_data invokeStatic \"db.cljc\" 1249]\n
   [datalevin.db$local_transact_tx_data invoke \"db.cljc\" 980]\n
   [datalevin.db$transact_tx_data invokeStatic \"db.cljc\" 1287]\n
   [datalevin.db$transact_tx_data invoke \"db.cljc\" 1263]\n
   [datalevin.core$with invokeStatic \"core.cljc\" 376]\n [datalevin.core$with
   invoke \"core.cljc\" 370]\n [datalevin.core$with invokeStatic \"core.cljc\"
   373]\n [datalevin.core$with invoke \"core.cljc\" 370]\n
   [datalevin.core$_transact_BANG_$fn__49252$fn__49257 invoke \"core.cljc\"
   631]\n [datalevin.core$_transact_BANG_$fn__49252 invoke \"core.cljc\" 629]\n
   [datalevin.core$_transact_BANG_ invokeStatic \"core.cljc\" 629]\n
   [datalevin.core$_transact_BANG_ invoke \"core.cljc\" 628]\n
   [datalevin.core$transact_BANG_ invokeStatic \"core.cljc\" 721]\n
   [datalevin.core$transact_BANG_ invoke \"core.cljc\" 634]\n
   [datalevin.core$transact_BANG_ invokeStatic \"core.cljc\" 719]\n
   [datalevin.core$transact_BANG_ invoke \"core.cljc\" 634]\n
   [hai.db.datalevin$db_write invokeStatic \"datalevin.clj\" 170]\n
   [hai.db.datalevin$db_write invoke \"datalevin.clj\" 167]\n
   [hai.db.datalevin$db_write invokeStatic \"datalevin.clj\" 168]\n
   [hai.db.datalevin$db_write invoke \"datalevin.clj\" 167]\n
   [hai.one_backend.db$eval118070 invokeStatic \"NO_SOURCE_FILE\" 117]\n
   [hai.one_backend.db$eval118070 invoke \"NO_SOURCE_FILE\" 117]\n
   [clojure.lang.Compiler eval \"Compiler.java\" 7691]\n [clojure.lang.Compiler
   eval \"Compiler.java\" 7646]\n [clojure.core$eval invokeStatic \"core.clj\"
   3232]\n [clojure.core$eval invoke \"core.clj\" 3228]\n
   [nrepl.middleware.interruptible_eval$evaluate$fn__1383$fn__1384 invoke
   \"interruptible_eval.clj\" 87]\n [clojure.lang.AFn applyToHelper \"AFn.java\"
   152]\n [clojure.lang.AFn applyTo \"AFn.java\" 144]\n [clojure.core$apply
   invokeStatic \"core.clj\" 667]\n [clojure.core$with_bindings_STAR_
   invokeStatic \"core.clj\" 1990]\n [clojure.core$with_bindings_STAR_ doInvoke
   \"core.clj\" 1990]\n [clojure.lang.RestFn invoke \"RestFn.java\" 428]\n
   [nrepl.middleware.interruptible_eval$evaluate$fn__1383 invoke
   \"interruptible_eval.clj\" 87]\n
   [clojure.main$repl$read_eval_print__9240$fn__9243 invoke \"main.clj\" 437]\n
   [clojure.main$repl$read_eval_print__9240 invoke \"main.clj\" 437]\n
   [clojure.main$repl$fn__9249 invoke \"main.clj\" 459]\n [clojure.main$repl
   invokeStatic \"main.clj\" 459]\n [clojure.main$repl doInvoke \"main.clj\"
   368]\n [clojure.lang.RestFn invoke \"RestFn.java\" 1526]\n
   [nrepl.middleware.interruptible_eval$evaluate invokeStatic
   \"interruptible_eval.clj\" 84]\n
   [nrepl.middleware.interruptible_eval$evaluate invoke
   \"interruptible_eval.clj\" 56]\n
   [nrepl.middleware.interruptible_eval$interruptible_eval$fn__1416$fn__1420
   invoke \"interruptible_eval.clj\" 152]\n [clojure.lang.AFn run \"AFn.java\"
   22]\n [nrepl.middleware.session$session_exec$main_loop__1486$fn__1490 invoke
   \"session.clj\" 218]\n [nrepl.middleware.session$session_exec$main_loop__1486
   invoke \"session.clj\" 217]\n [clojure.lang.AFn run \"AFn.java\" 22]\n
   [java.lang.Thread run \"Thread.java\" 833]]}" :data {:type :eav} :via [{:type
   clojure.lang.ExceptionInfo :message "Error putting r/w key buffer of
   \"datalevin/eav\"with value#datalevin/Indexable [1776 96 \"tempid\" -8 \"\"
   nil]: #error {\n :cause \"class java.lang.String cannot be cast to class
   java.lang.Number (java.lang.String and java.lang.Number are in module
   java.base of loader 'bootstrap')\"\n :via\n [{:type
   java.lang.ClassCastException\n :message \"class java.lang.String cannot be
   cast to class java.lang.Number (java.lang.String and java.lang.Number are in
   module java.base of loader 'bootstrap')\"\n :at [datalevin.bits$put_long
   invokeStatic \"bits.cljc\" 257]}]\n :trace\n [[datalevin.bits$put_long
   invokeStatic \"bits.cljc\" 257]\n [datalevin.bits$put_long invoke
   \"bits.cljc\" 257]\n [datalevin.bits$put_fixed invokeStatic \"bits.cljc\"
   527]\n [datalevin.bits$put_fixed invoke \"bits.cljc\" 515]\n
   [datalevin.bits$put_eav invokeStatic \"bits.cljc\" 807]\n
   [datalevin.bits$put_eav invoke \"bits.cljc\" 799]\n
   [datalevin.bits$put_buffer invokeStatic \"bits.cljc\" 928]\n
   [datalevin.bits$put_buffer invoke \"bits.cljc\" 871]\n
   [datalevin.binding.java.DBI put_key \"java.clj\" 180]\n
   [datalevin.binding.java$transact_STAR_ invokeStatic \"java.clj\" 262]\n
   [datalevin.binding.java$transact_STAR_ invoke \"java.clj\" 242]\n
   [datalevin.binding.java.LMDB transact_kv \"java.clj\" 479]\n
   [datalevin.storage.Store load_datoms \"storage.cljc\" 378]\n
   [datalevin.db$local_transact_tx_data invokeStatic \"db.cljc\" 1249]\n
   [datalevin.db$local_transact_tx_data invoke \"db.cljc\" 980]\n
   [datalevin.db$transact_tx_data invokeStatic \"db.cljc\" 1287]\n
   [datalevin.db$transact_tx_data invoke \"db.cljc\" 1263]\n
   [datalevin.core$with invokeStatic \"core.cljc\" 376]\n [datalevin.core$with
   invoke \"core.cljc\" 370]\n [datalevin.core$with invokeStatic \"core.cljc\"
   373]\n [datalevin.core$with invoke \"core.cljc\" 370]\n
   [datalevin.core$_transact_BANG_$fn__49252$fn__49257 invoke \"core.cljc\"
   631]\n [datalevin.core$_transact_BANG_$fn__49252 invoke \"core.cljc\" 629]\n
   [datalevin.core$_transact_BANG_ invokeStatic \"core.cljc\" 629]\n
   [datalevin.core$_transact_BANG_ invoke \"core.cljc\" 628]\n
   [datalevin.core$transact_BANG_ invokeStatic \"core.cljc\" 721]\n
   [datalevin.core$transact_BANG_ invoke \"core.cljc\" 634]\n
   [datalevin.core$transact_BANG_ invokeStatic \"core.cljc\" 719]\n
   [datalevin.core$transact_BANG_ invoke \"core.cljc\" 634]\n
   [hai.db.datalevin$db_write invokeStatic \"datalevin.clj\" 170]\n
   [hai.db.datalevin$db_write invoke \"datalevin.clj\" 167]\n
   [hai.db.datalevin$db_write invokeStatic \"datalevin.clj\" 168]\n
   [hai.db.datalevin$db_write invoke \"datalevin.clj\" 167]\n
   [hai.one_backend.db$eval118070 invokeStatic \"NO_SOURCE_FILE\" 117]\n
   [hai.one_backend.db$eval118070 invoke \"NO_SOURCE_FILE\" 117]\n
   [clojure.lang.Compiler eval \"Compiler.java\" 7691]\n [clojure.lang.Compiler
   eval \"Compiler.java\" 7646]\n [clojure.core$eval invokeStatic \"core.clj\"
   3232]\n [clojure.core$eval invoke \"core.clj\" 3228]\n
   [nrepl.middleware.interruptible_eval$evaluate$fn__1383$fn__1384 invoke
   \"interruptible_eval.clj\" 87]\n [clojure.lang.AFn applyToHelper \"AFn.java\"
   152]\n [clojure.lang.AFn applyTo \"AFn.java\" 144]\n [clojure.core$apply
   invokeStatic \"core.clj\" 667]\n [clojure.core$with_bindings_STAR_
   invokeStatic \"core.clj\" 1990]\n [clojure.core$with_bindings_STAR_ doInvoke
   \"core.clj\" 1990]\n [clojure.lang.RestFn invoke \"RestFn.java\" 428]\n
   [nrepl.middleware.interruptible_eval$evaluate$fn__1383 invoke
   \"interruptible_eval.clj\" 87]\n
   [clojure.main$repl$read_eval_print__9240$fn__9243 invoke \"main.clj\" 437]\n
   [clojure.main$repl$read_eval_print__9240 invoke \"main.clj\" 437]\n
   [clojure.main$repl$fn__9249 invoke \"main.clj\" 459]\n [clojure.main$repl
   invokeStatic \"main.clj\" 459]\n [clojure.main$repl doInvoke \"main.clj\"
   368]\n [clojure.lang.RestFn invoke \"RestFn.java\" 1526]\n
   [nrepl.middleware.interruptible_eval$evaluate invokeStatic
   \"interruptible_eval.clj\" 84]\n
   [nrepl.middleware.interruptible_eval$evaluate invoke
   \"interruptible_eval.clj\" 56]\n
   [nrepl.middleware.interruptible_eval$interruptible_eval$fn__1416$fn__1420
   invoke \"interruptible_eval.clj\" 152]\n [clojure.lang.AFn run \"AFn.java\"
   22]\n [nrepl.middleware.session$session_exec$main_loop__1486$fn__1490 invoke
   \"session.clj\" 218]\n [nrepl.middleware.session$session_exec$main_loop__1486
   invoke \"session.clj\" 217]\n [clojure.lang.AFn run \"AFn.java\" 22]\n
   [java.lang.Thread run \"Thread.java\" 833]]}" :data {:type :eav} :at
   [datalevin.binding.java.DBI put_key "java.clj" 185]}] :trace
   [[datalevin.binding.java.DBI put_key "java.clj" 185]
   [datalevin.binding.java$transact_STAR_ invokeStatic "java.clj" 262]
   [datalevin.binding.java$transact_STAR_ invoke "java.clj" 242]
   [datalevin.binding.java.LMDB transact_kv "java.clj" 479]
   [datalevin.storage.Store load_datoms "storage.cljc" 378]
   [datalevin.db$local_transact_tx_data invokeStatic "db.cljc" 1249]
   [datalevin.db$local_transact_tx_data invoke "db.cljc" 980]
   [datalevin.db$transact_tx_data invokeStatic "db.cljc" 1287]
   [datalevin.db$transact_tx_data invoke "db.cljc" 1263] [datalevin.core$with
   invokeStatic "core.cljc" 376] [datalevin.core$with invoke "core.cljc" 370]
   [datalevin.core$with invokeStatic "core.cljc" 373] [datalevin.core$with
   invoke "core.cljc" 370] [datalevin.core$_transact_BANG_$fn__49252$fn__49257
   invoke "core.cljc" 631] [datalevin.core$_transact_BANG_$fn__49252 invoke
   "core.cljc" 629] [datalevin.core$_transact_BANG_ invokeStatic "core.cljc"
   629] [datalevin.core$_transact_BANG_ invoke "core.cljc" 628]
   [datalevin.core$transact_BANG_ invokeStatic "core.cljc" 721]
   [datalevin.core$transact_BANG_ invoke "core.cljc" 634]
   [datalevin.core$transact_BANG_ invokeStatic "core.cljc" 719]
   [datalevin.core$transact_BANG_ invoke "core.cljc" 634]
   [hai.db.datalevin$db_write invokeStatic "datalevin.clj" 170]
   [hai.db.datalevin$db_write invoke "datalevin.clj" 167]
   [hai.db.datalevin$db_write invokeStatic "datalevin.clj" 168]
   [hai.db.datalevin$db_write invoke "datalevin.clj" 167]
   [hai.one_backend.db$eval118070 invokeStatic "NO_SOURCE_FILE" 117]
   [hai.one_backend.db$eval118070 invoke "NO_SOURCE_FILE" 117]
   [clojure.lang.Compiler eval "Compiler.java" 7691] [clojure.lang.Compiler eval
   "Compiler.java" 7646] [clojure.core$eval invokeStatic "core.clj" 3232]
   [clojure.core$eval invoke "core.clj" 3228]
   [nrepl.middleware.interruptible_eval$evaluate$fn__1383$fn__1384 invoke
   "interruptible_eval.clj" 87] [clojure.lang.AFn applyToHelper "AFn.java" 152]
   [clojure.lang.AFn applyTo "AFn.java" 144] [clojure.core$apply invokeStatic
   "core.clj" 667] [clojure.core$with_bindings_STAR_ invokeStatic "core.clj"
   1990] [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1990]
   [clojure.lang.RestFn invoke "RestFn.java" 428]
   [nrepl.middleware.interruptible_eval$evaluate$fn__1383 invoke
   "interruptible_eval.clj" 87]
   [clojure.main$repl$read_eval_print__9240$fn__9243 invoke "main.clj" 437]
   [clojure.main$repl$read_eval_print__9240 invoke "main.clj" 437]
   [clojure.main$repl$fn__9249 invoke "main.clj" 459] [clojure.main$repl
   invokeStatic "main.clj" 459] [clojure.main$repl doInvoke "main.clj" 368]
   [clojure.lang.RestFn invoke "RestFn.java" 1526]
   [nrepl.middleware.interruptible_eval$evaluate invokeStatic
   "interruptible_eval.clj" 84] [nrepl.middleware.interruptible_eval$evaluate
   invoke "interruptible_eval.clj" 56]
   [nrepl.middleware.interruptible_eval$interruptible_eval$fn__1416$fn__1420
   invoke "interruptible_eval.clj" 152] [clojure.lang.AFn run "AFn.java" 22]
   [nrepl.middleware.session$session_exec$main_loop__1486$fn__1490 invoke
   "session.clj" 218] [nrepl.middleware.session$session_exec$main_loop__1486
   invoke "session.clj" 217] [clojure.lang.AFn run "AFn.java" 22]
   [java.lang.Thread run "Thread.java" 833]]}
   {}
                  java.clj:  490  datalevin.binding.java.LMDB/transact_kv
              storage.cljc:  378  datalevin.storage.Store/load_datoms
                   db.cljc: 1249  datalevin.db$local_transact_tx_data/invokeStatic
                   db.cljc:  980  datalevin.db$local_transact_tx_data/invoke
                   db.cljc: 1287  datalevin.db$transact_tx_data/invokeStatic
                   db.cljc: 1263  datalevin.db$transact_tx_data/invoke
                 core.cljc:  376  datalevin.core$with/invokeStatic
                 core.cljc:  370  datalevin.core$with/invoke
                 core.cljc:  373  datalevin.core$with/invokeStatic
                 core.cljc:  370  datalevin.core$with/invoke
                 core.cljc:  631  datalevin.core$_transact_BANG_$fn__49252$fn__49257/invoke
                 core.cljc:  629  datalevin.core$_transact_BANG_$fn__49252/invoke
                 core.cljc:  629  datalevin.core$_transact_BANG_/invokeStatic
                 core.cljc:  628  datalevin.core$_transact_BANG_/invoke
                 core.cljc:  721  datalevin.core$transact_BANG_/invokeStatic
                 core.cljc:  634  datalevin.core$transact_BANG_/invoke
                 core.cljc:  719  datalevin.core$transact_BANG_/invokeStatic
                 core.cljc:  634  datalevin.core$transact_BANG_/invoke
             datalevin.clj:  170  hai.db.datalevin/db-write
             datalevin.clj:  167  hai.db.datalevin/db-write
             datalevin.clj:  168  hai.db.datalevin/db-write
             datalevin.clj:  167  hai.db.datalevin/db-write
                      REPL:  117  hai.one-backend.db/eval118070
                      REPL:  117  hai.one-backend.db/eval118070
             Compiler.java: 7691  clojure.lang.Compiler/eval
             Compiler.java: 7646  clojure.lang.Compiler/eval
                  core.clj: 3232  clojure.core/eval
                  core.clj: 3228  clojure.core/eval
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj: 1990  clojure.core/with-bindings*
                  core.clj: 1990  clojure.core/with-bindings*
               RestFn.java:  428  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  437  clojure.main/repl/read-eval-print/fn
                  main.clj:  437  clojure.main/repl/read-eval-print
                  main.clj:  459  clojure.main/repl/fn
                  main.clj:  459  clojure.main/repl
                  main.clj:  368  clojure.main/repl
               RestFn.java: 1526  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   84  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  152  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  218  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  217  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  833  java.lang.Thread/run

Any idea why this could have happened? Could it be a transient write error, or something do with tempids?

huahaiy commented 1 month ago

Could you isolate a test case?