Replies: 23 comments
-
When a new insert or update is made, a new raft log entry containing a new page of the SQLite Write-Ahead Log will be created in-memory, temporarily increasing memory usage. After a while outstanding raft log entries get compacted into a snapshot, and the associated memory is released. Compaction happens after So to answer your question: for UPDATE memory usage will grow up to a certain amount and then it will fluctuate between a lower an upper bound. However if you keep performing new INSERTs forever without ever performing DELETEs, then memory usage will grow indefinitely since a copy of the entire database is kept in-memory. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the info. Little curious how you decided on |
Beta Was this translation helpful? Give feedback.
-
From where did you take the number Right now I don't recall exactly why picked Yes, I think the APIs to add would be roughly what you describe. I didn't add them so far to avoid exposing unnecessary details and having to then support that public API indefinitely. What is your use case exactly? Maybe there are more effective ways to solve your problem, or maybe there's a simpler or more user-friendly API we can expose (e.g. |
Beta Was this translation helpful? Give feedback.
-
The comment for raft_set_snapshot_trailing says the default value was 128. Didn't actually check the code. If i use dqlite it would be running in docker container with hard memory limit. Just trying to get an idea of average memory usage so i can set the limit appropriately. |
Beta Was this translation helpful? Give feedback.
-
Oh okay, I need to update that then.
Yeah, so as I suspected I think users will be typically concerned with the final memory usage. So I'm keen to add an API as close as possible to that use case. Are you using dqlite indirectly because it's what backs LXD's database, or do you have a custom application which uses dqlite directly? In the latter case, do you also have an idea of the size of the "actual" database? In other words, if you were using SQLite directly, what would be the maximum size of the database file image? I'm asking because if the size of the actual database is large compared to the trailing raft log entries, it probably won't change much what the exact value of snapshot threshold/trailing is. |
Beta Was this translation helpful? Give feedback.
-
It would be a custom application that uses dqlite.
Not sure yet since its currently key/value that uses raft and would like to transition to a sql backing. Currently just testing dqlite and how quickly it grows with inserts/updates and shrinks with deletes. |
Beta Was this translation helpful? Give feedback.
-
I assume here you mean the raft-related growth and compaction (due to trailing logs and snapshots) and NOT increase/decrease of the actual database (which is clearly mostly stable if the number and size of inserts more or less matches the number of deletes). If that's the case, tweaking the trailing/threshold values should help, feel free to experiment by changing the hard-coded values and recompile. We do plan to optimize for large numbers of small insert/deletes by supporting a finer grained replication model, where instead of replicating Write-Ahead Log pages we would replicate single Btree nodes. In that case the size of the raft entries being passed around should be significantly smaller, and so the amount of memory needed to keep trailing entries around would be much smaller too. If just tweaking the trailing/snapshot values is not enough for your use case, please let me know so we have an idea of a concrete real-world case where a smarter replication model would matter. |
Beta Was this translation helpful? Give feedback.
-
yeah raft-related growth and compaction. |
Beta Was this translation helpful? Give feedback.
-
Tweaking trailing/snapshot values will help a little. Also wondering if there anyway to shrink the amount of free pages after large amount of deletes? |
Beta Was this translation helpful? Give feedback.
-
Probably using VACUUM, but I don't know its internals and never really tested it. If you try it and it doesn't work, please let me know. |
Beta Was this translation helpful? Give feedback.
-
I've tried using vacuum once and it seemed to double the memory usage. Auto Vacuum doesn't seem to do anything. |
Beta Was this translation helpful? Give feedback.
-
Then I'll have to look into this at some point. For now we haven't add issues because of this, so I'm not sure when I'll get a chance to investigate. |
Beta Was this translation helpful? Give feedback.
-
Actually, thinking about it, a possible explanation is that when setting the journal in WAL mode (as dqlite does), SQLite first creates new WAL pages when running VACUUM, and only upon checkpointing the WAL back into the database file the actual amount of used pages shrinks. You can probably check it by yourself using the sqlite3 command line, running |
Beta Was this translation helpful? Give feedback.
-
Looks like to turn on |
Beta Was this translation helpful? Give feedback.
-
What are you basing this statement on? Empirical test or documentation? My reading of the relevant SQLite documentation is a bit different, see here and here.
Same as above. I didn't do any test, but I couldn't find documentation indicating the behavior you described. |
Beta Was this translation helpful? Give feedback.
-
Thats what I observe from testing. |
Beta Was this translation helpful? Give feedback.
-
What testing did you do exactly? There is a subtle point in the docs, that I'm not sure you considered:
I wrote the following program that sets package main
import (
"database/sql"
"fmt"
"log"
"os"
_ "github.com/mattn/go-sqlite3"
)
const filename = "vacuum-test.db"
func main() {
os.Remove(filename)
// Open the db.
db, err := sql.Open("sqlite3", filename)
if err != nil {
log.Fatalf("open: %v", err)
}
defer db.Close()
// Set WAL journal mode.
if _, err := db.Exec("PRAGMA journal_mode=wal"); err != nil {
log.Fatalf("set WAL mode: %v", err)
}
row := db.QueryRow("PRAGMA journal_mode")
var mode string
if err := row.Scan(&mode); err != nil {
log.Fatalf("query journal mode: %v", err)
}
if mode != "wal" {
log.Fatalf("WAL mode not set: %s", mode)
}
// Set auto vacuum
if _, err := db.Exec("PRAGMA auto_vacuum=1"); err != nil {
log.Fatalf("set WAL mode: %v", err)
}
if _, err := db.Exec("VACUUM"); err != nil {
log.Fatalf("vacuum: %v", err)
}
row = db.QueryRow("PRAGMA auto_vacuum")
var auto string
if err := row.Scan(&auto); err != nil {
log.Fatalf("query auto vacuum: %v", err)
}
if auto != "1" {
log.Fatalf("auto vacuum not set: %s", auto)
}
fmt.Printf("auto_vacuum=%s\n", auto)
} Note that if I remove the |
Beta Was this translation helpful? Give feedback.
-
Also, note that depending on your workload |
Beta Was this translation helpful? Give feedback.
-
I was just testing with simple c program using dqlite's vfs. I was mostly watching memory usage and when vfs functions where being called. I tried setting |
Beta Was this translation helpful? Give feedback.
-
Do you mean manually invoking the internal dqlite vfs functions (e.g. If so, I think it would be simpler to just use the regular SQLite API (perhaps via Go or bash) with its stock on-disk VFS and just observe how the size of the main db and of the WAL file vary. That's enough to know how I suspect that you'll need to perform a checkpoint of the WAL file after issuing a
That's pretty much essentially, won't work otherwise. |
Beta Was this translation helpful? Give feedback.
-
Looks like you're right that forcing a checkpoint will reclaim the space. |
Beta Was this translation helpful? Give feedback.
-
Internally dqlite performs checkpoints automatically using I didn't quite test the above, but those should be more or less the issues involved. |
Beta Was this translation helpful? Give feedback.
-
unfortunately it looks like manually triggering a checkpoint doesn't reclaim the space in dqlite. |
Beta Was this translation helpful? Give feedback.
-
Was wondering if dqlite memory usage should grow overtime? Is it suppose to grow with amount of inserts/updates statements?
Beta Was this translation helpful? Give feedback.
All reactions