capocasa / limdb

Fast, in-process key-value store with a table-like interface persisted to disk using lmdb.
MIT License
36 stars 3 forks source link

MDB_READERS_FULL #6

Open sdmcallister opened 1 week ago

sdmcallister commented 1 week ago

I have the following code which attempts to use limdb with mummy:

import mummy, mummy/routers

import limdb
let db = initDatabase("myDirectory")

proc indexHandler(request: Request) =
  var headers: HttpHeaders
  headers["Content-Type"] = "text/plain"
  var f = db["foo"]
  # db.close()
  request.respond(200, headers, "Hello, World! " & f)

var router: Router
router.get("/", indexHandler)

let server = newServer(router)
echo "Serving on http://localhost:8080"
server.serve(Port(8080))

When I spam the refresh 50+ times eventually I get:

Serving on http://localhost:8080
Handler exception: LimDB initTransaction failed: MDB_READERS_FULL: Environment maxreaders limit reached C:\Users\.nimble\pkgs2\mummy-0.4.5-cb7f70cd4d6fd3a563e00e664cfbd8cbd3c39b79\mummy.nim(519) workerProc
C:\Users\.nimble\pkgs2\mummy-0.4.5-cb7f70cd4d6fd3a563e00e664cfbd8cbd3c39b79\mummy.nim(450) runTask
C:\Users\.nimble\pkgs2\mummy-0.4.5-cb7f70cd4d6fd3a563e00e664cfbd8cbd3c39b79\mummy\routers.nim(271) :anonymous
C:\Users\source\nim\mummy_tests\main.nim(9) indexHandler
C:\Users\.nimble\pkgs2\limdb-0.3.0-37ce8d2ae2f7bcea945b3eb7bd6a149891ed7390\limdb.nim(241) []
C:\Users\.nimble\pkgs2\limdb-0.3.0-37ce8d2ae2f7bcea945b3eb7bd6a149891ed7390\limdb.nim(122) initTransaction
[[reraised from:
C:\Users\.nimble\pkgs2\mummy-0.4.5-cb7f70cd4d6fd3a563e00e664cfbd8cbd3c39b79\mummy.nim(519) workerProc
C:\Users\.nimble\pkgs2\mummy-0.4.5-cb7f70cd4d6fd3a563e00e664cfbd8cbd3c39b79\mummy.nim(450) runTask
C:\Users\.nimble\pkgs2\mummy-0.4.5-cb7f70cd4d6fd3a563e00e664cfbd8cbd3c39b79\mummy\routers.nim(286) :anonymous
]]
capocasa commented 1 week ago

Interesting.

MDB_READERS_FULL means the maximum number of simultaneous accesses has been exceeded. By default this is 126, I believe.

I do believe mummy has a new thread for every ongoing request, and I'm not sure exactly when they are cleaned up. So it's possible you could go above that.

I currently don't expose this. I will change this, in the mean time you can work around like so:

import mummy, mummy/routers

import limdb, lmdb
let db = initDatabase("myDirectory")
discard envSetMaxreaders(db.env, 10000)
db["foo"] = "bar"

proc indexHandler(request: Request) =
  var headers: HttpHeaders
  headers["Content-Type"] = "text/plain"
  var f = db["foo"]
  request.respond(200, headers, "Hello, World! " & f)

var router: Router
router.get("/", indexHandler)

let server = newServer(router)
echo "Serving on http://localhost:8080"
server.serve(Port(8080))

Then hit it, here it's 5000 requests, 1200 at once:

for i in {1..5000}; do
  echo "url = \"http://localhost:8080\""
done > urls.txt
curl --parallel --parallel-immediate --parallel-max 1200 --config urls.txt

Works fine.