国产91在线|日韩,色国产精品一区在线观看,亚洲国产综合网,亚洲国产精品久久网午夜,欧美变态人zozo禽交,久久综合伊人77777麻豆,午夜亚洲国产成人不卡在线

開源OA系統(tǒng):巫山政府辦公oa系統(tǒng)中自己動(dòng)手寫數(shù)據(jù)庫系統(tǒng):容災(zāi)恢復(fù)原理和容災(zāi)恢復(fù)日志的設(shè)計(jì)

時(shí)間:2025-02-08 05:34:43 信創(chuàng)OA資訊首頁 廣州政府機(jī)關(guān)oa

PHPOA!國內(nèi)首家專業(yè)OA辦公軟件、OA系統(tǒng)、政務(wù)辦公開源oa系統(tǒng)服務(wù)提供商,采用PHP+MYSQL開源語言,一直致力于應(yīng)用管理軟件基層研發(fā),現(xiàn)己推出企業(yè)OA、政府OA、集團(tuán)OA、SAAS版OA等應(yīng)用平臺(tái),詳細(xì)咨詢13807814037 現(xiàn)在論壇購買,只需588元

開源政務(wù)OA系統(tǒng):巫山政府辦公政務(wù)OA系統(tǒng)中自己動(dòng)手寫數(shù)據(jù)庫系統(tǒng):容災(zāi)恢復(fù)原理和容災(zāi)恢復(fù)日志的設(shè)計(jì)代化和數(shù)字化已成為企業(yè)和機(jī)構(gòu)發(fā)展的必然趨勢。作為一種重要的辦公工具,公文管理系統(tǒng)在提高工作效率和便利性方面發(fā)揮著重要作用數(shù)據(jù)出現(xiàn)不一致性,也就是機(jī)票出票數(shù)量和相應(yīng)的支付款項(xiàng)不一致,沒有容錯(cuò)性的數(shù)據(jù)庫系統(tǒng)就不會(huì)有市場,本節(jié)的目的是設(shè)計(jì)恢復(fù)機(jī)制,確保數(shù)據(jù)在任何突如其來的意外情況下依然保持?jǐn)?shù)據(jù)一致性。 因此數(shù)據(jù)庫系統(tǒng)必須遵守acid原則,他們分別是atomicity, consistency, isolation, durability: atomicity: 其意思是任何數(shù)據(jù)操作要不完全執(zhí)行,要不就一點(diǎn)作用也沒有。數(shù)據(jù)庫中有一個(gè)叫“交易”的概念,也就是tra


世界首例針對(duì)特斯拉自動(dòng)駕駛判罰:德國裁定autopilot廣告誤導(dǎo)買家,特斯拉柏林工廠可能受阻:

保留上訴權(quán),但特斯拉還是改了宣傳這個(gè)案件中,做出最終裁決的是慕尼黑法院,但原告并不是德國政府監(jiān)管機(jī)構(gòu),而是德國反不公平競爭與保護(hù)中心(wettbewerbszentrale),一個(gè)反不當(dāng)競爭的民間獨(dú)立機(jī)構(gòu) 此外,特斯拉的宣傳,還帶著暗示——相關(guān)的自動(dòng)駕駛系統(tǒng)已經(jīng)在德國得到法律法規(guī)允許。但實(shí)際并沒有。外媒路透也評(píng)價(jià)說,特斯拉這種宣傳還帶來更進(jìn)一步的社會(huì)問題。? 但德國法院的判決也不是完全沒有影響,外媒分析,至少特斯拉柏林工廠可能會(huì)受阻。路透社透露,特斯拉柏林工廠一開始籌建就不是一帆風(fēng)順的。 首先是德國地方政府給了特斯拉建廠一些支持政策,但并不像中國上海一樣大力支持特斯拉。中央政府層面,德國聯(lián)邦政府給予的電動(dòng)車購置優(yōu)惠也沒有中國政府力度大。 所以現(xiàn)在德國的判例,對(duì)特斯拉的自動(dòng)駕駛,可能只是一個(gè)開始。更多國家的交通安全部門、車主幸存者,或許會(huì)以此為契機(jī),在更多國家和地區(qū),向特斯拉討要說法。

運(yùn)維大數(shù)據(jù)平臺(tái)落地構(gòu)想:

微信圖片_20190801133837.jpg 現(xiàn)在全國政務(wù)行業(yè)都在推行數(shù)字政府、數(shù)字中國的落地。 大部分省市都在進(jìn)行iaas資源、paas資源、daas資源以及saas資源的整合;構(gòu)建基于ipds架構(gòu)的云平臺(tái)數(shù)據(jù)中心,通過ipds云平臺(tái)數(shù)據(jù)中心,為用戶提供各類資源服務(wù)。 上述是以政務(wù)為例,回望企業(yè)客戶,建設(shè)路徑亦如此。 同時(shí)傳統(tǒng)的監(jiān)控能對(duì)單個(gè)點(diǎn)進(jìn)行監(jiān)控,很難結(jié)合cmdb配置平臺(tái)實(shí)現(xiàn)關(guān)聯(lián)關(guān)系的監(jiān)控,即某個(gè)點(diǎn)出現(xiàn)故障時(shí),會(huì)影響到哪些業(yè)務(wù),哪些操作系統(tǒng)。 作者:何世曉

【陽光私塾】告密者,一種歷史幽靈的閃現(xiàn):

這所我曾經(jīng)應(yīng)邀前往演講的學(xué)校,涌現(xiàn)出兩名杰出的學(xué)生告密者,她們將自己的“古代漢語”老師告到市教委和公安局,理由是在課堂上“批評(píng)文化”和“批評(píng)政府”。 這種復(fù)雜的四重監(jiān)視體系,培訓(xùn)了龐大的告密者隊(duì)伍,成為專制王朝的最大幫手。 這場從告密開始的運(yùn)動(dòng),最終升溫到令人發(fā)指的地步,據(jù)廣西《武宣縣無產(chǎn)階級(jí)文化大革命大事件》記載,該縣武宣中學(xué),甚至出現(xiàn)食人盛宴——眾學(xué)生在校園內(nèi)揭發(fā)批斗完自己的老師之后,將他們剖腹肢解,就地架設(shè)爐灶,烹煮至熟 眾所周知,批評(píng)是幫助政府改進(jìn)工作和推動(dòng)社會(huì)進(jìn)步的重要方式,也是憲法賦予的基本權(quán)利。 容忍和聽取不同意見,乃是衡量政治清明的基本標(biāo)尺,而在以“和諧”為政治目標(biāo)的社會(huì)中營造斗爭氣氛,置敢說真話的教師于被告密的恐懼之中,這不僅是以司法教育為使命的高等學(xué)府的恥辱,更是社會(huì)正義和民主進(jìn)程的敵人。

美國對(duì)勒索軟件重拳出擊,成立特別小組,懸賞1000萬美元:

(nist) 以及財(cái)政部、衛(wèi)生與公眾服務(wù)部的最新勒索軟件相關(guān)警報(bào)和威脅的指南。 拜登政府顯然也在考慮對(duì)黑客團(tuán)伙發(fā)動(dòng)破壞性網(wǎng)絡(luò)攻擊的可能性,并努力與私營部門組織(包括網(wǎng)絡(luò)保險(xiǎn)提供商和關(guān)鍵基礎(chǔ)設(shè)施公司)建立伙伴關(guān)系,以分享有關(guān)勒索軟件攻擊的信息。 阿波羅信息系統(tǒng)公司和ciso公司副總裁安迪·貝內(nèi)特說,現(xiàn)在的問題是接下來會(huì)發(fā)生什么。他們將如何超越聯(lián)邦政府的職能,使整個(gè)國家都有能力和賦權(quán)? 他還指出,各機(jī)構(gòu)之間的合作對(duì)于制定戰(zhàn)略和結(jié)合專業(yè)知識(shí)來應(yīng)對(duì)當(dāng)前勒索軟件攻擊的流行至關(guān)重要。與傳統(tǒng)恐怖主義不同,網(wǎng)絡(luò)攻擊和反擊手段并非政府所獨(dú)有。 這個(gè)特別小組是絕對(duì)值得的,如果做對(duì)了,將對(duì)打擊和建立政府所有領(lǐng)域的勒索軟件的復(fù)原力產(chǎn)生重大影響,他總結(jié)道。原文翻譯自helpnetsecurity

開源政務(wù)OA系統(tǒng):巫山政府辦公政務(wù)OA系統(tǒng)中自己動(dòng)手寫數(shù)據(jù)庫系統(tǒng):容災(zāi)恢復(fù)原理和容災(zāi)恢復(fù)日志的設(shè)計(jì)

勢,并討論如何在實(shí)踐中有效地應(yīng)用和管理這一系統(tǒng)。一、公文管理系統(tǒng)的定義 公文管理系統(tǒng)是一種基于計(jì)算機(jī)技術(shù)的軟件系統(tǒng),用于管理和處理各類公文文件。它通過數(shù)字化和自動(dòng)化的方式,將公文的創(chuàng)建、審批、傳遞和歸檔等環(huán)節(jié)進(jìn)行整合和優(yōu)化,從而提高工作效率和管理水平。二、公文管理系統(tǒng)的功能 1.公文創(chuàng)建和編輯:公文管理系統(tǒng)提供了豐富的模板和格式,使得公文的創(chuàng)建和編輯變得簡單和規(guī)范化。用戶可以根據(jù)需要選擇相應(yīng)的模板,填寫相關(guān)內(nèi)容,并進(jìn)行格式調(diào)整和排版。2.公文審批和流轉(zhuǎn):公文管理系統(tǒng)實(shí)現(xiàn)了公文的電子審批和流轉(zhuǎn),取代了傳統(tǒng)的紙質(zhì)審批流程。通過系統(tǒng)的設(shè)置,可以實(shí)現(xiàn)多級(jí)審批、并行審批和串行審批等不同的審批方式,大大縮短了審批時(shí)間和流轉(zhuǎn)周期。3.公文傳遞和共享:公文管理系統(tǒng)支持公文的電子傳遞和共享,使得公文的傳遞更加數(shù)據(jù)庫系統(tǒng)有一個(gè)極其重要的功能,那就是要保持?jǐn)?shù)據(jù)一致性。在用戶往數(shù)據(jù)庫寫入數(shù)據(jù)后,如果數(shù)據(jù)庫返回寫入成功,那么數(shù)據(jù)就必須永久性的保存在磁盤上。此外作為一個(gè)系統(tǒng),它必須具備自恢復(fù)功能,也就是如果系統(tǒng)出現(xiàn)意外奔潰,無論是內(nèi)部錯(cuò)誤,還是外部原因,例如突然斷電等,系統(tǒng)都必須要保持?jǐn)?shù)據(jù)的一致性。 例如我們從數(shù)據(jù)庫中訂購一張機(jī)票,假設(shè)機(jī)票數(shù)量正確減一,但還沒扣款,此時(shí)系統(tǒng)突然奔潰,如果系統(tǒng)沒有預(yù)防措施就會(huì)導(dǎo)致數(shù)據(jù)出現(xiàn)不一致性,也就是機(jī)票出票數(shù)量和相應(yīng)的支付款項(xiàng)不一致,沒有容錯(cuò)性的數(shù)據(jù)庫系統(tǒng)就不會(huì)有市場,本節(jié)的目的是設(shè)計(jì)恢復(fù)機(jī)制,確保數(shù)據(jù)在任何突如其來的意外情況下依然保持?jǐn)?shù)據(jù)一致性。 因此數(shù)據(jù)庫系統(tǒng)必須遵守acid原則,他們分別是atomicity, consistency, isolation, durability: atomicity: 其意思是任何數(shù)據(jù)操作要不完全執(zhí)行,要不就一點(diǎn)作用也沒有。數(shù)據(jù)庫中有一個(gè)叫“交易”的概念,也就是transation,它表示一系列必須全部完成的讀寫操作,必須是序列化的,也就是交易所給定的執(zhí)行步驟在運(yùn)行時(shí)不能被打斷,或者是中間突然插入其他交易的步驟,所以它也叫原子化。 consistency:意思是任何交易都必須確保數(shù)據(jù)處于一致狀態(tài)。也就是說交易中所定義的一系列讀寫步驟必須作為一個(gè)統(tǒng)一的單元進(jìn)行執(zhí)行,當(dāng)交易進(jìn)行時(shí),數(shù)據(jù)庫系統(tǒng)的運(yùn)行狀態(tài)就好像是一個(gè)單線程應(yīng)用。 isolation:意思是交易執(zhí)行時(shí),它的執(zhí)行環(huán)境或者上下文使得它好像是整個(gè)系統(tǒng)唯一正在運(yùn)行的交易,實(shí)際上同一時(shí)刻可能有多個(gè)交易正在執(zhí)行,但系統(tǒng)必須保證每個(gè)交易運(yùn)行時(shí)就好像整個(gè)系統(tǒng)只有它一個(gè)。 durability: 思思是任何被執(zhí)行完畢的交易所更改的數(shù)據(jù)必須持久化的存儲(chǔ)在磁盤或相關(guān)介質(zhì)上。 要保證acid原則的執(zhí)行,我們需要設(shè)計(jì)兩個(gè)模塊,分別是恢復(fù)管理器和并發(fā)管理器,前者確保系統(tǒng)在出現(xiàn)意外奔潰或關(guān)閉時(shí),數(shù)據(jù)依然處于一致性狀態(tài),后者確保多個(gè)交易在同時(shí)進(jìn)行時(shí),相互之間不產(chǎn)生干擾,本節(jié)先著重前者的實(shí)現(xiàn)。 恢復(fù)管理器的功能依賴于日志,系統(tǒng)在將數(shù)據(jù)寫入磁盤前,必須將寫入前的數(shù)據(jù)和寫入后的數(shù)據(jù)記錄在日志中,這樣恢復(fù)管理器才能從日志中將數(shù)據(jù)還原,相應(yīng)的日志格式如下: 代碼語言:javascript 復(fù)制 <start, 1> <commit , 1> <start , 2> <setint, 2, testfile, 1, 80, 1 ,2> <setstring, 2, testfile, 1, 40, one, one!> <commit, 2> <start, 3> <setint, 3, testfile, 1, 80, 2, 9999> <rollback, 3> <start, 4> <commit, 4> 上面日志的邏輯為表示系統(tǒng)啟動(dòng)一次交易,交易對(duì)應(yīng)的號(hào)碼為1, 從上面日志可以看到,交易1啟動(dòng)后什么數(shù)據(jù)都沒有寫入就直接完成交易。然后系統(tǒng)啟動(dòng)交易2,日志表示交易2向文件testfile寫入整形數(shù)據(jù),寫入的區(qū)塊號(hào)為1,在區(qū)塊內(nèi)部的偏移為80,在寫入前給定位置的數(shù)據(jù)為數(shù)值1,寫入后數(shù)據(jù)變?yōu)?。我們可以發(fā)現(xiàn)有了這樣的日志,恢復(fù)管理器就能執(zhí)行災(zāi)后恢復(fù),例如系統(tǒng)在進(jìn)行交易2時(shí),在執(zhí)行setint操作時(shí),系統(tǒng)突然奔潰,下次重啟后回復(fù)管理器讀取日志,它會(huì)發(fā)現(xiàn)有但是找不到對(duì)應(yīng)的于是這時(shí)它就明白交易2在進(jìn)行過程中發(fā)送了錯(cuò)誤使得交易沒有完成,此時(shí)它就能執(zhí)行恢復(fù),它讀取日志,于是就能知道交易2在文件testfile的區(qū)塊1中,偏移80字節(jié)處寫入了數(shù)值2,在寫入前數(shù)值為1,于是它就能將數(shù)值1重新寫入到testfile文件區(qū)塊1偏移為80字節(jié)位置,于是就相當(dāng)于恢復(fù)了原來的寫操作。 從上面日志可以看出,對(duì)于交易的記錄總共有四種類型,分別為start, commit, rollback, 和update,update分為兩種情況,也就是setint,寫入整形數(shù)值,setstring,寫入字符串。這里需要注意的是,系統(tǒng)為了支持高并發(fā)就會(huì)允許多個(gè)交易同時(shí)進(jìn)行,于是有關(guān)交易的日志就會(huì)交叉出現(xiàn)在日志中,例如有可能,之后就會(huì)跟著等等,不同交易的日志記錄交叉出現(xiàn)不會(huì)影響我們的識(shí)別邏輯,因?yàn)橥粋€(gè)交易不同時(shí)間操作一定會(huì)從上到下的呈現(xiàn)。 有了日志系統(tǒng)也能支持回滾操作,假設(shè)交易3寫入數(shù)值9999到文件testfile區(qū)塊號(hào)為1,偏移為80的位置,那么它會(huì)先生成日志,然后它立刻進(jìn)行回滾操作,這時(shí)候我們可以從日志中發(fā)現(xiàn),寫入9999前,對(duì)應(yīng)位置的數(shù)值是2,于是我們只要把數(shù)值2重新寫入?yún)^(qū)塊號(hào)為1偏移為80的位置就相當(dāng)于還原了寫入操作。因此回滾操作的步驟如下: 1,獲得要執(zhí)行回滾操作的交易號(hào)x 2,從下往上讀取日志,如果記錄對(duì)應(yīng)的交易號(hào)不是x,那么忽略,繼續(xù)往上讀取 3,如果交易號(hào)是x,讀取日志中數(shù)據(jù)寫入前的數(shù)據(jù), 4,將寫入前的數(shù)據(jù)重新寫入到日志記錄的位置,繼續(xù)執(zhí)行步驟2 注意執(zhí)行回滾時(shí),我們要從日志文件的底部往前讀,因?yàn)橐粋€(gè)地方的數(shù)值可能會(huì)被寫入多次,假設(shè)testfile區(qū)塊號(hào)為1,偏移為80的地方,在第一次寫入前數(shù)值為1,假設(shè)交易對(duì)這個(gè)位置分別寫入了3次,寫入的數(shù)值為2,3,4,那么回滾后給定位置的數(shù)值應(yīng)該恢復(fù)為1,要實(shí)現(xiàn)這個(gè)效果,我們必須要從日志的底部往上讀取。 我們再看容災(zāi)恢復(fù),每次系統(tǒng)啟動(dòng)時(shí)它首先要執(zhí)行災(zāi)后恢復(fù)工作。其目的是要保持?jǐn)?shù)據(jù)的“一致性”,所謂“一致性”是指,所有沒有執(zhí)行commit的交易,它所寫入的數(shù)據(jù)都要恢復(fù)為寫入前的數(shù)據(jù),所有已經(jīng)執(zhí)行了commit的交易,一定要確保寫入的數(shù)據(jù)都已經(jīng)存儲(chǔ)到磁盤上。第二種情況完全有可能發(fā)生,因?yàn)閿?shù)據(jù)會(huì)首先寫入內(nèi)存,然后系統(tǒng)會(huì)根據(jù)具體情況有選擇的將數(shù)據(jù)寫入磁盤,這是出于效率考慮,假設(shè)交易執(zhí)行了commit操作,部分寫入的數(shù)據(jù)還存儲(chǔ)在內(nèi)存中,此時(shí)系統(tǒng)突然奔潰,那么這部分在內(nèi)存中的數(shù)據(jù)就不會(huì)寫入到磁盤。 在恢復(fù)管理器看來,只要日志中有了commit記錄,那么交易就完成了,但是它并不能保證交易寫入的數(shù)據(jù)都已經(jīng)存儲(chǔ)在磁盤上了。所以恢復(fù)管理器有可能需要將日志中已經(jīng)完成的交易再執(zhí)行一次。 從上面描述可以看到,恢復(fù)管理器嚴(yán)重依賴于日志,因此我們必須確保在數(shù)據(jù)寫入前,日志必須要先完成,如果順序倒過來,先寫入數(shù)據(jù),再寫入日志,如果寫入數(shù)據(jù)后系統(tǒng)突然奔潰,那么寫入信息就不會(huì)記錄在日志里,那么恢復(fù)管理器就不能執(zhí)行恢復(fù)功能了。要執(zhí)行交易的重新執(zhí)行功能,需要執(zhí)行的步驟如下: 1,從頭開始讀取日志 2,當(dāng)遇到”“ 類似的日志時(shí),記錄下當(dāng)前交易號(hào)。 3,如果讀到的日志時(shí),將數(shù)值2再次寫入到文件testfile,區(qū)塊號(hào)為1,偏移為80的地方 恢復(fù)管理器在重新執(zhí)行交易時(shí),它需要對(duì)日志進(jìn)行兩次掃描,第一次掃描是從底部往上讀取日志,這樣恢復(fù)管理器才能知道哪些交易已經(jīng)執(zhí)行了commit操作,同時(shí)執(zhí)行undo功能,也就是將沒有執(zhí)行commit操作的交易修改進(jìn)行恢復(fù),于是第一次掃描時(shí)它把那些已經(jīng)執(zhí)行commit操作的交易號(hào)記錄下來,第二次掃描則是從日志的頭開始讀取,一旦讀到這樣的日志時(shí),它會(huì)查找x是否是第一次掃描時(shí)已經(jīng)記錄下來的執(zhí)行了commit操作的日志,如果是,那么它將x對(duì)應(yīng)的setint,setstring操作再執(zhí)行一次,然后要求緩存管理器立馬將寫入的數(shù)據(jù)存儲(chǔ)到磁盤上。 問題在于第二步也就是重新執(zhí)行交易對(duì)應(yīng)操作可能不必要,因?yàn)榻灰仔薷臉O有可能已經(jīng)寫入到磁盤,如果再次進(jìn)行磁盤寫操作就會(huì)降低系統(tǒng)效率。我們可以避免第二步重寫操作,只要我們讓緩存管理器把所有修改先寫入磁盤,然后再把commit記錄寫入日志即可,這樣帶來的代價(jià)是由于系統(tǒng)要頻繁的寫入磁盤由此會(huì)降低系統(tǒng)效率。同時(shí)我們也能讓第一步變得沒有必要,只要我們確保交易在執(zhí)行commit前數(shù)據(jù)不寫入磁盤即可,但如此帶來的代價(jià)是,緩存的數(shù)據(jù)不寫入磁盤,那么系統(tǒng)的吞吐量就會(huì)下降,因?yàn)榫彺鏀?shù)據(jù)不寫入磁盤,緩存頁面就不能重新分配,于是新的交易就無法執(zhí)行,因?yàn)榈貌坏骄彺妗?現(xiàn)在還存在一個(gè)問題是,系統(tǒng)運(yùn)行久了日志會(huì)非常龐大,它的數(shù)量甚至比數(shù)據(jù)要大,如果每次恢復(fù)都要讀取日志,那么恢復(fù)流程會(huì)越來越久。因此恢復(fù)管理器在執(zhí)行時(shí),它只能讀取部分日志,問題在于它如何決定讀取多少日志數(shù)據(jù)呢。它只需要知道兩個(gè)條件就能停止繼續(xù)讀取日志: 1,當(dāng)前讀取位置以上的日志都對(duì)應(yīng)已經(jīng)執(zhí)行了commit操作的交易 2,所有已經(jīng)執(zhí)行commit的交易,其數(shù)據(jù)都已經(jīng)寫入到了磁盤。 當(dāng)恢復(fù)管理器知道第一點(diǎn),那么它就不用在執(zhí)行回滾操作,知道第二點(diǎn)就不需要再將已經(jīng)commit的操作再次執(zhí)行。為了滿足滿足以上兩點(diǎn),系統(tǒng)需要執(zhí)行以下步驟: 1,停止啟動(dòng)新的交易 2,等待當(dāng)前所有正在進(jìn)行的交易全部完成 3,將所有修改的緩存寫入磁盤 4,插入一個(gè)中斷點(diǎn)日志表示上面操作已經(jīng)完成,并將中斷點(diǎn)日志寫入磁盤文件 5,開始接收新的交易 我們看一個(gè)具體例子: 代碼語言:javascript 復(fù)制 <start, 0> <setint, 0, junk, 33, 8, 542, 543> <start, 1> <start, 2> <setstring, 2, junk, 44, 20, hello, ciao> //在這里啟動(dòng)上面步驟,停止接收新的交易 <setint, 0, junk, 33, 12, joe, joseph> <commit, 0> //交易3準(zhǔn)備發(fā)起,但是它只能等待 <setint, 2 , junk, 66, 8, 0, 116> <commit, 2> <checkpont> //中斷點(diǎn),上面的日志不用再考慮,下面交易3可以啟動(dòng) <start, 3> <setint, 3, junk, 33, 8, 43, 120> 從上面日志中,恢復(fù)管理器從下往上讀取時(shí),只要看到checkpoint記錄就可以停止了。這種做法也有明顯缺陷,那就是整個(gè)系統(tǒng)必須要停止一段時(shí)間,這對(duì)于數(shù)據(jù)吞吐量大的情形是不可接受的。為了處理這個(gè)問題,我們對(duì)原來算法進(jìn)行改進(jìn),其步驟如下: 1,假設(shè)當(dāng)前正在運(yùn)行的交易為1,2,3,。。。。k 2,停止創(chuàng)建新的交易 3,將所有修改的緩存頁面數(shù)據(jù)寫入磁盤 4,將當(dāng)前正在進(jìn)行的交易號(hào)記錄下來,例如 5,運(yùn)行新交易創(chuàng)建 有了上面步驟后,恢復(fù)管理器在執(zhí)行恢復(fù)時(shí),依然要從底部往上讀取日志,那么它如何知道怎么停止繼續(xù)讀取日志呢,當(dāng)它讀取到nqchkpt這條記錄時(shí),它把記錄中的交易號(hào)用一個(gè)隊(duì)列存儲(chǔ)起來,然后繼續(xù)往上讀取日志,當(dāng)它讀取到這樣的日志時(shí),它查看x是否在隊(duì)列中,如果在,那么就將它從隊(duì)列中去除,這個(gè)步驟一直進(jìn)行到隊(duì)列為空,此時(shí)它就不用再繼續(xù)讀取日志了。 這個(gè)辦法能大大縮短系統(tǒng)停止交易創(chuàng)建的時(shí)間,我們看個(gè)具體例子: 代碼語言:javascript 復(fù)制 <start, 0> <setint, 0, junk, 33, 8, 542, 543> <start, 1> <start, 2> <commit, 1> <setstring, 2, junk, 44, 20, hello, ciao> <nqckpt, 0, 2> <setstring, 0, junk, 33, 12, joe, joseph> <commit, 0> <start, 3> <setint, 2, junk, 66, 8, 0, 116> <setint, 3, junk, 33, 8, 543, 120> 恢復(fù)管理器在執(zhí)行恢復(fù)任務(wù)時(shí),依然從底部往上讀取,當(dāng)它讀取最后一條日志時(shí)發(fā)現(xiàn)交易3沒有對(duì)應(yīng)的commit日志,于是系統(tǒng)知道它沒有完成,于是執(zhí)行回滾操作。讀取時(shí)同樣執(zhí)行回滾操作。當(dāng)讀取到時(shí),將0加入交易完成列表,注意系統(tǒng)并不能確定交易3的對(duì)應(yīng)的數(shù)據(jù)是否都已經(jīng)寫入磁盤,因此需要找到交易0的起始處,讓后把所有寫入緩存的日志重新寫入磁盤。 因此系統(tǒng)繼續(xù)往上讀取,此時(shí)系統(tǒng)知道交易0已經(jīng)執(zhí)行commit,所以忽略這條日志。繼續(xù)往上讀,讀取到時(shí),執(zhí)行回滾操作,然后繼續(xù)往上讀取,一直讀到時(shí)停止繼續(xù)往上讀,此時(shí)它開始從這里往下讀,把所有有關(guān)交易0的操作對(duì)應(yīng)的數(shù)據(jù)再次執(zhí)行,然后寫入磁盤,往下讀取一直遇到時(shí)停止。 理論已經(jīng)夠多了,我們需要進(jìn)入代碼設(shè)計(jì)。首先在工程目錄下創(chuàng)建一個(gè)子文件夾叫tx,它里面包含了所有與交易相關(guān)的模塊,例如恢復(fù)管理器和并發(fā)管理器,后者我們在下一節(jié)討論。首先我們先定義交易對(duì)象的接口,等完成并發(fā)管理器完成后再討論它的實(shí)現(xiàn),增加一個(gè)文件叫interface.go,添加代碼如下: 代碼語言:javascript 復(fù)制 package tx import( fm "file_manager" lg "log_manager" ) type transationinterface interface { commit() rollback() recover() pin(blk *fm.blockid) unpin(blk *fm.blockid) getint(blk *fm.blockid, offset uint64) uint64 getstring(blk *fm.blockid, offset uint64) string setint(blk *fm.blockid, offset uint64, val uint64, oktolog bool) setstring(blk *fm.blockid, offset uint64, val string, oktolog bool) availablebuffers() uint64 size(filename string) uint64 append(filename string) *fm.blockid blocksize() uint64 } 從上面代碼看到,“交易”接口跟原先實(shí)現(xiàn)的buffer接口很像,它其實(shí)是對(duì)buffer接口的封裝,在調(diào)用后者前,先使用恢復(fù)管理器和并發(fā)管理器做一些前提工作,交易對(duì)象的實(shí)現(xiàn)在后面再實(shí)現(xiàn)。 首先我們先看恢復(fù)日志的實(shí)現(xiàn),從前面例子看,總共有六種用于恢復(fù)的日志,分別為start, commit, rollback, setint, setstring, checkpoint,所以我們先設(shè)定日志記錄的接口,然后針對(duì)每種記錄類型再實(shí)現(xiàn)對(duì)應(yīng)實(shí)例,繼續(xù)在interface.go中添加內(nèi)容如下: 代碼語言:javascript 復(fù)制 type record_type uint64 const ( checkpoint record_type = iota start commit rollback setint setstring ) const ( uint64_length = 8 ) type logrecordinterface interface { op() record_type //返回記錄的類別 txnumber() uint32 //對(duì)應(yīng)交易的號(hào)碼 undo(tx transationinterface) //回滾操作 tostring() string //獲得記錄的字符串內(nèi)容 } 接下來我們分別創(chuàng)建繼承l(wèi)ogrecordinterface接口的記錄實(shí)例,首先是start 記錄,增加文件start_record.go,添加內(nèi)容如下: 代碼語言:javascript 復(fù)制 package tx import ( fm "file_manager" "fmt" lg "log_manager" ) type startrecord struct { tx_num uint64 log_manager *lg.logmanager } func newstartrecord(p *fm.page, log_manager *lg.logmanager) *startrecord { //p的頭8字節(jié)對(duì)應(yīng)日志的類型,從偏移8開始對(duì)應(yīng)交易號(hào) tx_num := p.getint(uint64_length) return &startrecord{ tx_num: tx_num, log_manager: log_manager, } } func (s *startrecord) op() record_type { return start } func (s *startrecord) txnumber() uint64 { return s.tx_num } func (s *startrecord) undo() { //該記錄沒有回滾操作的必要 } func (s *startrecord) tostring() string { str := fmt.sprintf("<start %d>", s.tx_num) return str } func (s *startrecord) writetolog() (uint64, error) { //日志寫的不是字符串而是二進(jìn)制數(shù)值 record := make([]byte, 2*uint64_length) p := fm.newpagebybytes(record) p.setint(uint64(0), uint64(start)) p.setint(uint64_length, s.tx_num) return s.log_manager.append(record) } 它的邏輯很簡單,只需要關(guān)注tostring()和writetolog兩個(gè)函數(shù),前者返回其字符串格式,后者將start常量和交易號(hào)以二進(jìn)制的形式寫入緩存頁面,下面我們運(yùn)行上面的代碼看看,增加record_test.go,添加代碼如下: 代碼語言:javascript 復(fù)制 package tx import ( "fmt" "github.com/stretchr/testify/require" "testing" fm "file_manager" lm "log_manager" "encoding/binary" ) func teststartrecord(t *testing.t) { file_manager, _ := fm.newfilemanager("recordtest", 400) log_manager, _ := lm.newlogmanager(file_manager, "record_file") tx_num := uint64(13) //交易號(hào) p := fm.newpagebysize(32) p.setint(0, uint64(start)) p.setint(8, uint64(tx_num)) start_record := newstartrecord(p, log_manager) expected_str := fmt.sprintf("<start %d>", tx_num) require.equal(t, expected_str, start_record.tostring()) _, err := start_record.writetolog() require.nil(t, err) iter := log_manager.iterator() //檢查寫入的日志是否符號(hào)預(yù)期 rec := iter.next() rec_op := binary.littleendian.uint64(rec[0:8]) rec_tx_num := binary.littleendian.uint64(rec[8:len(rec)]) require.equal(t, rec_op, start) require.equal(t, rec_tx_num, tx_num) } 在測試中,我們初始化了startrecord實(shí)例,然后調(diào)用其tostring和writetolog兩個(gè)接口,然后檢驗(yàn)其返回或者是寫入緩存的數(shù)據(jù)是否正確,上面測試用例可以通過,因此我們當(dāng)前實(shí)現(xiàn)的startrecord邏輯能保證基本正確性。 接下來我們繼續(xù)實(shí)現(xiàn)其他幾種恢復(fù)日志,首先是setstring格式的日志,創(chuàng)建set_string_record.go,實(shí)現(xiàn)代碼如下: 代碼語言:javascript 復(fù)制 package tx import ( fm "file_manager" "fmt" lg "log_manager" ) /* 在理論上一條setstring記錄有7個(gè)字段,例如<setstring, 0, junk, 33, 12, joe, joseph>, 在實(shí)現(xiàn)上我們只用6個(gè)字段,上面的記錄實(shí)際上對(duì)應(yīng)了兩次字符串的寫入,第一次寫入字符串"joseph", 第二次寫入joe,因此在實(shí)現(xiàn)上它對(duì)應(yīng)了兩條包含六個(gè)字段的記錄: <setstring, 0, junk, 33, 12, joseph> .... <setstring, 0, junk, 33, 12, joe> 回憶一下前面我們實(shí)現(xiàn)日志,日志是從下往上寫,也就是<setstring, 0, junk, 33, 12, joe>會(huì)寫在前面, <setstring, 0, junk, 33, 12, joseph>會(huì)寫在后面, 在回滾的時(shí)候,我們從上往下讀取,因此我們會(huì)先讀到j(luò)oe,然后讀到j(luò)oseph,于是執(zhí)行回滾時(shí)我們只要把 讀到的字符串寫入到給定位置就可以,例如我們先讀到j(luò)oe,然后寫入junk文件區(qū)塊為33偏移為12的地方, 然后又讀取joseph,再次將它寫入到j(luò)unk文件區(qū)塊為33偏移為12的地方,于是就實(shí)現(xiàn)了回滾效果, 所以實(shí)現(xiàn)上setstring記錄不用寫入7個(gè)字段,只有6個(gè)就可以 type setstringrecord struct { tx_num uint64 offset uint64 val string blk *fm.blockid } func newsetstringrecord(p fm.page) setstringrecord { tpos := uint64(uint64_length) tx_num := p.getint(tpos) fpos := tpos + uint64_length filename := p.getstring(fpos) bpos := fpos + p.maxlengthforstring(filename) blknum := p.getint(bpos) blk := fm.newblockid(filename, blknum) opos := bpos + uint64_length offset := p.getint(opos) vpos := opos + uint64_length val := p.getstring(vpos) //將日志中的字符串再次寫入給定位置 代碼語言:javascript 復(fù)制 return &setstringrecord{ tx_num: tx_num, offset: offset, val: val, blk: blk, } } func (s *setstringrecord) op() record_type { return setstring } func (s *setstringrecord) txnumber() uint64 { return s.tx_num } func (s *setstringrecord) tostring() string { str := fmt.sprintf(““, s.tx_num, s.blk.number(), s.offset, s.val) 代碼語言:javascript 復(fù)制 return str } func (s *setstringrecord) undo(tx transationinterface) { tx.pin(s.blk) tx.setstring(s.blk, s.offset, s.val, false) //將原來的字符串寫回去 tx.unpin(s.blk) } func writesetstringlog(log_manager lg.logmanager, tx_num uint64, blk fm.blockid, offset uint64, val string) (uint64, error) { / 構(gòu)造字符串內(nèi)容的日志,setstringreord在構(gòu)造中默認(rèn)給定緩存頁面已經(jīng)有了字符串信息, 但是在初始狀態(tài),緩存頁面可能還沒有相應(yīng)日志信息,這個(gè)接口的作用就是為給定緩存寫入 字符串日志 / tpos := uint64(uint64_length) fpos := uint64(tpos + uint64_length) p := fm.newpagebysize(1) bpos := uint64(fpos + p.maxlengthforstring(blk.filename())) opos := uint64(bpos + uint64_length) vpos := uint64(opos + uint64_length) rec_len := uint64(vpos + p.maxlengthforstring(val)) rec := make([]byte, rec_len) 代碼語言:javascript 復(fù)制 p = fm.newpagebybytes(rec) p.setint(0, uint64(setstring)) p.setint(tpos, tx_num) p.setstring(fpos, blk.filename()) p.setint(bpos, blk.number()) p.setint(opos, offset) p.setstring(vpos, val) return log_manager.append(rec) } 代碼語言:javascript 復(fù)制 需要注意的是上面代碼實(shí)現(xiàn)的setstring記錄跟前面理論有所不同,傳遞給setstringrecord的是一個(gè)緩存頁面,它其實(shí)對(duì)應(yīng)了setstring的日志記錄,writesetstringlog方法用于在給定日志中寫入setstring記錄。同時(shí)需要注意的是,它的undo方法需要通過實(shí)現(xiàn)了transationinterface的對(duì)象來完成,由于我們現(xiàn)在還沒有實(shí)現(xiàn)交易對(duì)象,因此我們需要實(shí)現(xiàn)一個(gè)偽對(duì)象來測試上面代碼,創(chuàng)建tx_sub.go,添加代碼如下: package tx import ( fm “file_manager” ) type txstub struct { p *fm.page } func newtxstub(p fm.page) txstub { return &txstub{ p: p, } } func (t *txstub) commit() { } func (t *txstub) rollback() { } func (t *txstub) recover() { } func (t txstub) pin(_ fm.blockid) { } func (t txstub) unpin(_ fm.blockid) { } func (t txstub) getint(_ fm.blockid, offset uint64) uint64 { 代碼語言:javascript 復(fù)制 return t.p.getint(offset) } func (t txstub) getstring(_ fm.blockid, offset uint64) string { val := t.p.getstring(offset) return val } func (t txstub) setint(_ fm.blockid, offset uint64, val uint64, _ bool) { t.p.setint(offset, val) } func (t txstub) setstring(_ fm.blockid, offset uint64, val string, _ bool) { t.p.setstring(offset, val) } func (t *txstub) availablebuffers() uint64 { return 0 } func (t *txstub) size(_ string) uint64 { return 0 } func (t txstub) append(_ string) fm.blockid { return nil } func (t *txstub) blocksize() uint64 { return 0 } 代碼語言:javascript 復(fù)制 下面我們寫測試用例,以便檢測代碼的邏輯,在record_test.go中添加代碼如下: func testsetstringrecord(t *testing.t) { filemanager, := fm.newfilemanager(“recordtest”, 400) logmanager, := lm.newlogmanager(file_manager, “setstring”) 代碼語言:javascript 復(fù)制 str := "original string" blk := uint64(1) dummy_blk := fm.newblockid("dummy_id", blk) tx_num := uint64(1) offset := uint64(13) //寫入用于恢復(fù)的日志 writesetstringlog(log_manager, tx_num, dummy_blk, offset, str) pp := fm.newpagebysize(400) pp.setstring(offset, str) iter := log_manager.iterator() rec := iter.next() log_p := fm.newpagebybytes(rec) setstrrec := newsetstringrecord(log_p) expectd_str := fmt.sprintf("<setstring %d %d %d %s>", tx_num, blk, offset, str) require.equal(t, expectd_str, setstrrec.tostring()) pp.setstring(offset, "modify string 1") pp.setstring(offset, "modify string 2") txstub := newtxstub(pp) setstrrec.undo(txstub) recover_str := pp.getstring(offset) require.equal(t, recover_str, str) } 代碼語言:javascript 復(fù)制 我們繼續(xù)實(shí)現(xiàn)setint記錄,它的實(shí)現(xiàn)就是把setstring記錄的實(shí)現(xiàn)代碼拷貝一份然后簡單修改一下,創(chuàng)建set_int_record.go,然后把set_string_record.go的代碼拷貝進(jìn)去然后做一些修改如下: package tx import ( fm “file_manager” “fmt” lg “l(fā)og_manager” ) type setintrecord struct { tx_num uint64 offset uint64 val uint64 blk *fm.blockid } func newsetintrecord(p fm.page) setintrecord { tpos := uint64(uint64_length) tx_num := p.getint(tpos) fpos := tpos + uint64_length filename := p.getstring(fpos) bpos := fpos + p.maxlengthforstring(filename) blknum := p.getint(bpos) blk := fm.newblockid(filename, blknum) opos := bpos + uint64_length offset := p.getint(opos) vpos := opos + uint64_length val := p.getint(vpos) //將日志中的字符串再次寫入給定位置 代碼語言:javascript 復(fù)制 return &setintrecord{ tx_num: tx_num, offset: offset, val: val, blk: blk, } } func (s *setintrecord) op() record_type { return setstring } func (s *setintrecord) txnumber() uint64 { return s.tx_num } func (s *setintrecord) tostring() string { str := fmt.sprintf(““, s.tx_num, s.blk.number(), s.offset, s.val) 代碼語言:javascript 復(fù)制 return str } func (s *setintrecord) undo(tx transationinterface) { tx.pin(s.blk) tx.setint(s.blk, s.offset, s.val, false) //將原來的字符串寫回去 tx.unpin(s.blk) } func writesetintlog(log_manager lg.logmanager, tx_num uint64, blk fm.blockid, offset uint64, val uint64) (uint64, error) { 代碼語言:javascript 復(fù)制 tpos := uint64(uint64_length) fpos := uint64(tpos + uint64_length) p := fm.newpagebysize(1) bpos := uint64(fpos + p.maxlengthforstring(blk.filename())) opos := uint64(bpos + uint64_length) vpos := uint64(opos + uint64_length) rec_len := uint64(vpos + uint64_length) rec := make([]byte, rec_len) p = fm.newpagebybytes(rec) p.setint(0, uint64(setstring)) p.setint(tpos, tx_num) p.setstring(fpos, blk.filename()) p.setint(bpos, blk.number()) p.setint(opos, offset) p.setint(vpos, val) return log_manager.append(rec) } 代碼語言:javascript 復(fù)制 然后在record_test.go里面添加新的測試用例: func testsetintrecord(t *testing.t) { filemanager, := fm.newfilemanager(“recordtest”, 400) logmanager, := lm.newlogmanager(file_manager, “setstring”) 代碼語言:javascript 復(fù)制 val := uint64(11) blk := uint64(1) dummy_blk := fm.newblockid("dummy_id", blk) tx_num := uint64(1) offset := uint64(13) //寫入用于恢復(fù)的日志 writesetintlog(log_manager, tx_num, dummy_blk, offset, val) pp := fm.newpagebysize(400) pp.setint(offset, val) iter := log_manager.iterator() rec := iter.next() log_p := fm.newpagebybytes(rec) setintrec := newsetintrecord(log_p) expectd_str := fmt.sprintf("<setint %d %d %d %d>", tx_num, blk, offset, val) require.equal(t, expectd_str, setintrec.tostring()) pp.setint(offset, 22) pp.setint(offset,33) txstub := newtxstub(pp) setintrec.undo(txstub) recover_val := pp.getint(offset) require.equal(t, recover_val, val) } 代碼語言:javascript 復(fù)制 最后還剩下rollback 和 commit兩個(gè)記錄,它們內(nèi)容簡單,我們一并放出來,創(chuàng)建rollback_record.go,添加代碼如下: package tx import ( fm “file_manager” “fmt” lg “l(fā)og_manager” ) type rollbackrecord struct { tx_num uint64 } func newrollbackrecord(p fm.page) rollbackrecord { return &rollbackrecord { tx_num : p.getint(uint64_length), } } func (r *rollbackrecord) op() record_type { return rollback } func (r *rollbackrecord) txnumber() uint64 { return r.tx_num } func(r *rollbackrecord) undo() { //它沒有回滾操作 } func (r *rollbackrecord) tostring() string { return fmt.sprintf(““, r.tx_num) } func writerollbacklog(lgmr lg.logmanager, tx_num uint64) (uint64, error){ rec := make([]byte, 2 uint64_length) p := fm.newpagebybytes(rec) p.setint(0, uint64(rollback)) p.setint(uint64_length, tx_num) 代碼語言:javascript 復(fù)制 return lgmr.append(rec) } 代碼語言:javascript 復(fù)制 同理在record_test.go中添加測試用例如下: func testrollbackrecord(t *testing.t) { filemanager, := fm.newfilemanager(“recordtest”, 400) logmanager, := lm.newlogmanager(file_manager, “rollback”) tx_num := uint64(13) writerollbacklog(log_manager, tx_num) iter := log_manager.iterator() rec := iter.next() pp := fm.newpagebybytes(rec) 代碼語言:javascript 復(fù)制 roll_back_rec := newrollbackrecord(pp) expected_str := fmt.sprintf("<rollback %d>", tx_num) require.equal(t, expected_str, roll_back_rec.tostring()) } 代碼語言:javascript 復(fù)制 接下來我們添加commit記錄,它的實(shí)現(xiàn)跟rollback差不多,添加commit_record.go然后添加代碼如下: package tx import ( fm “file_manager” “fmt” lg “l(fā)og_manager” ) type commitrecord struct { tx_num uint64 } func newcommitkrecordrecord(p fm.page) commitrecord { return &commitrecord { tx_num : p.getint(uint64_length), } } func (r *commitrecord) op() record_type { return commit } func (r *commitrecord) txnumber() uint64 { return r.tx_num } func(r *commitrecord) undo() { //它沒有回滾操作 } func (r *commitrecord) tostring() string { return fmt.sprintf(““, r.tx_num) } func writecommitkrecordlog(lgmr lg.logmanager, tx_num uint64) (uint64, error){ rec := make([]byte, 2 uint64_length) p := fm.newpagebybytes(rec) p.setint(0, uint64(commit)) p.setint(uint64_length, tx_num) 代碼語言:javascript 復(fù)制 return lgmr.append(rec) } 代碼語言:javascript 復(fù)制 然后在record_test.go添加代碼如下: func testcommitrecord(t *testing.t) { filemanager, := fm.newfilemanager(“recordtest”, 400) logmanager, := lm.newlogmanager(file_manager, “commit”) tx_num := uint64(13) writecommitkrecordlog(log_manager, tx_num) iter := log_manager.iterator() rec := iter.next() pp := fm.newpagebybytes(rec) 代碼語言:javascript 復(fù)制 roll_back_rec := newcommitkrecordrecord(pp) expected_str := fmt.sprintf("<commit %d>", tx_num) require.equal(t, expected_str, roll_back_rec.tostring()) } 代碼語言:javascript 復(fù)制 最后我們完成最簡單的checkpoint記錄,添加checkpoint_record.go,添加代碼如下: package tx import ( fm “file_manager” lg “l(fā)og_manager” “math” ) type checkpointrecord struct{ } func newcheckpointrecord() *checkpointrecord { return &checkpointrecord{ 代碼語言:javascript 復(fù)制 } } func (c *checkpointrecord) op() record_type { return checkpoint } func (c *checkpointrecord) txnumber() uint64 { return math.maxuint64 //它沒有對(duì)應(yīng)的交易號(hào) } func (c *checkpointrecord) undo() { } func (c *checkpointrecord) tostring() string{ return ““ } func writecheckpointtolog(lgmr *lg.logmanager) (uint64, error) { rec := make([]byte, uint64_length) p := fm.newpagebybytes(rec) p.setint(0, uint64(checkpoint)) return lgmr.append(rec) } 代碼語言:javascript 復(fù)制 最后在record_test.go中添加相應(yīng)測試用例: func testcheckpointrecord(t *testing.t) { filemanager, := fm.newfilemanager(“recordtest”, 400) logmanager, := lm.newlogmanager(file_manager, “checkpoint”) writecheckpointtolog(log_manager) iter := log_manager.iterator() rec := iter.next() pp := fm.newpagebybytes(rec) val := pp.getint(0) 代碼語言:javascript 復(fù)制 require.equal(t, val, uint64(checkpoint)) check_point_rec := newcheckpointrecord() expected_str := "<checkpoint>" require.equal(t, expected_str, check_point_rec.tostring()) } ``` 經(jīng)過調(diào)試,所有測試用例都能通過。要想更好的了解代碼邏輯,請(qǐng)?jiān)赽站搜索coding迪斯尼,我會(huì)在視頻中進(jìn)行調(diào)試和演示。代碼下載:https://github.com/wycl16514/database-system-recovery-record.git,[更多干貨](http://m.study.163.com/provider/7600199/index.htm?share=2&shareid=7600199):http://m.study.163.com/provider/7600199/index.htm?share=2&shareid=7600199

山東金麒麟專場 — 純前端表格技術(shù)應(yīng)用研討會(huì):

2018 年 7 月 16 日,“賦能開發(fā)者,走進(jìn)你身邊——純前端表格技術(shù)應(yīng)用研討會(huì)” 走進(jìn)山東金麒麟股份有限公司(以下簡稱金麒麟)。 西安葡萄城業(yè)務(wù)總監(jiān)郭瑋、資深前端技術(shù)專家姚堯受邀與山東金麒麟股份有限公司展開深入探討,圍繞葡萄城企業(yè)文化、數(shù)據(jù)管理系統(tǒng)實(shí)踐、前端技術(shù)發(fā)展趨勢以及?純前端表格控件 spreadjs?在各領(lǐng)域應(yīng)用場景等四大核心議題 作為全球領(lǐng)先的集開發(fā)工具、商業(yè)智能解決方案、管理系統(tǒng)設(shè)計(jì)工具于一身的軟件和服務(wù)提供商,通過本次研討會(huì),葡萄城實(shí)實(shí)在在地感受到了所提供的產(chǎn)品和服務(wù)為各領(lǐng)域行業(yè)帶來的價(jià)值,為此,葡萄城的技術(shù)專家們也感到無比自豪和驕傲 葡萄城公司成立于 1980 年,是全球領(lǐng)先的集開發(fā)工具、商業(yè)智能解決方案、管理系統(tǒng)設(shè)計(jì)工具于一身的軟件和服務(wù)提供商。 葡萄城的控件和軟件產(chǎn)品在國內(nèi)外屢獲殊榮,在全球被數(shù)十萬家企業(yè)、學(xué)校和政府機(jī)構(gòu)廣泛應(yīng)用。

「鎂客·請(qǐng)講」魔魚互動(dòng)韓宇:專注行業(yè)應(yīng)用,打造可看可用的ar vr產(chǎn)品:

“那是2009年,經(jīng)過評(píng)估后自己在技術(shù)和社會(huì)閱歷上的積累都非常薄弱,直接創(chuàng)業(yè)成功的概率幾乎為零,所以特意選擇了一個(gè)未來應(yīng)用廣泛又相對(duì)冷門的專業(yè)——地理信息系統(tǒng)繼續(xù)深造。”韓宇回憶說。 魔魚互動(dòng)創(chuàng)始人-韓宇“2015年,感覺積累的差不多了,而且趕上政府大力扶持創(chuàng)業(yè),整體創(chuàng)業(yè)環(huán)境非常好的時(shí)機(jī)。于是果斷投入了創(chuàng)業(yè)大軍?!蹦且荒?,經(jīng)過多年積累的韓宇,聯(lián)合兩位摯友正式啟動(dòng)了他們的創(chuàng)業(yè)之旅。 截止2015年底,魔魚互動(dòng)營業(yè)額不足10萬元,一名核心成員由于家庭原因被迫離開了公司,最慘淡時(shí)只剩下韓宇和另一名聯(lián)合創(chuàng)始人黃致堯。 幸好,2015年5月公司通過了新城科技園入孵項(xiàng)目評(píng)審,在政府的扶持下,公司一步步走上正軌。“那是一場及時(shí)雨,我們有幸通過了新城科技園入孵項(xiàng)目評(píng)審,有了固定辦公室,才逐步形成了一個(gè)穩(wěn)定的團(tuán)隊(duì)?!?他們已經(jīng)研發(fā)了三維機(jī)房實(shí)時(shí)監(jiān)控系統(tǒng)、基于三維城市的統(tǒng)計(jì)信息可視化平臺(tái)、web版三維城市在線漫游系統(tǒng)等,正在研發(fā)融合人文環(huán)境影響因素的虛擬樓盤展示系統(tǒng)。

用 python 慶祝拜登當(dāng)選的十種方式:

還記得上周三的時(shí)候川普在搖擺州上領(lǐng)先拜登好幾個(gè)點(diǎn),我都不敢打開炒股軟件,結(jié)果周四醒來一下就反轉(zhuǎn)了,一路逆襲到今天,基本上穩(wěn)了: ? musa_zadeh[4] import time for i in range(2021,2025): print("hello biden") time.sleep(365*24*60*60) # 拜登被稱為睡王

1分鐘鏈圈 | 曝光!區(qū)塊鏈游戲5天就能復(fù)制一款,玩家靠擊鼓傳花獲利!bch將于5月16日0點(diǎn)左右執(zhí)行硬分叉:

為瑞波幣產(chǎn)品和項(xiàng)目提供資金支持bch將于北京時(shí)間5月16日0點(diǎn)左右執(zhí)行硬分叉,區(qū)塊大小從8mb增加至32mb全球俄羅斯一銀行通過加密貨幣幫助委內(nèi)瑞拉石油幣發(fā)展歐盟批準(zhǔn)aml(反洗錢)在加密貨幣市場的匿名立法美國佛羅里達(dá)州塞米諾爾縣稅務(wù)辦公室接受 (news.bitcoin)5.圣路易聯(lián)儲(chǔ)主席james bullard:匯率問題是數(shù)字貨幣獲廣泛承認(rèn)的最大障礙美聯(lián)儲(chǔ)圣路易聯(lián)儲(chǔ)主席james bullard在coindesk 2018年度共識(shí)大會(huì)期間接受 根據(jù)美聯(lián)社報(bào)道,早期的石油幣投資者將向委內(nèi)瑞拉政府注冊并下載數(shù)字貨幣的錢包,通過向evrofinance mosnarbank的政府所有賬戶提供1000歐元(約合1190美元)的最低金額來購買該錢包。 (cointelegraph)11.美國佛羅里達(dá)州塞米諾爾縣稅務(wù)辦公室接受btc和bch塞米諾爾縣稅務(wù)員joel m. 區(qū)塊鏈允許塞米諾爾縣的稅務(wù)師在提高支付準(zhǔn)確性、透明度和效率的同時(shí),消除大部分的高額費(fèi)用。

轉(zhuǎn)載請(qǐng)注明出處,本站網(wǎng)址:http://www.nds518.com/news_2274.html
相關(guān)推薦
熱門TAG

常德做網(wǎng)站 廣東哪家網(wǎng)站制作公司好 福田區(qū)做網(wǎng)站 伽師縣網(wǎng)站設(shè)計(jì) 峨邊彝族自治縣網(wǎng)站建設(shè) 云南SEO網(wǎng)站優(yōu)化 便宜的網(wǎng)站建設(shè)公司 山海關(guān)企業(yè)網(wǎng)站開發(fā) 西安網(wǎng)站建設(shè)公司 市轄區(qū)SEO網(wǎng)站優(yōu)化 富寧做網(wǎng)站 渝北區(qū)公司網(wǎng)站建設(shè) seo服務(wù)網(wǎng)站 新蕪區(qū)自助建站 鞍山網(wǎng)站開發(fā) 網(wǎng)站制作策劃 南芬政府公文系統(tǒng) 網(wǎng)站怎么優(yōu)化seo 靈武市網(wǎng)頁設(shè)計(jì) 磴口做網(wǎng)站 海林市政務(wù)OA 萬盛區(qū)SEO網(wǎng)站優(yōu)化 東莞網(wǎng)站制作的公司 建一個(gè)網(wǎng)站的步驟 網(wǎng)站優(yōu)化排名公司 涉 縣自助建站 潁上縣網(wǎng)站設(shè)計(jì) 武進(jìn)區(qū)網(wǎng)頁設(shè)計(jì) 蘇尼特右旗公司網(wǎng)站建設(shè) 吳橋SEO網(wǎng)站優(yōu)化 好建站 濟(jì)陽縣網(wǎng)站設(shè)計(jì) 新田縣SEO網(wǎng)站優(yōu)化 平山網(wǎng)頁設(shè)計(jì) 市轄區(qū)自助建站 沙依巴克區(qū)網(wǎng)站設(shè)計(jì) 天門市做網(wǎng)站 富拉爾基區(qū)政務(wù)OA 市轄區(qū)政府辦公oa系統(tǒng) 漢中SEO網(wǎng)站優(yōu)化 北京旅游網(wǎng)站建設(shè) 內(nèi)鄉(xiāng)縣做網(wǎng)站 古冶網(wǎng)站建設(shè) 蒲城縣SEO網(wǎng)站優(yōu)化 seo公司 北京 本溪網(wǎng)站制作 方城縣政務(wù)oa系統(tǒng) 市轄區(qū)企業(yè)網(wǎng)站開發(fā) 普蘭店網(wǎng)站建設(shè) 新興縣網(wǎng)站建設(shè) 沈陽企業(yè)自助建站系統(tǒng) 北安市政府公文系統(tǒng) 遵義網(wǎng)頁設(shè)計(jì) 燈塔政府oa系統(tǒng) 吉木乃縣做網(wǎng)站 臨汾網(wǎng)站建設(shè) 應(yīng)城市網(wǎng)站設(shè)計(jì) 洞口縣SEO網(wǎng)站優(yōu)化 渭源縣做網(wǎng)站 浮梁縣網(wǎng)頁設(shè)計(jì) 江永縣網(wǎng)站設(shè)計(jì) 遂川縣自助建站 羅甸縣政府辦公oa系統(tǒng) 霍山縣人民政府電話 市中區(qū)網(wǎng)站設(shè)計(jì) 武定網(wǎng)頁設(shè)計(jì) 岳陽縣SEO網(wǎng)站優(yōu)化 吉林公司網(wǎng)站建設(shè) 沂源縣網(wǎng)頁設(shè)計(jì) 容 縣自助建站 荔波縣網(wǎng)站建設(shè) 好的建站網(wǎng)站 梧州網(wǎng)站建設(shè) 曲松縣自助建站 寶雞政務(wù)oa系統(tǒng) HR大數(shù)據(jù)分析與經(jīng)營模擬決策平臺(tái)題目