3 // Some smart guy removed XMLReader's global constants from PHP 5.1
4 // and replaced them with class constants. Breaking source compatibility
5 // is SUPER awesome, and I love languages which do this constantly!
6 $xmlReaderConstants = array(
21 "SIGNIFICANT_WHITESPACE",
29 foreach( $xmlReaderConstants as $name ) {
30 $fullName = "XMLREADER_$name";
31 $newName = "XMLReader::$name";
32 if( !defined( $fullName ) ) {
33 if( defined( $newName ) ) {
34 define( $fullName, constant( $newName ) );
36 // broken or missing the extension...
42 * Readahead helper for making large MediaWiki data dumps;
43 * reads in a previous XML dump to sequentially prefetch text
44 * records already normalized and decompressed.
46 * This can save load on the external database servers, hopefully.
48 * Assumes that dumps will be recorded in the canonical order:
49 * - ascending by page_id
50 * - ascending by rev_id within each page
51 * - text contents are immutable and should not change once
52 * recorded, so the previous dump is a reliable source
54 * Requires PHP 5 and the XMLReader PECL extension.
55 * @ingroup Maintenance
60 var $atPageEnd = false;
64 function BaseDump( $infile ) {
65 $this->reader = new XMLReader();
66 $this->reader->open( $infile );
70 * Attempts to fetch the text of a particular page revision
71 * from the dump stream. May return null if the page is
74 * @param int $page ID number of page to read
75 * @param int $rev ID number of revision to read
76 * @return string or null
78 function prefetch( $page, $rev ) {
79 $page = intval( $page );
80 $rev = intval( $rev );
81 while( $this->lastPage < $page && !$this->atEnd ) {
82 $this->debug( "BaseDump::prefetch at page $this->lastPage, looking for $page" );
85 if( $this->lastPage > $page || $this->atEnd ) {
86 $this->debug( "BaseDump::prefetch already past page $page looking for rev $rev [$this->lastPage, $this->lastRev]" );
89 while( $this->lastRev < $rev && !$this->atEnd && !$this->atPageEnd ) {
90 $this->debug( "BaseDump::prefetch at page $this->lastPage, rev $this->lastRev, looking for $page, $rev" );
93 if( $this->lastRev == $rev && !$this->atEnd ) {
94 $this->debug( "BaseDump::prefetch hit on $page, $rev [$this->lastPage, $this->lastRev]" );
95 return $this->nextText();
97 $this->debug( "BaseDump::prefetch already past rev $rev on page $page [$this->lastPage, $this->lastRev]" );
102 function debug( $str ) {
103 wfDebug( $str . "\n" );
105 //$dumper->progress( $str );
111 function nextPage() {
112 if( $this->skipTo( 'page', 'mediawiki' ) ) {
113 if( $this->skipTo( 'id' ) ) {
114 $this->lastPage = intval( $this->nodeContents() );
116 $this->atPageEnd = false;
127 if( $this->skipTo( 'revision' ) ) {
128 if( $this->skipTo( 'id' ) ) {
129 $this->lastRev = intval( $this->nodeContents() );
132 $this->atPageEnd = true;
139 function nextText() {
140 $this->skipTo( 'text' );
141 return strval( $this->nodeContents() );
147 function skipTo( $name, $parent='page' ) {
151 while( $this->reader->read() ) {
152 if( $this->reader->nodeType == XMLREADER_ELEMENT &&
153 $this->reader->name == $name ) {
156 if( $this->reader->nodeType == XMLREADER_END_ELEMENT &&
157 $this->reader->name == $parent ) {
158 $this->debug( "BaseDump::skipTo found </$parent> searching for <$name>" );
162 return $this->close();
166 * Shouldn't something like this be built-in to XMLReader?
167 * Fetches text contents of the current element, assuming
168 * no sub-elements or such scary things.
172 function nodeContents() {
176 if( $this->reader->isEmptyElement ) {
180 while( $this->reader->read() ) {
181 switch( $this->reader->nodeType ) {
183 // case XMLREADER_WHITESPACE:
184 case XMLREADER_SIGNIFICANT_WHITESPACE:
185 $buffer .= $this->reader->value;
187 case XMLREADER_END_ELEMENT:
191 return $this->close();
198 $this->reader->close();