@@ -70,29 +70,31 @@ public function writeHnsw(string $path, array $state): void
7070
7171 $ fh = fopen ($ path , 'wb ' );
7272 if ($ fh === false ) {
73- throw new \RuntimeException ("Failed to open hnsw.bin for writing: {$ path }" );
73+ throw new \RuntimeException ("Failed to open file for writing: {$ path }" );
7474 }
7575
76- fwrite ($ fh , self ::HNSW_MAGIC );
77- fwrite ($ fh , pack ('C ' , self ::VERSION ));
78- fwrite ($ fh , pack ('NNNN ' , $ dim , $ nodeCount , $ ep , (int ) $ state ['maxLayer ' ]));
76+ try {
77+ $ this ->checkedWrite ($ fh , self ::HNSW_MAGIC );
78+ $ this ->checkedWrite ($ fh , pack ('C ' , self ::VERSION ));
79+ $ this ->checkedWrite ($ fh , pack ('NNNN ' , $ dim , $ nodeCount , $ ep , (int ) $ state ['maxLayer ' ]));
7980
80- foreach ($ nodes as $ nodeId => $ node ) {
81- fwrite ($ fh , pack ('NN ' , $ nodeId , $ node ['maxLayer ' ]));
82- if ($ dim > 0 ) {
83- fwrite ($ fh , pack ('d* ' , ...$ node ['vector ' ]));
84- }
85- for ($ l = 0 ; $ l <= $ node ['maxLayer ' ]; $ l ++) {
86- $ conns = $ node ['connections ' ][$ l ] ?? [];
87- $ cnt = count ($ conns );
88- fwrite ($ fh , pack ('N ' , $ cnt ));
89- if ($ cnt > 0 ) {
90- fwrite ($ fh , pack ('N* ' , ...$ conns ));
81+ foreach ($ nodes as $ nodeId => $ node ) {
82+ $ this ->checkedWrite ($ fh , pack ('NN ' , $ nodeId , $ node ['maxLayer ' ]));
83+ if ($ dim > 0 ) {
84+ $ this ->checkedWrite ($ fh , pack ('d* ' , ...$ node ['vector ' ]));
85+ }
86+ for ($ l = 0 ; $ l <= $ node ['maxLayer ' ]; $ l ++) {
87+ $ conns = $ node ['connections ' ][$ l ] ?? [];
88+ $ cnt = count ($ conns );
89+ $ this ->checkedWrite ($ fh , pack ('N ' , $ cnt ));
90+ if ($ cnt > 0 ) {
91+ $ this ->checkedWrite ($ fh , pack ('N* ' , ...$ conns ));
92+ }
9193 }
9294 }
95+ } finally {
96+ fclose ($ fh );
9397 }
94-
95- fclose ($ fh );
9698 }
9799
98100 /**
@@ -192,31 +194,33 @@ public function writeBm25(string $path, array $state): void
192194 {
193195 $ fh = fopen ($ path , 'wb ' );
194196 if ($ fh === false ) {
195- throw new \RuntimeException ("Failed to open bm25.bin for writing: {$ path }" );
197+ throw new \RuntimeException ("Failed to open file for writing: {$ path }" );
196198 }
197199
198- fwrite ($ fh , self ::BM25_MAGIC );
199- fwrite ($ fh , pack ('C ' , self ::VERSION ));
200- fwrite ($ fh , pack ('N ' , $ state ['totalTokens ' ]));
200+ try {
201+ $ this ->checkedWrite ($ fh , self ::BM25_MAGIC );
202+ $ this ->checkedWrite ($ fh , pack ('C ' , self ::VERSION ));
203+ $ this ->checkedWrite ($ fh , pack ('N ' , $ state ['totalTokens ' ]));
201204
202- $ docLengths = $ state ['docLengths ' ];
203- fwrite ($ fh , pack ('N ' , count ($ docLengths )));
204- foreach ($ docLengths as $ nodeId => $ length ) {
205- fwrite ($ fh , pack ('NN ' , $ nodeId , $ length ));
206- }
205+ $ docLengths = $ state ['docLengths ' ];
206+ $ this -> checkedWrite ($ fh , pack ('N ' , count ($ docLengths )));
207+ foreach ($ docLengths as $ nodeId => $ length ) {
208+ $ this -> checkedWrite ($ fh , pack ('NN ' , $ nodeId , $ length ));
209+ }
207210
208- $ invertedIndex = $ state ['invertedIndex ' ];
209- fwrite ($ fh , pack ('N ' , count ($ invertedIndex )));
210- foreach ($ invertedIndex as $ term => $ postings ) {
211- $ termBytes = (string ) $ term ;
212- fwrite ($ fh , pack ('n ' , strlen ($ termBytes )) . $ termBytes );
213- fwrite ($ fh , pack ('N ' , count ($ postings )));
214- foreach ($ postings as $ postNodeId => $ tf ) {
215- fwrite ($ fh , pack ('NN ' , $ postNodeId , $ tf ));
211+ $ invertedIndex = $ state ['invertedIndex ' ];
212+ $ this ->checkedWrite ($ fh , pack ('N ' , count ($ invertedIndex )));
213+ foreach ($ invertedIndex as $ term => $ postings ) {
214+ $ termBytes = (string ) $ term ;
215+ $ this ->checkedWrite ($ fh , pack ('n ' , strlen ($ termBytes )) . $ termBytes );
216+ $ this ->checkedWrite ($ fh , pack ('N ' , count ($ postings )));
217+ foreach ($ postings as $ postNodeId => $ tf ) {
218+ $ this ->checkedWrite ($ fh , pack ('NN ' , $ postNodeId , $ tf ));
219+ }
216220 }
221+ } finally {
222+ fclose ($ fh );
217223 }
218-
219- fclose ($ fh );
220224 }
221225
222226 /**
@@ -290,4 +294,17 @@ public function readBm25(string $path): array
290294 'invertedIndex ' => $ invertedIndex ,
291295 ];
292296 }
297+
298+ /**
299+ * @param resource $fh
300+ */
301+ private function checkedWrite ($ fh , string $ data ): void
302+ {
303+ $ len = strlen ($ data );
304+ $ written = fwrite ($ fh , $ data );
305+
306+ if ($ written !== $ len ) {
307+ throw new \RuntimeException ("Failed to write {$ len } bytes (wrote " . ($ written === false ? '0 ' : $ written ) . ') ' );
308+ }
309+ }
293310}
0 commit comments