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

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

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

OpenDAL如何實(shí)現(xiàn)數(shù)據(jù)讀取

jf_wN0SrCdH ? 來源: 漩渦視界 ? 2023-08-18 09:50 ? 次閱讀

隨著 OpenDAL 社區(qū)的不斷發(fā)展,新的抽象在不斷增加,為新的貢獻(xiàn)者參與開發(fā)帶來了不少負(fù)擔(dān),不少維護(hù)者都希望對(duì) OpenDAL 的內(nèi)部實(shí)現(xiàn)有更深入的了解。與此同時(shí),OpenDAL 的核心設(shè)計(jì)已經(jīng)很長(zhǎng)時(shí)間沒有大幅度的變化,為寫一個(gè)內(nèi)部實(shí)現(xiàn)系列提供了可能。我想現(xiàn)在是時(shí)候?qū)懸幌盗嘘P(guān)于 OpenDAL 內(nèi)部實(shí)現(xiàn)的文章,從維護(hù)者的角度來闡述 OpenDAL 如何設(shè)計(jì),如何實(shí)現(xiàn)以及如何擴(kuò)展。在 OpenDAL v0.40 即將發(fā)布之際,希望這系列文章能夠更好的幫助社區(qū)理解過去,掌握現(xiàn)在,并確定未來。

第一篇文章會(huì)先聊聊 OpenDAL 最常使用的數(shù)據(jù)讀取功能,我會(huì)從最外層的接口開始,然后按照 OpenDAL 的調(diào)用順序來逐步展開。讓我們開始吧!

整體框架

在開始介紹具體的 OpenDAL 接口之前,我們首先熟悉一下 OpenDAL 項(xiàng)目。

OpenDAL[1]是一個(gè) Apache Incubator 項(xiàng)目,旨在幫助用戶從各種存儲(chǔ)服務(wù)中以統(tǒng)一的方式便捷高效訪問數(shù)據(jù)。它的項(xiàng)目愿景[2]是 “自由訪問數(shù)據(jù)”:

?Free from services: 任意服務(wù)都能通過原生接口自由訪問

?Free from implementations: 無(wú)論底層實(shí)現(xiàn)如何,都可以通過統(tǒng)一的方式調(diào)用

?Free to integrate: 能夠自由地與各種服務(wù),語(yǔ)言集成

?Free to zero cost: 用戶不需要為用不到的功能付出開銷

在這套理念的基礎(chǔ)上,OpenDAL Rust Core 可以主要分成以下組成部分:

?Operator: 對(duì)用戶暴露的外層接口

?Layers: 不同中間件的具體實(shí)現(xiàn)

?Services: 不同服務(wù)的具體實(shí)現(xiàn)

所以從宏觀的角度上來看,OpenDAL 的數(shù)據(jù)讀取調(diào)用??雌饋頃?huì)像是這樣:

5ae2b634-3d0f-11ee-ac96-dac502259ad0.png

所有 Layers 和 Services 都實(shí)現(xiàn)了統(tǒng)一了 Accessor 接口,在進(jìn)行 Operator 構(gòu)建時(shí)會(huì)抹除所有的類型信息。對(duì) Operator 來說,不管用戶使用什么服務(wù)或者增加了多少中間件,所有的調(diào)用邏輯都是一致的。這一設(shè)計(jì)將 OpenDAL 的 API 拆分成了 Public API 和 Raw API 兩層,其中 Public API 直接暴露給用戶,提供便于使用的上層接口,而 Raw API 則是面向 OpenDAL 內(nèi)部開發(fā)者提供,維護(hù)統(tǒng)一的內(nèi)部接口,并提供一些便利的實(shí)現(xiàn)。

Operator

OpenDAL 的 Operator API 會(huì)盡可能遵循一致的調(diào)用范式,減少用戶的學(xué)習(xí)和使用成本。以read為例,OpenDAL 提供了以下 API:

?op.read(path): 將指定文件全部?jī)?nèi)容讀出

?op.reader(path): 創(chuàng)建一個(gè) Reader 用來做流式讀取

?op.read_with(path).range(1..1024): 使用指定參數(shù)來讀取文件內(nèi)容,比如說 range

?op.reader_with(path).range(1..1024): 使用指定參數(shù)來創(chuàng)建 Reader 做流式讀取

不難看出read更像是一個(gè)語(yǔ)法糖,用來方便用戶快速地進(jìn)行文件讀取而不需要考慮AsyncRead等各種 trait。而reader則給予了用戶更多的靈活度,實(shí)現(xiàn)了AsyncSeek,AsyncRead等社區(qū)廣泛使用的 trait,允許用戶更靈活的讀取數(shù)據(jù)。read_with和reader_with則通過 Future Builder 系列函數(shù),幫助用戶以更自然的方式來指定各種參數(shù)。

Operator 內(nèi)部的邏輯看起來會(huì)是這樣:

5b21961a-3d0f-11ee-ac96-dac502259ad0.png

它的主要工作是面向用戶封裝接口:

?完成OpRead的構(gòu)建

?調(diào)用Accessor提供的read函數(shù)

?將返回的值包裹為Reader并在Reader的基礎(chǔ)上實(shí)現(xiàn)AsyncSeek,AsyncRead等接口

Layers

這里有一個(gè)隱藏的小秘密是 OpenDAL 會(huì)自動(dòng)為 Service 套上一些 Layer 以實(shí)現(xiàn)一些內(nèi)部邏輯,截止到本文完成的時(shí)候,OpenDAL 自動(dòng)增加的 Layer 包括:

?ErrorContextLayer: 為所有的 Operation 返回的 error 注入 context 信息,比如scheme,path等

?CompleteLayer: 為服務(wù)補(bǔ)全必須的能力,比如說為 s3 增加 seek 支持

?TypeEraseLayer: 實(shí)現(xiàn)類型擦除,將Accessor中的關(guān)聯(lián)類型統(tǒng)一擦除,讓用戶使用時(shí)不需要攜帶泛型參數(shù)

這里的ErrorContextLayer和TypeEraseLayer都比較簡(jiǎn)單不再贅述,重點(diǎn)聊聊CompleteLayer,它旨在以零開銷的方式為 OpenDAL 返回的Reader增加seek或者next支持,讓用戶不需要再重復(fù)實(shí)現(xiàn)。OpenDAL 在早期版本中通過不同的函數(shù)調(diào)用來返回Reader和SeekableReader,但是用戶的實(shí)際反饋并不是很好,幾乎所有用戶都在使用SeekableReader。因此后續(xù) OpenDAL 在重構(gòu)中將 seek 支持作為第一優(yōu)先級(jí)加入了內(nèi)部的Readtrait 中:

pubtraitRead:Unpin+Send+Sync{
///Readbytesasynchronously.
fnpoll_read(&mutself,cx:&mutContext<'_>,buf:&mut[u8])->Poll>;

///Seekasynchronously.
///
///Returns`Unsupported`errorifunderlyingreaderdoesn'tsupportseek.
fnpoll_seek(&mutself,cx:&mutContext<'_>,pos:io::SeekFrom)->Poll>;

///Stream[`Bytes`]fromunderlyingreader.
///
///Returns`Unsupported`errorifunderlyingreaderdoesn'tsupportstream.
///
///ThisAPIexistsforavoidingbytescopyinginsideasyncruntime.
///Userscanpollbytesfromunderlyingreaderanddecidewhento
///read/consumethem.
fnpoll_next(&mutself,cx:&mutContext<'_>)->Poll>>;
}

在 OpenDAL 中實(shí)現(xiàn)一個(gè)服務(wù)的讀取能力就需要實(shí)現(xiàn)這個(gè) trait,這是一個(gè)內(nèi)部接口,不會(huì)直接暴露給用戶,其中:

?poll_read是最基礎(chǔ)的要求,所有服務(wù)都必須實(shí)現(xiàn)這一接口。

?當(dāng)服務(wù)原生支持seek時(shí),可以實(shí)現(xiàn)poll_seek,OpenDAL 會(huì)進(jìn)行正確的 dispatch,比如說 local fs;

?而當(dāng)服務(wù)原生支持next,即返回流式的 Bytes 時(shí),可以實(shí)現(xiàn)poll_next,比如說基于 HTTP 的服務(wù),他們底層是一個(gè) TCP Stream,hyper 會(huì)將其封裝為一個(gè) bytes stream。

通過Readtrait,OpenDAL 確保所有服務(wù)都能盡可能地暴露自己的原生支持能力,從而提供對(duì)不同服務(wù)都能實(shí)現(xiàn)高效的讀取。

在此 trait 的基礎(chǔ)上,OpenDAL 會(huì)根據(jù)各個(gè)服務(wù)支持的能力來進(jìn)行補(bǔ)全:

?seek/next 都支持:直接返回

?不支持 next: 使用StreamableReader進(jìn)行封裝以模擬 next 支持

?不支持 seek: 使用ByRangeSeekableReader進(jìn)行封裝以模擬 seek 支持

?seek/next 均不支持:同時(shí)進(jìn)行兩種封裝

ByRangeSeekableReader主要利用了服務(wù)支持 range read 的能力,當(dāng)用戶進(jìn)行 seek 的時(shí)候就 drop 當(dāng)前 reader 并在指定的位置發(fā)起新的請(qǐng)求。

OpenDAL 通過CompleteLayer暴露出一個(gè)統(tǒng)一的 Reader 實(shí)現(xiàn),用戶不需要考慮底層服務(wù)是否支持 seek,OpenDAL 總是會(huì)選擇最優(yōu)的方式來發(fā)起請(qǐng)求。

Services

經(jīng)過 Layers 的補(bǔ)全之后,就到調(diào)用 Service 具體實(shí)現(xiàn)的地方,這里分別以最常見的兩類服務(wù)fs和s3來舉例說明數(shù)據(jù)是如何讀取的。

Service fs

tokio::File實(shí)現(xiàn)了tokio::AsyncRead和tokio::AsyncSeek,通過使用async_compat::Compat,我們將其轉(zhuǎn)化為了futures::AsyncRead和futures::AsyncSeek。在此基礎(chǔ)上,我們提供了內(nèi)置的函數(shù)oio::into_read_from_file將其轉(zhuǎn)化為實(shí)現(xiàn)了oio::Read的類型,最終的類型名為:oio::FromFileReader>。

oio::into_read_from_file實(shí)現(xiàn)中沒有什么特別復(fù)雜的地方,read 和 seek 基本上都是在調(diào)用傳入的 File 類型提供的函數(shù)。比較麻煩的地方是關(guān)于 seek 和 range 的正確處理:seek 到 range 右側(cè)是允許的行為,此時(shí)不會(huì)報(bào)錯(cuò),read 也只會(huì)返回空,但是 seek 到 range 左側(cè)是非法行為,Reader 必須返回InvalidInput以便于上層正確處理。

有趣的歷史:當(dāng)初這塊實(shí)現(xiàn)的時(shí)候有問題,還是在 fuzz 測(cè)試中發(fā)現(xiàn)的。

Services s3

S3 是一個(gè)基于 HTTP 的服務(wù),opendal 提供了大量基于 HTTP 的封裝以幫助開發(fā)者重用邏輯,只需要構(gòu)建請(qǐng)求,并返回構(gòu)造好的 Body 即可。OpenDAL Raw API 封裝了一套基于 reqwest 的接口,HTTP GET 接口會(huì)返回一個(gè)Response

///IncomingAsyncBodycarriesthecontentreturnedbyremoteservers.
pubstructIncomingAsyncBody{
///#TODO
///
///hyperreturns`implStream>`butwecan't
///writethetypesinstable.Sowewillboxhere.
///
///After[TAIT](https://rust-lang.github.io/rfcs/2515-type_alias_impl_trait.html)
///hasbeenstable,wecanchange`IncomingAsyncBody`into`IncomingAsyncBody`.
inner:oio::Streamer,
size:Option,
consumed:u64,
chunk:Option,
}

這個(gè) body 內(nèi)部包含的 stream 是 reqwest 返回的 bytes stream,opendal 在此基礎(chǔ)上實(shí)現(xiàn)了 content length 檢查和 read 支持。

這里額外提一嘴關(guān)于 reqwest/hyper 的小坑:reqwets 和 hyper 并沒有檢查返回的 content length,所以一個(gè)非法的 server 可能會(huì)返回與預(yù)期的 content length 不符的數(shù)據(jù)量而非報(bào)錯(cuò),進(jìn)而導(dǎo)致數(shù)據(jù)的行為不符合預(yù)期。OpenDAL 在這里專門增加了檢查,在數(shù)據(jù)不足時(shí)返回ContentIncomplete,并在數(shù)據(jù)超出預(yù)期時(shí)返回ContentTruncated,避免用戶收到非法的數(shù)據(jù)。

總結(jié)

本文自頂向下介紹了 OpenDAL 如何實(shí)現(xiàn)數(shù)據(jù)讀?。?/p>

?Operator 負(fù)責(zé)對(duì)用戶暴露易用的接口

?Layers 負(fù)責(zé)對(duì)服務(wù)的能力進(jìn)行補(bǔ)全

?Services 負(fù)責(zé)不同服務(wù)的具體實(shí)現(xiàn)

在整個(gè)鏈路中 OpenDAL 都盡可能遵循零開銷的原則,優(yōu)先使用服務(wù)原生提供能力,其次再考慮通過其他的方法進(jìn)行模擬,最后才會(huì)返回不支持的報(bào)錯(cuò)。通過這三層的設(shè)計(jì),用戶不需要了解底層服務(wù)的細(xì)節(jié),也不需要接入不同服務(wù)的 SDK 就可以輕松地調(diào)用op.read(path)來訪問任意存儲(chǔ)服務(wù)中的數(shù)據(jù)。

這就是: HowOpenDALread data freely!

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

    關(guān)注

    33

    文章

    8598

    瀏覽量

    151157
  • API
    API
    +關(guān)注

    關(guān)注

    2

    文章

    1501

    瀏覽量

    62017
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4331

    瀏覽量

    62618
  • 數(shù)據(jù)讀取
    +關(guān)注

    關(guān)注

    0

    文章

    9

    瀏覽量

    6530

原文標(biāo)題:OpenDAL 內(nèi)部實(shí)現(xiàn):數(shù)據(jù)讀取

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

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    如何在MCS中實(shí)現(xiàn)ADC數(shù)據(jù)讀取?

    周期使能MCS0的CH0和CH1,CH0可以正常被多次運(yùn)行,但是CH1僅被執(zhí)行一次;如果需要實(shí)現(xiàn)多通道的運(yùn)行,需要怎么處理呢? 在CH0中通過AEI總線讀取CH0的AD數(shù)據(jù),AD C采樣觸發(fā)正常
    發(fā)表于 07-24 07:59

    ADS1299的配套軟件不支持讀取級(jí)聯(lián)的其他芯片的數(shù)據(jù),如何實(shí)現(xiàn)讀取級(jí)聯(lián)的多個(gè)芯片的數(shù)據(jù)呢?

    ADS1299的配套軟件不支持讀取級(jí)聯(lián)的其他芯片的數(shù)據(jù),如何實(shí)現(xiàn)讀取級(jí)聯(lián)的多個(gè)芯片的數(shù)據(jù)呢,是用stm32進(jìn)行spi通信嗎,如何
    發(fā)表于 11-13 06:36

    FPGA怎么實(shí)現(xiàn)控制CF從SDRAM中讀取數(shù)據(jù)實(shí)現(xiàn)CF卡向SDRAM傳數(shù)據(jù)

    FPGA怎么實(shí)現(xiàn)控制CF從SDRAM中讀取數(shù)據(jù)以及實(shí)現(xiàn)CF卡向SDRAM中上傳數(shù)據(jù)????本人初學(xué)者,希望大家?guī)蛶兔Γ。。。≈x謝?。?/div>
    發(fā)表于 02-25 21:58

    LabvIEW中如何實(shí)現(xiàn)大容量數(shù)據(jù)的快速讀取呢?

    LabvIEW中如何實(shí)現(xiàn)大容量數(shù)據(jù)的快速讀取呢?我試過將數(shù)據(jù)存放在excel表中,然后用讀取電子表格VI去
    發(fā)表于 10-08 21:25

    實(shí)現(xiàn) Labview 和SQL server進(jìn)行數(shù)據(jù)讀取和寫入

    我想實(shí)現(xiàn)以下功能:Labview讀取SQL server中的一個(gè)表格,鼠標(biāo)點(diǎn)擊選中某一行,此行處于被選中狀態(tài)(顏色變深),點(diǎn)擊保存按鈕,將實(shí)時(shí)數(shù)組中的數(shù)據(jù)存入此行,并寫入SQL server。其他
    發(fā)表于 09-07 09:25

    MOVC實(shí)現(xiàn)讀取程序存儲(chǔ)區(qū)域的靜態(tài)數(shù)據(jù)

    51單片機(jī) 特殊指令MOVC實(shí)現(xiàn)讀取程序存儲(chǔ)區(qū)域的靜態(tài)數(shù)據(jù),只能讀取,不能寫入,因此不能實(shí)現(xiàn)自編程。 外部存儲(chǔ)器通過P2、P0端口連接地址和
    發(fā)表于 11-23 09:10

    基于CPLD的Flash讀取控制的設(shè)計(jì)與實(shí)現(xiàn)

            在使用Flash 存儲(chǔ)數(shù)據(jù)時(shí),有時(shí)需要對(duì)其設(shè)計(jì)讀寫控制邏輯。本文介紹了用VHDL 語(yǔ)言在CPLD內(nèi)部編程,實(shí)現(xiàn)對(duì)Flash 中數(shù)據(jù)
    發(fā)表于 09-04 09:29 ?35次下載

    衛(wèi)星SAR數(shù)據(jù)讀取與保存方法研究與軟件實(shí)現(xiàn)

    基于GDAL、OpenGL、TinyXML和HDF5等開源庫(kù),對(duì)目前主要的衛(wèi)星SAR傳感器-ENVISAT、ERS、Radarsat、TerraSAR-X、CosmoSkyMed產(chǎn)品的數(shù)據(jù)及其屬性進(jìn)行讀取、顯示和保存的關(guān)鍵技術(shù)研究及其軟件
    發(fā)表于 01-08 16:21 ?28次下載

    TensorFlow數(shù)據(jù)讀取機(jī)制分析

    在學(xué)習(xí)TensorFlow的過程中,有很多小伙伴反映讀取數(shù)據(jù)這一塊很難理解。確實(shí)這一塊官方的教程比較簡(jiǎn)略,網(wǎng)上也找不到什么合適的學(xué)習(xí)材料。今天這篇文章就以圖片的形式,用最簡(jiǎn)單的語(yǔ)言,為大家詳細(xì)
    發(fā)表于 09-28 17:45 ?0次下載
    TensorFlow<b class='flag-5'>數(shù)據(jù)</b><b class='flag-5'>讀取</b>機(jī)制分析

    Windows Server實(shí)現(xiàn)RAID技術(shù),保證數(shù)據(jù)讀取速度和安全

    保證數(shù)據(jù)讀取速度和安全,Windows Server 2008 R2如何實(shí)現(xiàn)RAID技術(shù)。在Windows操作系統(tǒng)中,數(shù)據(jù)都保存在磁盤中,并以分區(qū)或卷的形式作為目錄結(jié)構(gòu)的頂級(jí)。
    的頭像 發(fā)表于 12-06 16:12 ?4373次閱讀

    使用STM32單片機(jī)實(shí)現(xiàn)AD7606并行讀取數(shù)據(jù)的代碼免費(fèi)下載

    本文檔的主要內(nèi)容詳細(xì)介紹的是使用STM32單片機(jī)實(shí)現(xiàn)AD7606并行讀取數(shù)據(jù)的代碼免費(fèi)下載。
    發(fā)表于 03-13 08:00 ?94次下載
    使用STM32單片機(jī)<b class='flag-5'>實(shí)現(xiàn)</b>AD7606并行<b class='flag-5'>讀取</b><b class='flag-5'>數(shù)據(jù)</b>的代碼免費(fèi)下載

    用STM32實(shí)現(xiàn)MPU6050原始數(shù)據(jù)讀取

    STM32+MPU6050讀取加速度計(jì)和陀螺儀原始數(shù)據(jù)。
    發(fā)表于 12-06 11:51 ?11次下載
    用STM32<b class='flag-5'>實(shí)現(xiàn)</b>MPU6050原始<b class='flag-5'>數(shù)據(jù)</b>的<b class='flag-5'>讀取</b>

    內(nèi)存是怎么讀取數(shù)據(jù)

    你知道內(nèi)存是怎么讀取數(shù)據(jù)的嗎?知道數(shù)據(jù)是怎么一個(gè)一個(gè)字節(jié)發(fā)送的嗎?
    的頭像 發(fā)表于 03-30 13:52 ?5460次閱讀

    基于C#實(shí)現(xiàn)文本讀取的7種方式是什么

    文本讀取在上位機(jī)開發(fā)中經(jīng)常會(huì)使用到,實(shí)現(xiàn)的方式也有很多種,今天跟大家分享一下C#實(shí)現(xiàn)讀取讀取的7種方式。基于FileStream,并結(jié)合它的
    的頭像 發(fā)表于 02-22 15:38 ?1876次閱讀
    基于C#<b class='flag-5'>實(shí)現(xiàn)</b>文本<b class='flag-5'>讀取</b>的7種方式是什么

    labview visa讀取數(shù)據(jù)越來越慢

    實(shí)際上,LabVIEW通過VISA(Virtual Instrument Software Architecture)來與儀器通信。但是,有時(shí)候在使用VISA讀取數(shù)據(jù)時(shí),可能會(huì)遇到讀取速度變慢
    的頭像 發(fā)表于 01-08 10:00 ?3172次閱讀