mirror of
https://github.com/patarapolw/cjdic2.git
synced 2026-11-09 17:39:35 +00:00
enum-map and more db attach
This commit is contained in:
1 parent
a38a28a836
commit
ec14023c04
6 files changed
+76
-47
No files matched your search
Generated
+21
@@ -639,6 +639,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"blake3",
|
||||
"enum-map",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -1124,6 +1125,26 @@ version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
|
||||
|
||||
[[package]]
|
||||
name = "enum-map"
|
||||
version = "2.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9"
|
||||
dependencies = [
|
||||
"enum-map-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum-map-derive"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumflags2"
|
||||
version = "0.7.12"
|
||||
|
||||
@@ -16,3 +16,4 @@ blake3 = "1.8.3"
|
||||
anyhow = "1.0.102"
|
||||
vibrato = "0.5.2"
|
||||
zstd = "0.13.3"
|
||||
enum-map = "2.7.3"
|
||||
+43
-40
@@ -2,12 +2,13 @@ use std::{
|
||||
env::current_dir,
|
||||
path::{Path, PathBuf},
|
||||
sync::{
|
||||
Arc, Mutex,
|
||||
Arc, LazyLock, Mutex,
|
||||
atomic::{AtomicBool, Ordering},
|
||||
},
|
||||
};
|
||||
|
||||
use anyhow::{Ok, Result};
|
||||
use enum_map::EnumMap;
|
||||
use rusqlite::Connection;
|
||||
|
||||
mod yomitan;
|
||||
@@ -20,18 +21,32 @@ pub use yomitan_writer::{YomitanProgress, YomitanWriter, YomitanZipImportResult,
|
||||
pub(crate) struct Database {
|
||||
pub(crate) conn: Arc<Mutex<Connection>>,
|
||||
pub(crate) dir: PathBuf,
|
||||
yomitan_attached: Arc<AtomicBool>,
|
||||
yomitan_glossary_attached: Arc<AtomicBool>,
|
||||
is_db_attached: EnumMap<DbChild, Arc<AtomicBool>>,
|
||||
}
|
||||
|
||||
enum DbChild {
|
||||
#[derive(Debug, Enum, Clone, Copy)]
|
||||
pub(crate) enum DbChild {
|
||||
Yomitan,
|
||||
YomitanGlossary,
|
||||
Reading,
|
||||
}
|
||||
|
||||
const USER_DBFILE: &str = "user.db";
|
||||
pub(crate) const YOMITAN_DBFILE: &str = "yomitan.db";
|
||||
pub(crate) const YOMITAN_GLOSSARY_DBFILE: &str = "yomitan-glossary.db";
|
||||
|
||||
pub(crate) const DBFILE: LazyLock<EnumMap<DbChild, &str>> = LazyLock::new(|| {
|
||||
enum_map! {
|
||||
DbChild::Yomitan => "yomitan.db",
|
||||
DbChild::YomitanGlossary => "yomitan-glossary.db",
|
||||
DbChild::Reading => "reading.db"
|
||||
}
|
||||
});
|
||||
pub(crate) const DBSCHEMA: LazyLock<EnumMap<DbChild, &str>> = LazyLock::new(|| {
|
||||
enum_map! {
|
||||
DbChild::Yomitan => "yomitan",
|
||||
DbChild::YomitanGlossary => "glossary",
|
||||
DbChild::Reading => "reading"
|
||||
}
|
||||
});
|
||||
|
||||
impl Database {
|
||||
pub fn new(db_dir: impl AsRef<Path>) -> Result<Self> {
|
||||
@@ -50,37 +65,28 @@ impl Database {
|
||||
Ok(Self {
|
||||
conn: Arc::new(Mutex::new(conn)),
|
||||
dir,
|
||||
yomitan_attached: Arc::new(AtomicBool::new(false)),
|
||||
yomitan_glossary_attached: Arc::new(AtomicBool::new(false)),
|
||||
is_db_attached: enum_map! {
|
||||
DbChild::Yomitan => Arc::new(AtomicBool::new(false)),
|
||||
DbChild::YomitanGlossary => Arc::new(AtomicBool::new(false)),
|
||||
DbChild::Reading => Arc::new(AtomicBool::new(false)),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn yomitan(&self) -> Result<yomitan::YomitanDatabase> {
|
||||
self.ensure_db_attached(DbChild::Yomitan)?;
|
||||
self.ensure_db_attached(DbChild::YomitanGlossary)?;
|
||||
self.ensure_db_attached(DbChild::Reading)?;
|
||||
Ok(yomitan::YomitanDatabase::new(self.clone()))
|
||||
}
|
||||
|
||||
fn ensure_db_attached(&self, db_child: DbChild) -> Result<()> {
|
||||
match db_child {
|
||||
DbChild::Yomitan => {
|
||||
if self.yomitan_attached.load(Ordering::Acquire) {
|
||||
if self.is_db_attached[db_child].load(Ordering::Acquire) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
DbChild::YomitanGlossary => {
|
||||
if self.yomitan_glossary_attached.load(Ordering::Acquire) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let conn = self.conn.lock().unwrap();
|
||||
|
||||
let is_attached = match db_child {
|
||||
DbChild::Yomitan => self.yomitan_attached.load(Ordering::Relaxed),
|
||||
DbChild::YomitanGlossary => self.yomitan_glossary_attached.load(Ordering::Relaxed),
|
||||
};
|
||||
let is_attached = self.is_db_attached[db_child].load(Ordering::Relaxed);
|
||||
|
||||
if !is_attached {
|
||||
let dir = self.dir.clone();
|
||||
@@ -90,16 +96,15 @@ impl Database {
|
||||
current_dir()?.join(dir)
|
||||
};
|
||||
|
||||
let db_file = match db_child {
|
||||
DbChild::Yomitan => YOMITAN_DBFILE,
|
||||
DbChild::YomitanGlossary => YOMITAN_GLOSSARY_DBFILE,
|
||||
};
|
||||
let schema_name = match db_child {
|
||||
DbChild::Yomitan => "yomitan",
|
||||
DbChild::YomitanGlossary => "glossary",
|
||||
let mode = match db_child {
|
||||
DbChild::Yomitan | DbChild::YomitanGlossary => "?mode=ro&immutable=1",
|
||||
_ => "",
|
||||
};
|
||||
|
||||
let path = path.join(db_file).to_string_lossy().replace(r"\", r"/");
|
||||
let path = path
|
||||
.join(DBFILE[db_child])
|
||||
.to_string_lossy()
|
||||
.replace(r"\", r"/");
|
||||
|
||||
#[cfg(windows)]
|
||||
let path = if !path.starts_with("/") {
|
||||
@@ -108,22 +113,20 @@ impl Database {
|
||||
path.to_string()
|
||||
};
|
||||
|
||||
let uri = format!("file:{}?mode=ro&immutable=1", path);
|
||||
let uri = format!("file:{}{}", path, mode);
|
||||
|
||||
conn.execute(&format!("ATTACH DATABASE ?1 AS {}", schema_name), [uri])?;
|
||||
conn.execute(
|
||||
&format!("ATTACH DATABASE ?1 AS {}", DBSCHEMA[db_child]),
|
||||
[uri],
|
||||
)?;
|
||||
conn.execute_batch(&format!(
|
||||
r"
|
||||
PRAGMA {}.mmap_size = 3000000000; -- 3_000_000_000
|
||||
",
|
||||
schema_name
|
||||
DBSCHEMA[db_child]
|
||||
))?;
|
||||
|
||||
match db_child {
|
||||
DbChild::Yomitan => self.yomitan_attached.store(true, Ordering::Release),
|
||||
DbChild::YomitanGlossary => self
|
||||
.yomitan_glossary_attached
|
||||
.store(true, Ordering::Release),
|
||||
};
|
||||
self.is_db_attached[db_child].store(true, Ordering::Release);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -13,7 +13,7 @@ use zip::ZipArchive;
|
||||
|
||||
use crate::{
|
||||
CJDicError, Timer,
|
||||
db::{YOMITAN_DBFILE, YOMITAN_GLOSSARY_DBFILE},
|
||||
db::{DBFILE, DbChild},
|
||||
};
|
||||
|
||||
fn blake3_hex(s: &str) -> String {
|
||||
@@ -65,7 +65,7 @@ pub struct YomitanWriter {
|
||||
impl YomitanWriter {
|
||||
pub fn new(db_dir: impl AsRef<Path>) -> Result<Self> {
|
||||
let dir = db_dir.as_ref().to_path_buf();
|
||||
let conn = Connection::open(dir.join(YOMITAN_DBFILE))?;
|
||||
let conn = Connection::open(dir.join(DBFILE[DbChild::Yomitan]))?;
|
||||
|
||||
conn.execute_batch(
|
||||
"
|
||||
@@ -193,7 +193,7 @@ impl YomitanWriter {
|
||||
.query_row("SELECT MAX(id) FROM glossaries", [], |r| r.get::<_, i64>(0))?
|
||||
as usize;
|
||||
|
||||
let message = &format!("Migrate to {}", YOMITAN_GLOSSARY_DBFILE);
|
||||
let message = &format!("Migrate to {}", DBFILE[DbChild::YomitanGlossary]);
|
||||
progress_callback(YomitanProgress {
|
||||
message: message.to_string(),
|
||||
current: 0,
|
||||
@@ -255,7 +255,8 @@ impl YomitanWriter {
|
||||
steps: total,
|
||||
});
|
||||
|
||||
let _timer = Timer::new(format!("cleanup for {}", YOMITAN_GLOSSARY_DBFILE));
|
||||
let _timer =
|
||||
Timer::new(format!("cleanup for {}", DBFILE[DbChild::YomitanGlossary]));
|
||||
self.conn.execute_batch(
|
||||
"
|
||||
UPDATE glossaries SET content = '[]';
|
||||
@@ -368,7 +369,7 @@ impl YomitanWriter {
|
||||
current_dir()?.join(dir)
|
||||
};
|
||||
|
||||
let db_file = YOMITAN_GLOSSARY_DBFILE;
|
||||
let db_file = DBFILE[DbChild::YomitanGlossary];
|
||||
let schema_name = "glossary";
|
||||
|
||||
let path = path.join(db_file).to_string_lossy().replace(r"\", r"/");
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#[macro_use]
|
||||
extern crate enum_map;
|
||||
|
||||
mod db;
|
||||
mod error;
|
||||
mod service;
|
||||
|
||||
@@ -11,7 +11,7 @@ use vibrato::{Dictionary, Tokenizer};
|
||||
use crate::{
|
||||
Timer, ZipSource,
|
||||
db::{
|
||||
Database, YOMITAN_DBFILE, YomitanProgress, YomitanRow, YomitanWriter,
|
||||
DBFILE, Database, DbChild, YomitanProgress, YomitanRow, YomitanWriter,
|
||||
YomitanZipImportResult,
|
||||
},
|
||||
error::CJDicError,
|
||||
@@ -182,7 +182,7 @@ impl AppService {
|
||||
let mut new_dicts: Vec<String> = vec![];
|
||||
let mut to_be_removed_dicts: Vec<String> = vec![];
|
||||
|
||||
let db_path = self.db.dir.join(YOMITAN_DBFILE);
|
||||
let db_path = self.db.dir.join(DBFILE[DbChild::Yomitan]);
|
||||
|
||||
if db_path.exists() {
|
||||
let conn = Connection::open(&db_path)?;
|
||||
|
||||
Reference in new issue
Block a user