3 OpenIsis - an open implementation of the CDS/ISIS database
4 Version 0.8.x (patchlevel see file Version)
5 Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 see README for more information
24 // $Id: File.php,v 1.4 2003/06/13 19:35:24 kripke Exp $
28 the magic for a 4/4/0 little endian isis xref file.
29 http://OpenIsis.org/openisis/doc/Serialized
31 define( 'ISIS_FILE_MAGIC', "ISIXD\0:)" );
33 The flat file database.
34 It does not know anything about isis records,
35 it's just dealing with the string representation.
37 58971 records (unesb), 29442129 bytes flat (34565120 as .mst)
38 mkxrf: 8.1 sec (7280 recs / sec)
39 read all (just the string): 3.48 sec (~17.000 recs / sec)
40 read 10.000, creating recs: 3.95 sec
41 read 1.000, creating recs, printing: ~2 sec
43 @version $Revision: 1.4 $
52 /** number of records == number of last record
56 function Isis_File ( $name, $write = 0 )
60 $this->mst = fopen($name.'.txt', $write ? 'a+' : 'r');
63 flock($this->mst, $write ? LOCK_EX : LOCK_SH);
64 $s = fstat($this->mst);
66 if ( file_exists($name.'.ptr') ) // avoid annoying warning
67 $this->xrf = fopen($name.'.ptr', $write ? 'r+' : 'r');
71 $s = fstat($this->xrf);
72 $magic = fread($this->xrf, 8);
73 $remake = $s['mtime'] < $mtime || ISIS_FILE_MAGIC != $magic;
75 $this->len = $s['size'] / 8 - 1;
76 if ( $remake && !$write ) {
81 if ( !$this->xrf && !($this->xrf = fopen($name.'.ptr','w+')) ) {
93 ftruncate($this->xrf, 0);
95 fwrite( $this->xrf, ISIS_FILE_MAGIC, 8 );
99 $line = fgets($this->mst);
100 $end = !is_string($line) || '' == $line;
101 if ( $end || "\n" == $line{0} ) {
102 $now = ftell($this->mst);
103 $len = $now - $pos - 1;
107 $xrf = pack('VV', $pos, $len);
108 // echo "mfn $mfn pos $pos len $len\n";
109 if ( 8 != ($foo = fwrite($this->xrf, $xrf)) )
111 if ($this->len < $mfn)
123 && 2 == sscanf($line, "%c %d", &$ctrl, &$num)
127 $pos = ftell($this->mst);
129 fseek($this->xrf, 8*$mfn);
134 fflush( $this->xrf );
139 @return string number $mfn or null
141 function read ( $mfn )
143 fseek($this->xrf, 8*$mfn);
144 $xrf = fread( $this->xrf, 8 );
145 if ( 8 != strlen($xrf) ) {
146 // echo "no xrf for $mfn\n";
149 $xrf = unpack('Vpos/Vlen', $xrf);
150 // echo "mfn $mfn pos ${xrf['pos']} len ${xrf['len']}\n";
151 if ( !$xrf['pos'] || !$xrf['len'] )
153 fseek($this->mst, $xrf['pos']);
154 $rec = fread($this->mst, $xrf['len']);
155 return $xrf['len'] == strlen($rec) ? $rec : null;
160 write $data as $mfn or ++$this->len
163 function write ( $data, $mfn = 0 )
166 trigger_error( $this->name.' not writable', E_USER_ERROR );
169 elseif ($this->len < $mfn)
171 if ( !is_string($data) )
173 elseif ( $len = strlen($data) ) {
174 if ("\n" == $data{$len-1})
179 fseek($this->mst, 0, SEEK_END); // prbly not needed by mode a+
180 fwrite($this->mst, "\nW\t$mfn\n");
182 $pos = ftell($this->mst);
184 fwrite($this->mst, $data);
185 fseek($this->xrf, 8*$mfn);
186 // echo "write $mfn len $len\n";
187 fwrite($this->xrf, pack('VV', $pos, $len));
196 trigger_error( $this->name.' not writable', E_USER_ERROR );
197 $c = fopen($this->name.'.new', 'w+');
198 flock($c, LOCK_EX); // so we have exclusive locks on both
199 for ( $n=1; $n<=$this->len; $n++ )
200 fwrite($c, is_null($data = $this->read($n))
201 ? "\n" : "\n".$data."\n"
204 if ( file_exists($this->name.'.old') )
205 unlink($this->name.'.old');
206 rename($this->name.'.txt', $this->name.'.old');
207 rename($this->name.'.new', $this->name.'.txt');
210 $this->mkxref(); // frob the xref in place