< 返回版块

huang12zheng 发表于 2022-08-27 18:48

Tags:salsa

昨天看了salsa 2022了,发现不懂了. 写了些笔记, 抛砖引玉

PS 2018是什么样子的,我已经忘记了 :)

  • Database->Storage

我们从Database::default 进去, 看一下 然后找到 storage: ::core::default::Default::default(), 再看一下 salsa::Storage::default,

pub fn main() {
    let mut db = db::Database::default(); //<<<<<
    let source_program = SourceProgram::new(&mut db, String::new());
    compile::compile(&db, source_program);
    let diagnostics = compile::compile::accumulated::<Diagnostics>(&db, source_program);
    {
        ::std::io::_eprint(::core::fmt::Arguments::new_v1(
            &["", "\n"],
            &[::core::fmt::ArgumentV1::new_debug(&diagnostics)],
        ));
    };
}

#[automatically_derived]
    impl ::core::default::Default for Database {
        #[inline]
        fn default() -> Database {
            Database {
                storage: ::core::default::Default::default(),  <<<<
                logs: ::core::default::Default::default(),
            }
        }
    }

pub(crate) struct Database {
        storage: salsa::Storage<Self>,
        logs: Option<Arc<Mutex<Vec<String>>>>,
    }
  • Storage->Jar

发现Storage里做了一件事, DB::create_jars(&mut routes); 这里的DB是HasJars. 所以我们要去找

  1. fn create_jars(routes: &mut salsa::routes::Routes) -> Self::Jars { 或
  2. impl salsa::storage::HasJars for
impl<DB> Default for Storage<DB>
where
    DB: HasJars,
{
    fn default() -> Self {
        let mut routes = Routes::new();
        let jars = DB::create_jars(&mut routes); // <<<<<
        Self {
            shared: Arc::new(Shared {
                jars,
                cvar: Default::default(),
            }),
            routes: Arc::new(routes),
            runtime: Runtime::default(),
        }
    }
}

impl salsa::storage::HasJars for Database {
        type Jars = (crate::Jar,);
        fn jars(&self) -> (&Self::Jars, &salsa::Runtime) {
            self.storage.jars()
        }
        fn jars_mut(&mut self) -> (&mut Self::Jars, &mut salsa::Runtime) {
            self.storage.jars_mut()
        }
        fn create_jars(routes: &mut salsa::routes::Routes<Self>) -> Self::Jars {
            (<crate::Jar as salsa::jar::Jar>::create_jar(routes),)  <<<
        }
    }
  • create_jars

注意到 返回值是一个元组, 也就是说,我们给database 多少个Jar,就会在这里有多少个 Jar的create_jar (没有s)

#[salsa::db(crate::Jar)]
pub(crate) struct Database {
    storage: salsa::Storage<Self>,

    // The logs are only used for testing and demonstrating reuse:
    //
    logs: Option<Arc<Mutex<Vec<String>>>>,
}
  • create_jar

create_jar 是 在 trait of impl<'salsa_db> salsa::jar::Jar 上代码

fn create_jar<DB>(routes: &mut salsa::routes::Routes<DB>) -> Self
    where
        DB: salsa::storage::JarFromJars<Self> + salsa::storage::DbWithJar<Self>,
    {
        let i0 =
            <crate::compile::compile as salsa::storage::IngredientsFor>::create_ingredients(routes);
        ....
        Self(i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11)
    }
  1. create_ingredients 返回的是 Self::Ingredients,且type Ingredients = Self; 就compile而言, 就是返回compile

先不说具体的 create_ingredients, 我们说一下返回值 compile, 或者说是Jar的成分 ingredients. 即 FunctionIngredient 和 InputFieldIngredient

分别在 functions.rs 和 input_field.rs里

  • 在input_field.rs 里有 方法 store,fetch,实现了对 给定hash下,将值存到map里.

  • 而 functions.rs 里没有, 但可以在 store.rs里找到store( , 以及 fetch.rs 里 pub fn fetc

salsa::function::FunctionIngredient::new(index, "compile");
salsa::input_field::InputFieldIngredient::new(index, "text");

impl<C> FunctionIngredient<C>
where
    C: Configuration,
{
    pub fn new(index: IngredientIndex, debug_name: &'static str) -> Self {
        Self {
            index,  //<<<<
            memo_map: memo::MemoMap::default(),
            lru: Default::default(),
            sync_map: Default::default(),
            deleted_entries: Default::default(),
            registered: Default::default(),
            debug_name,  //<<<<
        }
    }

pub struct InputFieldIngredient<K, F> {
    index: IngredientIndex,
    map: FxHashMap<K, StampedValue<F>>,  /// &&&&
    debug_name: &'static str,
}


///////  会 代码生成 修改 Ingredients的
// function
pub struct compile {
    intern_map: salsa::interned::IdentityInterner<SourceProgram>,
    function: salsa::function::FunctionIngredient<Self>,
}
// struct
pub struct SourceProgram(salsa::Id);
  • store.rs里的 store( 和 fetch.rs 里的 fetch(
/// store.rs
pub fn store(
        &mut self,
        runtime: &mut Runtime,
        key: C::Key,
        value: C::Value,
        durability: Durability,
    ) {
        let revision = runtime.current_revision();
        let memo = Memo {
            value: Some(value),
            verified_at: AtomicCell::new(revision),
            revisions: QueryRevisions {
                changed_at: revision,
                durability,
                origin: QueryOrigin::BaseInput,
            },
        };

        if let Some(old_value) = self.memo_map.insert(key, Arc::new(memo)) { // <<<<<<<<<<<<<<<<<<<<<
            // NB: we don't have to store `old_value` into `deleted_entries` because we have `&mut self`.
            let durability = old_value.load().revisions.durability;
            runtime.report_tracked_write(durability);
        }
    }

pub fn fetch(&self, db: &DynDb<C>, key: C::Key) -> &C::Value {
        let runtime = db.runtime();

        runtime.unwind_if_revision_cancelled(db);

        let StampedValue {
            value,
            durability,
            changed_at,
        } = self.compute_value(db, key);

        if let Some(evicted) = self.lru.record_use(key.as_id()) {
            self.evict(AsId::from_id(evicted));
        }

        db.runtime().report_tracked_read(
            self.database_key_index(key).into(),
            durability,
            changed_at,
        );

        value
    }

我们回到 impl compile {

发现都做了三件事

  1. get jar
  2. get ingredients
  3. store(when new or set) or fetch(when get)
可以说 数据的结构应该是 
Database--Jars--Jar--ingredients--ingredient--map[hash]--value
注意, 在map 之前的 映射关系都是vec[index]这样的硬编码.
impl compile {
        #[allow(dead_code, clippy::needless_lifetimes)]
        pub fn get<'__db>(db: &'__db dyn crate::Db, source_program: SourceProgram) -> &'__db () {
            let (__jar, __runtime) = <_ as salsa::storage::HasJar<crate::Jar>>::jar(db);
            let __ingredients =
                <_ as salsa::storage::HasIngredientsFor<compile>>::ingredient(__jar);
            let __key = __ingredients.intern_map.intern(__runtime, (source_program));
            __ingredients.function.fetch(db, __key)
        }
        #[allow(dead_code, clippy::needless_lifetimes)]
        pub fn set(db: &mut dyn crate::Db, source_program: SourceProgram, __value: ()) {
            let (__jar, __runtime) = <_ as salsa::storage::HasJar<crate::Jar>>::jar_mut(db);
            let __ingredients =
                <_ as salsa::storage::HasIngredientsFor<compile>>::ingredient_mut(__jar);
            let __key = __ingredients.intern_map.intern(__runtime, (source_program));
            __ingredients
                .function
                .store(__runtime, __key, __value, salsa::Durability::LOW)
        }

上面代码 表明了使用时,具体发生了什么, 那么 好像只少了 Database::base create_ingredients硬编码的过程了.

注意 create_jar硬编码 在上面有代码.

  • create_ingredients 这里 要补充一个变量 routes, 作用如下:
  1. 对于一个 compiler(这是一个容器) ,等于 jars.x.y.x 比如 jars.0.0.0

想说 数据 都在 栈上.

  1. 将这个过程 写为 闭包 |jars| jars.x.y
  2. 将这个闭包存入routes,得到下标index , 做为 hash返回.

不过routes 里存了两个闭包, 不可变和可变的. 容器里有map.

let index = routes.push(
    |jars| {
        let jar =
            <DB as salsa::storage::JarFromJars<Self::Jar>>::jar_from_jars(jars);
        let ingredients =
            <_ as salsa::storage::HasIngredientsFor<Self>>::ingredient(jar);
        &ingredients.0
    },
    |jars| {
        let jar =
            <DB as salsa::storage::JarFromJars<Self::Jar>>::jar_from_jars_mut(
                jars,
            );
        let ingredients =
            <_ as salsa::storage::HasIngredientsFor<Self>>::ingredient_mut(jar);
        &mut ingredients.0
    },
);

impl salsa::storage::HasIngredientsFor<crate::compile::compile> for Jar {
    fn ingredient(
        &self,
    ) -> &<crate::compile::compile as salsa::storage::IngredientsFor>::Ingredients {  /// 《《《《《《《 IngredientsFor::Ingredients  is Self
        &self.0
    }
    fn ingredient_mut(
        &mut self,
    ) -> &mut <crate::compile::compile as salsa::storage::IngredientsFor>::Ingredients {
        &mut self.0
    }
}

/// 注意1
impl salsa::storage::IngredientsFor for compile {
        type Ingredients = Self;

/// 注意2
/// &self.0 即 Ingredients.x  x为某struct 或 function 的属性或参数 在 struct 或 function的位置.

也就是说, 根据我们给的schema 硬编码的过程只 生成 database, jars, Ingredients, prop of Ingredient的关系, 并且将一部分关系存到了routes里

》》》 就只是抛砖引玉

ps:请问, 如果我想做序列化, 要怎么做呢? ?_? ?_? ?_? -_-

pub struct Span(salsa::Id);

#[salsa::tracked]
pub struct Span {
    pub start: usize,
    pub end: usize,
}

评论区

写评论

还没有评论

1 共 0 条评论, 1 页