OpenAI

2 nëntor 2026

Inxhinieria

Zgjerimi i Git në OpenAI

Ndërtimi i kontrollit të kodit burimor për shkallën e punës së agjentëve, duke investuar në ekosistemin Git.

Nga Aaron Friel, Taylor Blau dhe Ted Nyman, anëtarë të stafit teknik

Duke ngarkuar…

Gjatë vitit të fundit, madhësia e monodepos sonë dhe kërkesat ndaj saj janë rritur me një ritëm marramendës. Ishte e qartë se duhej ta rinovonim sistemin tonë të kontrollit të kodit burimor për të përballuar nivelin e punës së njëkohshme që mundëson Codex.

Ndërtuam Pando, një sistem të ri prapavije për depot Git, pa ndërprerë asnjë punë inxhinierike dhe pa ndryshuar mënyrën se si ekipi ynë përdor Git. Pando tani mbështet të gjithë zhvillimin në monodepon e OpenAI. Pando është projektuar për dy synime ambicioze: së pari, shkrime të zgjerueshme horizontalisht, të optimizuara për operacione push të njëkohshme në shumë degë. Së dyti, maksimizimin e kapacitetit të përpunimit të leximeve, që klientët të shkarkojnë të dhëna aq shpejt sa të shfrytëzojnë plotësisht gjerësinë e disponueshme të brezit të rrjetit.

I arritëm këto synime duke ruajtur përputhshmërinë me protokollin dhe klientin Git, çka u mundësoi inxhinierëve dhe agjentëve tanë ta përfshinin pa vështirësi Pando në rrjedhat ekzistuese të punës. Në përdorim real, Pando e uli vonesën mediane të operacioneve push pothuajse 5 herë. Tani ai shpërndan gati një petabajt të dhënash Git në ditë.

Këtu do të shpjegojmë arsyet që na shtynë të ndërtojmë një sistem të ri kontrolli të kodit burimor dhe pse zgjodhëm të ruanim përputhshmërinë me Git. Do ta krahasojmë sistemin tonë me qasjet e zakonshme për zgjerimin e Git, duke shpjeguar pse Pando është veçanërisht i aftë t’u përgjigjet nevojave të OpenAI për zgjerim. Do të flasim edhe për hapat e ardhshëm dhe si do të vazhdojmë të kontribuojmë në Git për të mbështetur punën në shkallën që sjellin agjentët.

Pse na duhej një sistem i ri kontrolli i kodit burimor

Codex ka ndryshuar përmasat dhe ritmin e zhvillimit në OpenAI, duke u mundësuar inxhinierëve të bëjnë shumë më tepër punë paralelisht. Kjo do të thotë më shumë degë dhe operacione push, më shumë bashkime dhe më shumë operacione fetch e klonime nga mjediset e zhvillimit, proceset kërkimore dhe CI.

Këto kërkesa shumëfishojnë njëra-tjetrën. Tani një inxhinier ka disa ndryshime njëherësh gati për CI dhe çdo push mund të nisë disa procese që marrin të njëjtin commit.

Duke nisur nga fundi i vitit të kaluar, sistemet që mbështesnin monodepon tonë e kishin të vështirë të mbanin ritmin. Përjetuam operacione fetch dhe push të ngadalta, si dhe bashkime të dështuara, me besueshmërinë që herë pas here binte nën 90%. Kishim arritur një kufi të vetë Git, apo të mënyrës se si e shërbenim monodepon tonë? Git lindi nga një komunitet që shkëmbente përmes emailit arnime për kernelin. Për më shumë se dy dekada, zhvilluesit i kanë përshtatur mjetet e tyre rreth Git, teksa mënyra e ndërtimit të softuerit ka ndryshuar. Kur nisëm të hasnim pengesa në monodepon tonë, për ne ishte e rëndësishme të vazhdonim të mbështeteshim në atë punë.

Pamë një mënyrë për ta ruajtur atë rrjedhë pune të njohur, duke rindërtuar sistemin e prapavijës që të trajtonte paralelisht operacionet push në degë të ndryshme dhe t’u shërbente të njëjtin historik shumë lexuesve njëkohësisht. Mbështetja te Git si themel i rrjedhës sonë të kontrollit të kodit burimor nënkuptonte se përmirësimet e klientit mund të ishin të dobishme edhe jashtë OpenAI. Donim t’ia kontribuonim projektit kryesor këto përmirësime nga kopja jonë e Git⁠(hapet në një dritare të re), duke i ndarë me komunitetin më të gjerë.

Inxhinieri për Git në shkallë të gjerë

Zgjerimi i një sistemi kontrolli të kodit burimor ka dy përmasa thelbësore: shumë shkrues që kryejnë push në degë të ndryshme dhe shumë lexues që marrin të njëjtin historik. Pando është optimizuar për të dyja.

Së pari, Pando bashkërendon në mënyrë të pavarur përditësimet e çdo dege. Përditësimet e degëve pa lidhje mes tyre mund të ecin paralelisht dhe një lexues që merr një degë merr historikun e nevojshëm për atë version. Kompromisi është se një lexues që shqyrton disa degë mund t’i shohë ato në çaste të ndryshme kohore.

Së dyti, Pando ripërdor skedarët e paketave (formati i Git për kompresimin e disa objekteve së bashku) në operacione fetch, në vend që të krijojë një skedar të veçantë për çdo klient. Një klient mund të shkarkojë disa objekte që i ka tashmë, por serveri mund t’u shërbejë të njëjtët bajte shumë klientëve me pak përpunim.

Këto zgjedhje na lejojnë të zgjerojmë shkrimet nëpër degë dhe të shërbejmë leximet nga memoria e përkohshme. Për të parë si funksionojnë së bashku, le të fillojmë me mënyrën se si Git e ruan dhe e transferon historikun.

Hyrje në ruajtjen e objekteve në Git

Git duhet të jetë në gjendje të mbajë të sinkronizuara dy pjesë të një depoje: objektet dhe referencat.

Një depo Git regjistron gjendjet e skedarëve dhe historikun që i lidh ato si një graf objektesh. Një objekt mund të jetë blob, pemë, commit ose etiketë. Blob-et mbajnë përmbajtjen e një skedari individual, ndërsa pemët lidhin emra me blob-e ose pemë të tjera për të formuar një strukturë dosjesh. Commit-et tregojnë drejt një peme rrënjë dhe zero ose më shumë commit-eve prind, duke formuar historikun e depos suaj.

Objektet identifikohen nga një hash i llojit dhe përmbajtjes së tyre. Objektet janë gjithashtu të pandryshueshme: regjistrimi i një skedari të ndryshuar krijon një blob të ri, ndërsa skedarët dhe dosjet e pandryshuara mund të ripërdorin objektet ekzistuese.

Degët dhe etiketat janë referenca, ose “refs”, që tregojnë drejt commit-eve. Kryerja e një commit-i në një degë krijon një commit të ri dhe përditëson referencën e degës që të tregojë drejt tij.

Dega refs/heads/main tregon drejt commit-it C2, prindi i të cilit është C1. C1 tregon drejt pemës rrënjë T1, ku parser.py i referohet blob-it B1. C2 tregon drejt pemës rrënjë T2, ku parser.py i referohet blob-it B2. Në të dyja pemët rrënjë, docs/ i referohet së njëjtës pemë, T3. Zëri i saj README.md tregon drejt blob-it B3, ndërsa usage.md tregon drejt blob-it B4.

Objektet Git i referohen njëri-tjetrit sipas ID-së: commit-et u referohen pemëve, ndërsa pemët u referohen pemëve dhe blob-eve. Dega refs/heads/main tregon drejt commit-it C2, prindi i të cilit është C1. C1 tregon drejt pemës rrënjë T1, ku parser.py i referohet blob-it B1. C2 tregon drejt pemës rrënjë T2, ku parser.py i referohet blob-it B2. Në të dyja pemët rrënjë, docs/ i referohet së njëjtës pemë, T3. Zëri i saj README.md tregon drejt blob-it B3, ndërsa usage.md tregon drejt blob-it B4.

Git i ruan objektet në gjendje “të veçuar” ose “të paketuar”. Objektet e veçuara ruhen në skedarë individualë, të identifikuar nga ID-ja e objektit. Objektet e paketuara ruhen së bashku në një skedar pakete, duke lejuar që objektet e ngjashme të ruhen si diferenca kundrejt njëri-tjetrit.

Dy versione të parser.py shfaqen nën $GIT_DIR/objects . Si objekte të veçuara, blob-i A përmban parse(), ndërsa blob-i B përmban si parse(), ashtu edhe parse_file(). Skedari i paketës e ruan A të plotë dhe e paraqet B si udhëzime për të kopjuar të gjithë A dhe për të shtuar parse_file(). Skedari shoqërues *.idx i lokalizon të dy blob-et në skedarin e paketës sipas ID-së së objektit.

Git mund t’i ruajë blob-et si skedarë të veçantë ose t’i paketojë së bashku, duke e koduar njërin si diferencë kundrejt një tjetri.

Në Git, një objekt është i arritshëm nga një commit nëse Git mund ta gjejë duke ndjekur lidhjet nga ai commit përmes prindërve, pemëve dhe blob-eve të tij. Gjatë një fetch-i, klienti i tregon serverit cilat commit-e kërkon dhe cilat i ka tashmë. Serveri gjen objektet e arritshme nga commit-et e kërkuara, përjashton ato që e di se klienti i ka tashmë dhe dërgon pjesën tjetër si skedar pakete në të njëjtin format që Git përdor në disk. Një klonim i plotë nis pa asnjë objekt, ndaj i duhen të gjitha objektet e arritshme nga historiku që po klonohet.

Një push transferon objekte në drejtimin e kundërt, duke i kërkuar serverit të përditësojë një ose më shumë referenca. Klienti përdor grupin e referencave të njoftuara nga serveri për të shmangur dërgimin e objekteve që serveri i ka tashmë. Prandaj, paketa që dërgohet mund të varet nga objekte ekzistuese: marrja vetëm e paketës nuk mjafton për të rindërtuar historikun e ri.

Replikimi i një depoje Git do të thotë të mbahen të disponueshme si objektet, ashtu edhe referencat në shumë serverë. Para se një replikë të mund të shërbejë vlerën e re të një reference, duhet të jetë në gjendje të ofrojë objektet e arritshme nga ajo vlerë. Shërbimi duhet gjithashtu të bashkërendojë përditësimet konkurruese të referencave, pra operacionet push që përpiqen ta zhvendosin të njëjtën degë nga e njëjta majë e vjetër te commit-e të reja të ndryshme. Sistemet që imponojnë një rend të vetëm për të gjitha shkrimet në një depo mund t’i detyrojnë operacionet push në degë pa lidhje mes tyre të presin njëri-tjetrin.

Modelet ekzistuese të shërbimeve të shpërndara Git

Gjatë projektimit të Pando, vlerësuam qasjet tradicionale për zgjerimin e kontrollit të kodit burimor me Git: njëra bashkërendon përditësimet e referencave në replikat e depos përmes konfirmimit me tri faza (3PC, protokoll për bashkërendimin e një konfirmimi në shumë nyje); tjetra i rendit përditësimet përmes një regjistri të përbashkët paraprak shkrimi (WAL, regjistër ku ndryshimet shkruhen para se të zbatohen) në ruajtjen e blob-eve.

Konfirmimi me tri faza (3PC)

Në projektimin me konfirmim me tri faza që modeluam, shërbimi Git mban një kopje të plotë të depos në disa replika. Kur cilido server merr një push, skedari i paketës së ardhur kopjohet dhe u dërgohet të gjitha replikave paralelisht. Për ta publikuar push-in, shumica e replikave duhet ta pranojnë përditësimin e referencës. Serveri që e menaxhon këtë është bashkërenduesi dhe procesi kërkon disa raunde komunikimi midis tij dhe çdo replike tjetër.

Për të pranuar një përditësim reference, çdo replikë kyç kopjen e vet të referencës dhe kontrollon që ajo ende tregon drejt commit-it që pret klienti. Më pas, bashkërenduesi u dërgon një mesazh parakonfirmimi replikave që pranojnë. Pasi shumica konfirmon marrjen e mesazhit të parakonfirmimit, bashkërenduesi u thotë ta kryejnë përditësimin. Çdo replikë e përditësuar mund të njoftojë më pas majën e re të degës nga kopja e saj lokale e depos.

Mbajtja e replikave të plota mundëson shërbimin lokal të leximeve dhe garanton që klientët të marrin një pamje konsistente të të gjitha referencave, pavarësisht replikës që zgjedhin. Si rrjedhojë, referencat përditësohen një nga një dhe çdo push kërkon disa cikle komunikimi vajtje-ardhje për të bashkërenduar përditësimin e referencës midis replikave.

Pritja për kuorum bën që performanca e disqeve të replikave dhe vonesa e komunikimit të ndikojnë drejtpërdrejt në push. Me rritjen e vëllimit të shkrimeve, replikat duhet të mbajnë ritmin si me paketat hyrëse, ashtu edhe me trafikun e leximit.

Regjistri paraprak i shkrimit (WAL)

Në projektimin e bazuar në WAL që modeluam, shërbimi Git përdor një manifest të përbashkët në ruajtjen e blob-eve për të renditur përditësimet në të gjithë depon. Kur një server merr një push, ai ngarkon skedarin e paketës së ardhur në një depozitë blob-esh dhe përgatit përditësimin e referencës në kopjen e tij lokale të depos. Për ta publikuar push-in, ai shton një zë në një manifest të përbashkët të ruajtur në depozitën e blob-eve, i cili regjistron përditësimin e referencës dhe tregon drejt skedarit të paketës. Më pas serveri Git përditëson manifestin me një operacion krahasimi dhe zëvendësimi. Ky operacion ose e zëvendëson manifestin në mënyrë atomike, ose e refuzon ndryshimin. Nëse një shkrues tjetër e ka përditësuar ndërkohë, serveri lexon zërat e shtuar në këtë interval, kontrollon që përditësimi i tij i referencës është ende i vlefshëm dhe provon sërish duke përdorur skedarin e paketës që ka ngarkuar tashmë.

Shkruesit mund t’i ngarkojnë paralelisht skedarët e tyre të paketave, por edhe operacionet push në degë pa lidhje mes tyre kërkojnë përditësimin e të njëjtit manifest. Koha vajtje-ardhje për një krahasim dhe zëvendësim të suksesshëm kufizon sa shpesh depoja mund të publikojë një manifest të ri. Një depozitë blob-esh me vonesë të ulët e bën këtë hap të shpejtë. Grupimi lejon që një manifest të përditësojë disa referenca njëkohësisht, por me koston e vendosjes së përditësimeve në radhë dhe rritjes së vonesës.

Depozita e blob-eve mund të marrë skedarë paketash paralelisht, por përditësimet e manifestit të përbashkët ende konkurrojnë me njëri-tjetrin. Vetëm rritja e kapacitetit të depozitës së blob-eve nuk e zgjidh këtë ngushticë. Çdo replikë duhet ende t’i lexojë dhe indeksojë paketat nga depozita e blob-eve para se t’i shërbejë lokalisht. Nëse shkrimet hyrëse e tejkalojnë ritmin e kësaj pune, replikat mbeten prapa dhe klientët presin më gjatë për të marrë commit-et e sapodërguara me push.

Projektimi i arkitekturës së Pando

Kjo na sjell te Pando. Pando është një arkitekturë e re për shërbimin e depove Git, me synimin për të përballuar shumë klientë që kryejnë push njëkohësisht. Ja si funksionon:

Rishikimi i kufizimeve

Para se të zhvillonim Pando, kishim një parandjenjë se mund t’i përmbushnim kërkesat tona pa bërë kompromis me Git, por duhej të bënim kompromis me disa gjëra që shumica e sistemeve Git i marrin si kërkesa të mirëqena:

  • Konsistenca në të gjithë depon: Sigurimi i një pamjeje të qëndrueshme të të gjitha referencave në një çast të caktuar kërkon bashkërendim në të gjithë depon. Në një sistem që rendit së bashku të gjitha përditësimet e referencave, operacionet push në degë pa lidhje mes tyre konkurrojnë për një pikë të vetme bashkërendimi.

  • Skedarë paketash unikë për çdo klient: Nëse dy klientë me historikë lokalë të ndryshëm marrin të njëjtën degë, serverit mund t’i duhet të krijojë një paketë të ndryshme për secilin, që të mos u dërgojë objekte që i kanë tashmë. Krijimi i këtyre përgjigjeve konsumon burime CPU-je dhe I/O-je në disk, duke e vështirësuar shërbimin e një numri të madh lexuesish.

Në vend të kësaj, Pando ofron një model me konsistencë më pak të rreptë (konsistencë shkakësore) për të përballuar më shumë shkrime dhe ripërdor skedarët e paketave për të përballuar më shumë lexime.

Konsistenca shkakësore (CC)

Kur një klient kryen push në një degë, Pando e ruan skedarin e paketës së ardhur si një blob të pandryshueshëm në një depozitë blob-esh. Sa herë që dega zhvendoset, Pando regjistron në një depozitë metadatash një version reference që përmban majën e re të degës, paketën që e solli dhe çdo version të mëparshëm reference nga i cili varet paketa. Si depozita e blob-eve, ashtu edhe ajo e metadatave mund të zgjerohen horizontalisht.

Marrja e një commit-i ose reference nga Pando kërkon që klientit t’i dërgohet një grup versionesh reference (skedarësh paketash), duke rindërtuar gjendjen e klientit që krijoi versionin e referencës që po merret. Kjo siguron një formë më të dobët konsistence në të gjithë depon, ndërsa garanton serializueshmëri për përditësimet e referencave individuale. Klientët bien në konflikt vetëm kur kryejnë push njëkohësisht në të njëjtën referencë. Një klient që lexon disa degë nuk mund të supozojë se këto lexime përshkruajnë të njëjtin çast kohor në të gjithë depon.

Majtas, tri paketa të njëpasnjëshme të degës kryesore përmbajnë commit-et A, B dhe C; D dhe E; dhe F. Djathtas, dega kryesore dhe dega tematike ndahen te C. Dega kryesore përparon te G, ndërsa dega tematike përparon përmes D, E dhe F. Paketa më e fundit e degës tematike përmban D, E dhe F. Një kontur me vija të ndërprera tregon se D dhe E janë të pranishme edhe në paketën e mëparshme të degës tematike. Shigjeta blu shënon varësinë e paketës së re nga dega kryesore te G. Prindi i F në Git është E.

Një push në degën kryesore shton një paketë inkrementale, që përmban një ose më shumë commit-e. Çdo push në një degë anësore përfshin sërish commit-et e mëparshme të saj, që një klient me versionin e njoftuar të degës kryesore ta marrë degën anësore me një paketë të vetme.

Kjo është një formë e konsistencës shkakësore. Për të marrë një referencë, lexuesi sheh historikun e shkruesit që e krijoi atë. Gjatë një operacioni push, Pando kontrollon historikun e përbashkët për të cilin bien dakord klienti dhe serveri, duke siguruar që klientët të krijojnë skedarë paketash që mund të ndahen më lehtë.

Si rrjedhojë, Pando nuk ofron një gjendje të të gjitha referencave në një çast të caktuar gjatë operacioneve Git, as një renditje të përditësimeve të referencave brenda një operacioni clone ose fetch. Konkretisht, supozo se degët foo dhe bar përditësohen të dyja gjatë negocimit të një klonimi të plotë. Gjatë negocimit, një klient mund ta shohë foo në versionin 1 dhe bar në versionin 2, ndërsa një tjetër sheh foo në versionin 2 dhe bar në versionin 1. Në praktikë, përdoruesit dhe agjentët nuk varen nga renditja globale e përditësimeve të referencave, por nga rendi i përditësimeve të një reference të vetme.

Krahasimi i qasjeve

Në këtë simulim të tre modeleve të konsistencës, konfigurojmë 1 000 klientë që secili të zgjedhë një degë të veçantë e më pas të kryejë vazhdimisht push me commit-e unike, duke matur kohën totale të kaluar dhe vonesën nga push te fetch. Kjo e fundit është një matje e rëndësishme për ngarkesat e punës, pasi mat kohën e ciklit vajtje-ardhje që u duhet përdoruesve dhe agjentëve për të bashkëpunuar ose për të përdorur sisteme të tjera që mbështeten te kontrolli i versioneve. Simulimi modelon pajisje që variojnë nga makinat virtuale standarde te ato të nivelit të lartë, si dhe sisteme ruajtjeje blob-esh. Në këtë simulim, kemi lehtësuar kërkesën për konsistencë në të gjithë depon për konfirmimin me tri faza.

Simulating Git Server Implementations

Follow each writer through repeated pushes, and separately measure when an independent reader can check out each commit.

Three-phase commit

Ready
Simulated time
0 s
Mean push to fetch
—
Writers done
0 / 1,000

Each square represents one writer. All selected architectures run the same workload. Squares lighten as pushes are acknowledged and turn blue when a writer finishes. The chart shows writers finished over simulated time; independent readers can continue fetching afterward. Use arrow keys to select a writer, Home or End to jump, and Escape to clear.

0 / 10,000 pushes acknowledged · 0 fetched

Select a square to inspect that writer.

Object-store WAL

Ready
Simulated time
0 s
Mean push to fetch
—
Writers done
0 / 1,000

Each square represents one writer. All selected architectures run the same workload. Squares lighten as pushes are acknowledged and turn blue when a writer finishes. The chart shows writers finished over simulated time; independent readers can continue fetching afterward. Use arrow keys to select a writer, Home or End to jump, and Escape to clear.

0 / 10,000 pushes acknowledged · 0 fetched

Select a square to inspect that writer.

Pando

Ready
Simulated time
0 s
Mean push to fetch
—
Writers done
0 / 1,000

Each square represents one writer. All selected architectures run the same workload. Squares lighten as pushes are acknowledged and turn blue when a writer finishes. The chart shows writers finished over simulated time; independent readers can continue fetching afterward. Use arrow keys to select a writer, Home or End to jump, and Escape to clear.

0 / 10,000 pushes acknowledged · 0 fetched

Select a square to inspect that writer.

Writer progress through verified fetches

  • Three-phase commit
  • Object-store WAL
  • Pando
05001,00000 s
  • Waiting
  • Pushing
  • All pushes acknowledged
0 sLater

Synthetic teaching models, not production benchmarks. Mean push to fetch covers topic pushes, from the first attempt through retries until an independent reader verifies that commit. It includes waiting for a reader slot and excludes builds and tests. With merges enabled, writer completion includes the required fetches and trunk merge.

Experiment settings

Preparing simulation…

Results

Play the comparison to see the recorded results.

Synthetic teaching models, not production benchmarks. Mean push to fetch covers topic pushes, from the first attempt through retries until an independent reader verifies that commit. It includes waiting for a reader slot and excludes builds and tests. With merges enabled, writer completion includes the required fetches and trunk merge.

Ekzekuto këtë simulim që krahason Pando me dy qasje të tjera. Zgjidh infrastrukturën, nga pajisjet standarde te ato të nivelit të lartë, numrin e klientëve dhe cilësime të tjera për të parë krahasimin.

Sistemi i modeluar i konfirmimit me tri faza shfaq vonesë shkrimi dukshëm më të madhe nën ngarkesë, teksa disqet arrijnë kufirin e kapacitetit; ndërkohë, sistemet me regjistër paraprak shkrimi shfaqin vonesë leximi dukshëm më të madhe për të njëjtën arsye, pasi serverët e kanë të vështirë të mbajnë ritmin e leximit nga regjistri. Si në testimet reale në monodepon tonë, ashtu edhe në këtë simulim, Pando mbështet mijëra e mijëra klientë që mund të kryejnë push njëkohësisht pa ndikuar te performanca nën ngarkesë.

Kur trajton një push, Pando verifikon skedarin e paketës së ardhur ndërsa e transmeton në ruajtjen e blob-eve, pa e shpaketuar në një depo lokale. Kur një klient nis një fetch, Pando zgjedh paketat e ruajtura që i duhen lexuesit dhe lexuesi i shkarkon ato. Asnjë server nuk ka nevojë të aplikojë skedarë paketash në një depo lokale apo të kryejë operacione të kushtueshme shpaketimi dhe paketimi. Meqë këta serverë kryejnë kryesisht negocimin dhe përzgjedhjen e skedarëve të paketave, serverët Pando mund të funksionojnë në pajisje standarde.

Kjo i lejon Pando të zgjerohet deri në kufijtë e klientëve, të rrjetit midis klientëve dhe Pando, si dhe të shërbimit të ruajtjes së blob-eve. Me kapacitet të mjaftueshëm, klientët që punojnë në degë të pavarura mund të transferojnë paketa aq shpejt sa ua lejon lidhja e tyre. Për t’u shërbyer më shumë klientëve me atë shpejtësi, mund të shtojmë serverë Pando dhe të zgjerojmë krahas tyre depozitat e metadatave dhe të blob-eve.

Pushing and Fetching a Branch in Pando

Pando stores the writer’s packfile in blob storage and records the ref version in metadata service. On fetch, Pando selects the packs the reader needs, and Express serves them.

Stream the push

  • Packfile bytes
  • Metadata
  • Request / acknowledgment
  • Packfile URIs

Një agjent redakton skedarë, krijon një commit lokalisht dhe ekzekuton git push, që krijon një skedar pakete me ato ndryshime për të përditësuar një degë. Pando e merr paketën dhe e transmeton në ruajtjen e blob-eve. Pasi verifikon push-in e ardhur me dekodim në një kalim të vetëm, Pando përdor një transaksion me shumë çelësa për të regjistruar një version reference në depozitën tonë të metadatave dhe për të përditësuar në mënyrë atomike treguesin e referencës. Kjo i mundëson Pando të sigurojë konsistencën "lexo atë që ke shkruar vetë". I gjithë ky operacion shkrimi kërkon O(1)O(1) lexime dhe shkrime metadatash.

Kur një klient tjetër merr degën, Pando zgjedh një grup paketash të ruajtura duke përdorur historikun që klienti e ka tashmë. Ky operacion kërkon O(log⁡Δ)O(\log \Delta) lexime metadatash, ku Δ\Delta është largësia më e shkurtër, e matur në versione reference, midis asaj që klienti ka dhe asaj që kërkon. Serveri kthen URI-të e skedarëve të paketave dhe klienti i shkarkon përmes një shërbimi, Express, që i ruan skedarët e paketave në memorie të përkohshme rajonale.

Ky projektim mbështetet në tri shërbimet qendrore të arkitekturës së Pando: push, fetch dhe kompaktim.

Zgjerimi i kapacitetit për push

Kur një klient kryen push, një server tradicional Git sillet si një lojtar pokeri që hap të gjitha letrat, duke i treguar klientit çdo degë që ka. Më pas klienti mbledh commit-et, pemët dhe blob-et për të krijuar një skedar pakete që përjashton objektet që e di se serveri i ka tashmë.

Njoftimi i më shumë referencave mund ta zvogëlojë madhësinë e push-it. Por mund ta vështirësojë edhe ripërdorimin e paketës, sepse një klienti tjetër mund t’i mungojnë objektet që shkruesi i la jashtë.

Pando ndjek një qasje tjetër. Në vend që t’i hapë të gjitha letrat, ai i njofton klientit vetëm një grup të përzgjedhur degësh. Kjo bëhet për dy arsye:

  1. Ofrimi i një pamjeje konsistente të çdo reference është i kushtueshëm. Me miliona degë, vetëm njoftimi i referencave mund të kalojë 100 MiB. Për ta ofruar këtë, çdo server duhet ose të mbajë një hartëzim të përditësuar, me kosto të konsiderueshme bashkërendimi, ose të kryejë një kërkim në bazën e të dhënave, kostoja e të cilit rritet me numrin e referencave.

  2. Duke i ofruar klientit vetëm një nëngrup referencash, ai do të krijojë një paketë që varet vetëm nga ato që serveri e lejon shprehimisht të përjashtojë. Gjurmimi i varësive i lejon Pando të ripërdorë skedarin e paketës që një klient krijon gjatë një push-i, duke e shërbyer si përgjigje ndaj një fetch-i të mëvonshëm.

Sa më shumë referenca të njoftojë një server Git, aq më shumë burime kanë klientët që kryejnë push për të përjashtuar objekte, duke krijuar kështu paketa më të vogla. Megjithatë, për t’i ripërdorur këta skedarë paketash, serveri duhet të jetë në gjendje të vërtetojë se klientët që kryejnë fetch i kanë të gjitha varësitë. Përndryshe, skedari i paketës mund të lërë jashtë objekte që i duhen klientit.

Nga ana tjetër, nëse një server Git nuk njofton asnjë referencë, klienti do të krijonte një skedar pakete që përmban historikun e plotë të depos. Atë skedar pakete mund ta përdorë çdo klient tjetër, por me koston e konsiderueshme që marrja e çdo dege të bëhet praktikisht një klonim i plotë.

Kurbë që tregon si ndikojnë referencat e njoftuara në madhësinë e skedarit të paketës: nga historiku i plotë kur nuk njoftohet asnjë, te njoftimi i degës kryesore, e deri te vetëm objektet e reja kur njoftohen të gjitha referencat.

Njoftimi i më shumë referencave sjell skedarë paketash më të vegjël. Pjesa më e madhe e zvogëlimit mund të arrihet duke njoftuar vetëm një referencë.

Si parazgjedhje, kur një klient kryen push për një degë të re veçorie, Pando njofton si bazë vetëm një degë kryesore të caktuar. Kjo e mban madhësinë e njoftimit të pandryshuar ndërsa depos i shtohen degë, por kërkon kompromise. Kur një inxhinier kryen push shumë herë në një degë të vetme ose ndërton një degë veçorie mbi një tjetër, klienti duhet të ridërgojë gjithçka që është jashtë degës kryesore.

Kjo i bën më të mëdha operacionet push të njëpasnjëshme në degë, me objekte potencialisht të tepërta, dhe konsumon më shumë brez rrjeti të klientit. Në monodepon tonë, madhësia mediane e skedarit të paketës të krijuar kështu ishte nën 20 KiB dhe percentili i 99-të ishte nën 3 MiB. Për ne, ky ishte një kompromis i arsyeshëm, sepse një lexues që e ka tashmë historikun e njoftuar të degës kryesore mund ta marrë degën me atë skedar të vetëm pakete.

Pasi zgjedh grupin e referencave për t’ia njoftuar klientit, Pando pranon push-in dhe përditëson depozitën e metadatave. Pando e ndan përditësimin e metadatave në pjesë sinkrone dhe asinkrone. Përditësimi sinkron i metadatave siguron që klientët të mund ta marrin menjëherë commit-in e sapopërditësuar. Ai shkruan një version të ri reference dhe përditëson hartëzimin e treguesit të referencës drejt atij versioni, duke ruajtur majën e re, varësitë e përdorura për negocimin e skedarit të paketës dhe një lidhje drejt skedarit të dërguar me push.

Njëkohësisht, në të njëjtin transaksion regjistrohen detyra asinkrone, si planifikimi i kompaktimit. Për operacione push shumë të mëdha, vetëm një nëngrup commit-esh shkruhet në mënyrë sinkrone. Kjo na lejon të kërkojmë vetëm një numër konstant leximesh dhe shkrimesh në depozitën e metadatave, pavarësisht madhësisë së push-it.

E rëndësishme është që serverët Pando mund të pranojnë në mënyrë të pavarur operacione push në referenca pa lidhje mes tyre. I vetmi çelës për të cilin ka konkurrencë është treguesi i referencës, të cilin e mbrojmë me një operacion atomik të ngjashëm me krahasimin dhe zëvendësimin. Mund ta rrisim kapacitetin e përpunimit të shkrimeve duke shtuar serverë Pando, njësi zgjerimi të depozitës së metadatave ose depozita blob-esh.

Operacione fetch dhe clone me shpejtësinë e plotë të lidhjes

Kur një klient kryen një fetch, i jep serverit dy grupe ID-sh commit-esh, të njohura në protokoll si haves dhe wants. Në një server tradicional Git, serveri llogarit diferencën midis bashkësive të objekteve të arritshme nga commit-et e zotëruara dhe atyre të arritshme nga commit-et e kërkuara, i kompreson dhe ia dërgon rezultatin klientit. Ndonëse serveri Git me burim të hapur ka një sërë indeksesh lokale për ta përshpejtuar këtë operacion, krijimi i këtyre skedarëve të paketave mund të jetë i kushtueshëm dhe ata përgjithësisht nuk përshtaten mirë për ruajtje në memorie të përkohshme.

Në vend të kësaj, Pando përdor hartëzimet e commit-eve të regjistruara gjatë operacioneve push për të gjetur vlerat haves dhe wants të klientit dhe për t’i lidhur me një grup versionesh reference që përmbajnë ato commit-e. Secili prej këtyre versioneve të referencës lidhet me një skedar pakete që Pando e ka marrë më parë. Serveri e përdor këtë për të përcaktuar çfarë i duhet klientit, duke zgjedhur skedarët e paketave që mbulojnë grupin e objekteve të nevojshme.

Planning fetches in Pando

Pando compares what a client has with what it wants, then selects the stored packfiles needed—including any missing branch dependencies.

Already heldFetchMissing branch dependency

Fetch 27 trunk packs.

Select a branch to include its trunk dependencies.

Pando i hartëzon vlerat have dhe want të protokollit Git në një varg versionesh reference. Kërkimi i një dege anësore nënkupton edhe kërkimin e historikut deri te varësitë e saj në degën kryesore.

Protokolli Git lejon dërgimin e vetëm një skedari pakete në përgjigjen HTTP gjatë një operacioni clone ose fetch. Megjithatë, një veçori e nënvlerësuar e protokollit Git, packfile-uri, i lejon serverit të kthejë lidhje për shkarkimin veçmas të paketave shtesë. Pando përdor vetëm këtë mënyrë dhe transmeton drejtpërdrejt në përgjigje një skedar pakete bosh. Për ta mbështetur këtë veçori, OpenAI kontribuoi disa përmirësime për packfile-uri në projektin kryesor.

Sistemet e OpenAI operojnë në shumë rajone gjeografike, ndaj në secilin mbajmë grupe serverësh Pando me memorie të përkohshme lokale. Një shërbim shpërndarjeje paketash, Express, ruan në memorie të përkohshme të dhënat e depozitës sonë të blob-eve, ndërsa një shërbim më vete bën të njëjtën gjë për depozitën e metadatave. Këto memorie të përkohshme i mundësojnë Pando t’u përgjigjet kërkesave për një ID commit-i ose për një lexim të veçantë reference tërësisht nga gjendja e ruajtur në atë grup serverësh. Përdorim hashim konsistent për t’i drejtuar kërkesat për skedarë paketash te serverët Express, me shkallë gjetjeje në memorie të përkohshme mbi 99%.

Ky sistem memoriesh të përkohshme siguron kapacitet përpunimi jashtëzakonisht të lartë, të aftë të shfrytëzojë plotësisht kufirin e rrjetit midis klientëve dhe Pando. Duke përdorur këto URI skedarësh paketash dhe memorie të përkohshme lokale, kemi verifikuar se vetëm me makina virtuale standarde të ofruesve cloud, operacionet clone dhe fetch shfrytëzojnë plotësisht lidhje rrjeti 10 Gbps.

Kompaktimi dhe koha deri te bajti i parë

Për shumicën e serverëve Git, ripaketimi dhe pastrimi i objekteve të papërdorura janë të nevojshëm për të ruajtur performancën e një depoje në rritje. Të dy këta hapa lirojnë hapësirë, por kërkojnë shumë burime llogaritëse dhe I/O.

Në një depo që ndryshon shpejt si monodepoja e OpenAI, nuk është praktike të dërgohet një URI e veçantë skedari pakete për çdo push të kryer që nga fetch-i i fundit. Çdo ditë, një klienti do t’i duhej të shkarkonte dhjetëra mijëra skedarë paketash për të përditësuar degën e vet kryesore.

Në vend të kësaj, Pando bashkon paketa në sfond për ta ulur këtë kosto shtesë, duke përdorur një projektim të ngjashëm me kompaktimin në pemët e bashkimit të strukturuara si regjistër. Çdo push prodhon atë që Pando e quan skedar pakete "L0", njësia më e vogël e të dhënave që Pando mund të transmetojë. Me kalimin e kohës, proceset në sfond i mbledhin këta skedarë paketash në grupe mbuluese që përfshijnë një varg versionesh reference dhe rriten gjeometrikisht duke nisur nga L0. Sot, monodepoja jonë përdor grupe mbuluese skedarësh paketash deri në nivelin L4.

Këto grupe mbuluese shërbejnë për dy qëllime. Pasi një grup mbulues mbushet mjaftueshëm, një proces kompaktimi e merr përsipër dhe krijon një skedar të vetëm pakete. Kjo përmirëson raportin e kompresimit duke riorganizuar objektet brenda skedarit të paketës. Por përmirëson edhe performancën e negocimit të fetch-it, duke vepruar si një listë me kapërcime mbi versionet e referencave. Duke përshkuar njëkohësisht indekset në çdo nivel, Pando mund të zgjedhë në kohë logaritmike një grup paketash për t’ia dërguar klientit. Këto grupe mbuluese skedarësh paketash, të ripaketuara ose jo, mundësojnë një zgjidhje më efikase për planifikimin e fetch-it, duke ulur kërkesat si për kapacitetin e përpunimit, ashtu edhe për vonesën e Pando.

Compaction in Pando

Small packfiles are grouped into larger covers across levels, improving compression and speeding up fetches.

Compaction in progressPublished cover

Kompaktimi bashkon në sfond skedarë paketash nga shumë versione reference, duke mundësuar operacione fetch më efikase me më pak skedarë.

Ndryshe nga shumë serverë Git, skedarët e paketave mbahen në çdo nivel dhe nuk hidhen poshtë apo hiqen nga pastrimi i objekteve të papërdorura. Paketat në çdo nivel përdoren vazhdimisht për t’u shërbyer klientëve, bazuar te vlerat haves dhe wants që ata paraqesin gjatë një fetch-i. Për klientët që e përdorin Pando si API, leximi i një objekti çfarëdo nga një skedar pakete zakonisht kërkon më pak të dhëna nga një L0 sesa nga një L4, sepse ka më pak gjasa të jetë i kompresuar.

Kompaktimi në Pando ul ndjeshëm madhësinë totale të transferimeve te klientët dhe bën që kostoja e planifikimit të paketave të rritet në mënyrë nënlineare me masën në të cilën klienti ka mbetur prapa. Kjo është veçanërisht e rëndësishme për depot e mëdha që ndryshojnë shpejt, të cilat presim të bëhen norma e re në zhvillimin e softuerit.

Ndërtimi i Pando

E ndërtuam Pando me Codex, duke kaluar nga nisja e projektit në përdorim real për vetëm 10 javë. Bërthama e Pando u projektua nga një inxhinier i vetëm, u zbatua nga ekipe agjentësh dhe u vu në përdorim nga një grup i vogël inxhinierësh. Pando filloi të shërbente trafik real në prill të këtij viti dhe është pjesë e një sistemi më të gjerë mjetesh për menaxhimin e kontrollit të kodit burimor që përdoren në OpenAI.

Përdorëm një larmi të gjerë qasjesh për të verifikuar projektimin e Pando. Zbatuam parimet tona për ndërtimin e themeleve më të sigurta të softuerit⁠. Meqë ishte një projekt nga e para, zgjodhëm ta zbatonim Pando në Rust dhe pa varësi të trashëguara. Shkruam një grup testesh përputhshmërie që agjentët të mund t’i testonin ndryshimet e tyre kundrejt sjelljes standarde të Git. Zhvilluam edhe struktura testimi me simulim determinist, që na lejonin të kontrollonim invariantet dhe vetitë e sistemit, duke gjetur e zbutur kushte gare të vështira për t’u dalluar dhe regresione në negocim e planifikim paketash.

Shumë modele kontribuuan në këtë sistem; teksa bëheshin të disponueshme modele të reja, i përdornim për të përmirësuar performancën dhe besueshmërinë e Pando. Duke përdorur GPT‑6 Astra, agjentët shkruan në Lean dhe TLA+ për të formalizuar një "teori të Pando", të cilën e përdorëm për të gjetur e korrigjuar gabime në zbatim dhe për të provuar vetitë e sistemit. Disa seanca të pandërprera u zhvilluan për qindra orë, duke gjetur dhe korrigjuar raste kufitare në Pando. Gjithashtu mbajmë agjentë në punë pa ndërprerje për të testuar sigurinë e Git dhe Pando me sulme të simuluara, duke përdorur modele me aftësi Daybreak.

Vënia në përdorim e Pando

Fillimisht e vendosëm Pando si një ndërmjetës që përcillte leximet dhe shkrimet te sistemi ynë ekzistues i kontrollit të kodit burimor. Kjo na lejoi ta mbanim Pando të sinkronizuar me sistemin e mëparshëm, që ta kalonim trafikun në Pando në mënyrë të sigurt, pa ndërprerje shërbimi.

Si pjesë e projektimit të memories së tij të përkohshme, Pando mund të eliminojë kërkesat e dyfishta dhe t’i bashkojë kërkesat para se t’i përcjellë. Kjo na lejoi t’i mbanim mjetet ekzistuese në gjendje të mirë pune, ndërsa i kalonim sistemet në Pando një nga një. Teksa kalonim më shumë ngarkesa pune në Pando, operacionet e tyre push mbushnin memorien e përkohshme të Pando dhe përmirësonin besueshmërinë e sistemit tonë të mëparshëm të prapavijës.

Për të optimizuar performancën gjatë përdorimit të Pando, filluam të shpërndanim variantin tonë publik të Git në kompjuterët e zhvilluesve dhe brenda aplikacionit ChatGPT për kompjuter. Për t’i kaluar klientët në Pando me faza, përdorëm një shtresë të brendshme ndërmjetëse mbi Git CLI. Krijuam shumë mjete të tjera për trajtimin e kërkesave për ndryshime, rishikimin e kodit dhe API për automatizime. Krahas trafikut Git, migruam qindra integrime që vareshin nga API të trashëguara, webhook-e dhe shkarkime deposh.

Vetë Codex i ndihmoi zhvilluesit dhe ekipet ta bënin kalimin. Krijuam aftësi për përgatitjen e kopjeve ekzistuese të punës dhe për t’i udhëzuar agjentët të përdornin sistemin e ri. Si rezultat, zhvilluesit thjesht mund t’i kërkonin Codex të migronte mjediset dhe shërbimet e tyre të zhvillimit.

Kalimi në Pando përmirësoi besueshmërinë e bashkimeve dhe uli me afro 80% vonesën mediane të operacioneve push.

Pando mund të shpërndajë një petabajt të dhënash Git në ditë me vetëm pak bërthama CPU-je. Pando ka shpërndarë më shumë se 57 terabajt paketa Git brenda një ore të vetme, ku mbi 99% e bajteve vinin nga memoria e përkohshme në diskun lokal.

Ripërdorimi i paketave u lejon shumë klientëve të shkarkojnë të njëjtin historik depoje me pak përpunim në nyjet që e shërbejnë. Ky shembull tregon një depo të vetme, por Pando është projektuar për të mbështetur shumë më tepër. Me rritjen e kërkesës, mund të zgjerojmë në mënyrë të pavarur shpërndarjen e të dhënave dhe negocimin Git.

Kontributi në projektin Git

Ndërtimi i Pando mbi protokollin dhe klientin Git na ndihmoi të identifikonim gabime dhe mundësi për të përmirësuar performancën e vetë Git.

Për shembull, Pando u shërben klientëve drejtpërdrejt paketa të ripërdorshme, ndaj shkarkimi dhe indeksimi i tyre u bënë thelbësore për ta bërë sistemin të shpejtë e të besueshëm. Kjo punë nxori në pah raste kufitare në shkarkimet e njëkohshme, pastrimin pas transferimeve të ndërprera dhe rinisjen e shkarkimeve që kishin përfunduar tashmë. I korrigjuam këto rrjedha ekzekutimi, shtuam verifikime gjatë pranimit të një pakete ekzistuese për një fetch dhe ia kontribuuam këtë punë projektit kryesor.

Duhej gjithashtu të shihnim ku shpenzoheshin koha dhe brezi i rrjetit, ndaj shtuam gjurmim për shkarkimet packfile-uri dhe numërim bajtesh për krijimin e paketave, duke e bërë më të lehtë të dallohej nëse një fetch i ngadaltë e harxhonte kohën duke krijuar apo transferuar paketa.

Në variantin e Git të OpenAI⁠(hapet në një dritare të re), klienti mund të shkarkojë dhe indeksojë paralelisht paketa të pavarura. Shtuam konceptin e "vlerave have të deklaruara shprehimisht", që një server të mund të njoftojë majën aktuale të një dege veçmas nga historiku që një klient që kryen push mund ta lërë jashtë paketës së vet. Në Pando, kjo u mundëson klientëve të përdorin --force-with-lease për të kontrolluar që një degë veçorie nuk ka lëvizur dhe ta ndërtojnë paketën duke u bazuar vetëm te dega kryesore. Kushdo që e ka atë historik të degës kryesore mund ta marrë më pas degën duke përdorur të njëjtën paketë.

Disa prej këtyre përmirësimeve janë tashmë në projektin kryesor Git dhe shumë të tjera në depon tonë publike. Po vazhdojmë të punojmë me komunitetin Git që këto përmirësime të jenë të dobishme edhe përtej Pando. Mund ta ndjekësh këtë punë në gjurmuesin tonë publik të arnimeve⁠(hapet në një dritare të re).A ka qenë e dobishme kjo bisedë deri tani?

Çfarë vjen më pas

Duke rimenduar qasjet tradicionale ndaj zgjerimit të depove Git, Pando na mundëson të zgjerojmë monodepon tonë pa ndryshuar flukset e punës në Git që inxhinierët dhe agjentët tanë përdorin tashmë. Në monodepon tonë, Pando ka mundësuar më shumë punë paralele, ka përmirësuar besueshmërinë e bashkimeve dhe ka shkurtuar kohën për publikimin e ndryshimeve në kod. Përtej monodepos sonë, po shqyrtojmë edhe përdorime të tjera të Pando brenda OpenAI, përfshirë ngarkesa pune ku një numër i madh agjentësh duhet të bashkëpunojnë në një depo të përbashkët Git.

Teksa inxhinierët dhe agjentët prodhojnë më shumë softuer, më shumë ekipe jashtë OpenAI do të ndeshen me kufijtë që hasëm ne në kontrollin e kodit burimor. Aktualisht po shqyrtojmë mënyra për ta ndarë me përdoruesit tanë teknologjinë që e bën të mundur Pando.

Pando mbështetet në dy dekada përvojë të përdoruesve dhe operatorëve të depove Git. Do të vazhdojmë ta zhvillojmë Pando duke punuar me komunitetin me burim të hapur të Git për të ndarë çdo përmirësim që u sjell dobi përdoruesve të Git në përgjithësi.

Autori

OpenAI