女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

踩坑rust的partial copy導致metrics丟失

jf_wN0SrCdH ? 來源: RisingWave中文開源社區(qū) ? 2024-01-03 10:02 ? 次閱讀

作者:溫一鳴RisingWaveLabs 內(nèi)核開發(fā)工程師

在 RisingWave 的存儲代碼中,我們使用 RAII [1] 的思想來對 LSM iterator 的 metrics 進行監(jiān)控,從而避免在代碼中忘記上報 metrics 而導致 metrics 丟失。在實現(xiàn)中,我們設計了一個 rust 的 struct MonitoredStateStoreIterStats去收集 LSM iterator 的 metrics,去統(tǒng)計 iterator 中 key 的數(shù)量和長度,并為這個 struct 實現(xiàn)了 Drop,在這個 struct 被釋放的時候把在本地收集的 metrics 上報 prometheus。通過這種方式,我們不需要在每次 iterator 使用完后都手動上報 metrics,從而避免了由于代碼的疏忽導致忘記上報 metrics。

以下是一段簡化過的代碼。我們通過try_stream[2] 這個宏來封裝一個 iterator 的 stream 來收集這個 stream 的 metrics。在返回的 stream 被釋放時,stats 隨著 stream 被釋放,并調(diào)用其 drop 方法來上報收集到的 metrics。

pubstructMonitoredStateStoreIter{
inner:S,
stats:MonitoredStateStoreIterStats,
}

structMonitoredStateStoreIterStats{
total_items:usize,
total_size:usize,
storage_metrics:Arc,
}

implMonitoredStateStoreIter{
#[try_stream(ok=StateStoreIterItem,error=StorageError)]
asyncfninto_stream_inner(mutself){
letinner=self.inner;
futures::pin_mut!(inner);
whileletSome((key,value))=inner
.try_next()
.await
.inspect_err(|e|error!("Failedinnext:{:?}",e))?
{
self.stats.total_items+=1;
self.stats.total_size+=key.encoded_len()+value.len();
yield(key,value);
}
}
}

implDropforMonitoredStateStoreIterStats{
fndrop(&mutself){
self.storage_metrics
.iter_item
.observe(self.total_itemsasf64);
self.storage_metrics
.iter_size
.observe(self.total_sizeasf64);
}
}

然而,在使用過程中,我們遇到了上報的 metrics 全部為 0 的問題。

1最小復現(xiàn)

由于使用了try_stream宏來生成 stream,因此我們懷疑在try_stream生成的代碼中有 bug 導致 metrics 丟失。于是我們用 cargo-expand [3] 來將查看宏生成的代碼。展開后的代碼如下:

fninto_stream_inner(
mutself,
)->implStream
>{
::from_generator(staticmove|
mut__task_context:::ResumeTy,
|->::Result<(),?StorageError>{
let():()={
letinner=self.inner;
letmutinner=inner;
#[allow(unused_mut)]
letmutinner=unsafe{
::new_unchecked(
&mutinner,
)
};
whileletSome((key,value))
={
letmut__pinned=inner.try_next();
loop{
iflet::Ready(
result,
)=unsafe{
poll(Pin::as_mut(&mut__pinned),get_context(__task_context))
}{
breakresult;
}
__task_context=(yield::Pending);
}
}?
{
self.stats.total_items+=1;
self.stats.total_size+=key.encoded_len()+value.len();
__task_context=(yield::Ready((
key,
value,
)));
}
};
#[allow(unreachable_code)]
{
return::Ok(());
loop{
__task_context=(yield::Pending);
}
}
})
}

可以看到,try_stream宏生成的代碼中,包含了一個 rust generator 的閉包。閉包中收集和上報 metrics 的邏輯與原代碼基本相同,按照我們對 rust 的理解,仍然不應該會出現(xiàn) metrics 丟失的問題。因此我們懷疑是 rust 編譯器中與 generator 相關的邏輯存在問題。在 rust playground 上,我們嘗試了以下代碼來對問題進行復現(xiàn)。

structStat{
count:usize,
vec:Vec,
}

implDropforStat{
fndrop(&mutself){
println!("count:{}",self.count);
}
}

fnmain(){

letmutstat=Stat{
count:0,
vec:Vec::new(),
};

letmutf=move||{
stat.count+=1;
1
};

println!("num:{}",f());
}

執(zhí)行以后輸出如下。

num:1
count:0

按照預期,輸出的 num 和 count 應該都為1,因為在調(diào)用閉包 f 時stat.count += 1被調(diào)用了,但是以上代碼中遇到了和最開始同樣的問題。因此以上代碼可以作為我們問題的一個最小復現(xiàn)。

2問題分析

對以上代碼進行分析的話,我們看到閉包 f 的代碼中使用了 move,因此在閉包中使用過的對象的 ownership 應該都會轉(zhuǎn)移到閉包中。而 struct Stats實現(xiàn)了Drop,因此Stats是不可以 partial move 的,其必須作為一個整體被 move 進入閉包。而在閉包中執(zhí)行了stats.count += 1,因此 stats 中的 count 應該被置為1。但是從程序的輸出可以看到在 stats 被 drop 時,stats 的 count 是 0。

我們嘗試將閉包 f 改為如下代碼,來顯式的將 stats 的 ownership 給 move 進閉包里。

letmutf=move||{
letmutstat=stat;
stat.count+=1;
1
};

輸出恢復正常。

num:1
count:1

我們再次嘗試在閉包 f 中使用 stat 中的另一個字段 vec:

letmutf=move||{
let_=stat.vec.len();
stat.count+=1;
1
};

輸出同樣恢復正常。

num:1
count:1

可以看到,我們顯式地將 stat 整個 move 進閉包,或者在閉包中使用類型為 vec 的字段,都會使得 stat 的ownership 被 move 進閉包。

于是我們推測,盡管 stat 實現(xiàn)了自己的 drop 導致不能被 partial move,但是如果我們在 move 的閉包中只使用了 stat 中實現(xiàn)了 Copy 類型的字段,則這個字段的值會被 Copy 到閉包中,而閉包中對這個字段的修改只會作用于被 Copy 后的值,而原字段并不會改變。

3驗證猜想

我們可以通過將以上代碼編譯成二進制代碼后,對其匯編代碼進行分析,從而驗證我們的猜想。然而,編譯后的匯編代碼會過于復雜且晦澀難懂,同時編譯器對其進行的一些優(yōu)化也會改變原有的邏輯導致匯編代碼難以理解。因此我們打算通過分析在編譯過程中產(chǎn)生的 MIR 中間代碼來對問題進行分析。在 rust playground 上可以十分方便地生成 MIR 代碼。

首先我們對存在問題的最小復現(xiàn)代碼生成 MIR,生成后與閉包相關的 MIR 如下。可以看到這個閉包確實只包含了一個類型為 usize 的字段,這個字段的值取的是 stat 中的 count 值。

bb1:{
_1=Stat{count:const0_usize,vec:move_2};
_3={closure@src/main.rs:19:17:19:24}{stat:(_1.0:usize)};
}

而我們對后續(xù)測試中有正常輸出的代碼生成 MIR,生成后與閉包相關的 MIR 如下。可以看到這個閉包將整個 stat 的 ownership 給 move 了進去。

bb1:{
_1=Stat{count:const0_usize,vec:move_2};
_3={closure@src/main.rs:19:17:19:24}{stat:move_1};
}

于是,我們的猜想得到了驗證,在我們出現(xiàn)問題的代碼中,閉包確實沒有捕獲 stat 的 ownership。

4后續(xù)與總結(jié)

我們向 rust 社區(qū)反映了這個問題,得到的反饋是,這個是 rust 2021 后實現(xiàn)的一個 feature [4]。在 rust 2021 中,一個使用了 move 的閉包在捕獲一個 struct 的時候,會盡可能少地去捕獲 struct 中的字段。

如果一個 struct 沒有實現(xiàn) Drop,這意味著他里面的字段可以被分開 move,而閉包只會捕獲閉包中用到的字段。

如果某個被閉包使用的字段實現(xiàn)了 Copy,那他閉包并不會捕獲這個字段的 ownership,而是將這個字段 copy 一份放在閉包中。

如果一個 struct 實現(xiàn)了 Drop,那他里面的字段只能作為一個整體被捕獲。但如果閉包只使用了這個閉包中實現(xiàn)了 Copy 的字段,那這個閉包不會捕獲這個 struct,而是將使用到的字段 copy 一份。

我們的代碼中,正是因為這個行為,導致我們的代碼產(chǎn)生了歧義,而出現(xiàn)了 metrics 的丟失。

針對這個問題,我們認為有兩個地方有提升的空間。

首先,try_stream這個宏的封裝存在一定的問題。在使用宏來聲明代碼中,其暴露出來的使用方法是通過調(diào)用一個方法來生成 stream,而在調(diào)用方法時,如果參數(shù)是通過 move ownership 的形式傳入的,同時在生成 stream 的代碼中我們使用了這個參數(shù),那我們應該認為這個 stream 包含了這個參數(shù)的 ownership。然而,由于這個宏在實現(xiàn)的時候使用了閉包,導致這個 stream 并沒有包含這個參數(shù)的 ownership,從而導致問題。這個是宏封裝邏輯時的問題。

其次,rust 在語言設計上,由于引入了這個閉包捕獲 ownership 的特殊邏輯,導致會寫出有歧義的代碼。例如,在上述代碼中,很難想象stat.count += 1并沒有去修改 stat 中的 count 值。我們也向 rust 社區(qū)反映了這個問題 [5]。

最后,回到我們最開始的問題中。要想解決 metrics 丟失的問題,在我們的代碼中,我們只需要做以下修改就能讓代碼正常運行[6]。

#[try_stream(ok=StateStoreIterItem,error=StorageError)]
asyncfninto_stream_inner(mutself){
letinner=self.inner;
...
self.stats.total_items+=1;
self.stats.total_size+=key.encoded_len()+value.len();
}

修改為

#[try_stream(ok=StateStoreIterItem,error=StorageError)]
asyncfninto_stream_inner(self){
letinner=self.inner;
letmutstats=self.stats;
...
stats.total_items+=1;
stats.total_size+=key.encoded_len()+value.len();
}

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 內(nèi)核
    +關注

    關注

    3

    文章

    1406

    瀏覽量

    41064
  • 代碼
    +關注

    關注

    30

    文章

    4886

    瀏覽量

    70215
  • Rust
    +關注

    關注

    1

    文章

    233

    瀏覽量

    6940

原文標題:踩坑 rust 的 partial copy 導致 metrics 丟失

文章出處:【微信號:Rust語言中文社區(qū),微信公眾號:Rust語言中文社區(qū)】歡迎添加關注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關推薦
    熱點推薦

    開發(fā)STM32 USB HID過的

    記錄一下 開發(fā)STM32 USB HID過的一、前言二、代碼配置一、前言MCU: STM32F103C8T6CubeMX: STM32CubeMX 5.3.0二、代碼配置引腳配置時鐘樹配置我
    發(fā)表于 08-24 07:15

    有沒有關于STM32入門經(jīng)驗分享

    有沒有關于STM32入門經(jīng)驗分享
    發(fā)表于 10-13 06:52

    NodeMCU開發(fā)板經(jīng)歷分享

    寫在前面今天入手了一個NodeMCU的板子,準備學習一下物聯(lián)網(wǎng)相關的知識。不過由于博主學藝不精,在第一步燒寫固件上就了,所以就想著把自己的經(jīng)歷寫出來分享給大家,希望能有一些幫助
    發(fā)表于 11-01 07:55

    Linux學習過程過的與如何解決

    Linux記錄記錄Linux學習過程過的與如何解決1解決方法:F10進入BIOS使能
    發(fā)表于 11-04 08:44

    移植debian系統(tǒng)過的

    基本的linux系統(tǒng),板子的交叉編譯器是arm-linux-gnueabihf-gcc,這給我?guī)砹瞬簧俚穆闊灾劣谙胫匦乱浦惨幌耫ebian系統(tǒng)。ok,轉(zhuǎn)入正題,說說這兩天我吧。首先...
    發(fā)表于 12-14 08:42

    STM32編程常有哪些?

    STM32編程常有哪些?
    發(fā)表于 12-17 06:15

    記錄寫SAM4S的bootloader所

    記錄寫SAM4S的bootloader所
    發(fā)表于 01-24 07:16

    嵌入式Linux記錄

    Linux記錄記錄Linux學習過程過的與如何解決1解決方法:F10進入BIOS使能
    發(fā)表于 11-01 17:21 ?10次下載
    嵌入式Linux<b class='flag-5'>踩</b><b class='flag-5'>坑</b>記錄

    將NodeMCU接入物聯(lián)網(wǎng)平臺的之路(阿里云、百度天工)

    將NodeMCU接入物聯(lián)網(wǎng)平臺的之路(阿里云、百度天工)
    發(fā)表于 11-29 18:06 ?15次下載
    將NodeMCU接入物聯(lián)網(wǎng)平臺的<b class='flag-5'>踩</b><b class='flag-5'>坑</b>之路(阿里云、百度天工)

    Arduino-IDE配置ESP32-CAM開發(fā)環(huán)境過的那些

    Arduino-IDE配置ESP32-CAM開發(fā)環(huán)境過的那些
    發(fā)表于 11-30 18:36 ?24次下載
    Arduino-IDE配置ESP32-CAM開發(fā)環(huán)境<b class='flag-5'>踩</b>過的那些<b class='flag-5'>坑</b>

    STM32CubeIDE+FREERTOS記錄

    STM32CubeIDE+FREERTOS記錄
    發(fā)表于 12-05 18:06 ?15次下載
    STM32CubeIDE+FREERTOS<b class='flag-5'>踩</b><b class='flag-5'>坑</b>記錄

    搭建D1s RT-Smart開發(fā)環(huán)境筆記

    作為一個linux新手想要嘗試RT-Smart的開發(fā),但是網(wǎng)上教程前輩們的linux環(huán)境都是已經(jīng)相對完備的,因此像我這樣新手在搭建環(huán)境時常常缺這缺那的導致報錯,經(jīng)過一段時間的終于搞定了,因此和大家分享我遇到的
    的頭像 發(fā)表于 09-28 16:26 ?1021次閱讀
    搭建D1s RT-Smart開發(fā)環(huán)境<b class='flag-5'>踩</b><b class='flag-5'>坑</b>筆記

    推挽電路的,你過沒?

    推挽電路的,你過沒?
    的頭像 發(fā)表于 11-24 16:25 ?1374次閱讀
    推挽電路的<b class='flag-5'>坑</b>,你<b class='flag-5'>踩</b>過沒?

    關于圖像傳感器圖像質(zhì)量的四大誤區(qū)!你過幾個

    關于圖像傳感器圖像質(zhì)量的四大誤區(qū)!你過幾個
    的頭像 發(fā)表于 11-27 16:56 ?611次閱讀
    關于圖像傳感器圖像質(zhì)量的四大誤區(qū)!你<b class='flag-5'>踩</b>過幾個<b class='flag-5'>坑</b>?

    反相輸入放大器的,你過沒有?

    反相輸入放大器的,你過沒有?
    的頭像 發(fā)表于 12-06 15:35 ?890次閱讀
    反相輸入放大器的<b class='flag-5'>坑</b>,你<b class='flag-5'>踩</b>過沒有?