80 if ( !function_exists(
'gzdeflate' ) ) {
81 throw new MWException(
"Need zlib support to read or write this "
82 .
"kind of history object (ConcatenatedGzipHistoryBlob)\n" );
93 if ( !isset( $this->mItems[$hash] ) ) {
94 $this->mItems[$hash] = $text;
95 $this->mSize += strlen( $text );
106 if ( array_key_exists( $hash, $this->mItems ) ) {
107 return $this->mItems[$hash];
119 $this->mDefaultHash = $this->
addItem( $text );
127 return $this->
getItem( $this->mDefaultHash );
136 $this->mSize -= strlen( $this->mItems[$hash] );
137 unset( $this->mItems[$hash] );
144 if ( !$this->mCompressed ) {
145 $this->mItems = gzdeflate(
serialize( $this->mItems ) );
146 $this->mCompressed =
true;
154 if ( $this->mCompressed ) {
155 $this->mItems =
unserialize( gzinflate( $this->mItems ) );
156 $this->mCompressed =
false;
165 return [
'mVersion',
'mCompressed',
'mItems',
'mDefaultHash' ];
179 return $this->mSize < $this->mMaxSize
210 $this->mHash = $hash;
242 if ( isset( self::$blobCache[$this->mOldId] ) ) {
246 $row =
$dbr->selectRow(
248 [
'old_flags',
'old_text' ],
249 [
'old_id' => $this->mOldId ]
256 $flags = explode(
',', $row->old_flags );
257 if ( in_array(
'external', $flags ) ) {
258 $url = $row->old_text;
259 $parts = explode(
'://', $url, 2 );
260 if ( !isset( $parts[1] ) || $parts[1] ==
'' ) {
263 $row->old_text = ExternalStore::fetchFromURL( $url );
267 if ( !in_array(
'object', $flags ) ) {
271 if ( in_array(
'gzip', $flags ) ) {
279 if ( !is_object( $obj ) ) {
287 self::$blobCache = [ $this->mOldId => $obj ];
290 return $obj->getItem( $this->mHash );
319 $this->mCurId = $curid;
337 $row =
$dbr->selectRow(
'cur', [
'cur_text' ], [
'cur_id' => $this->mCurId ] );
341 return $row->cur_text;
394 if ( !function_exists(
'gzdeflate' ) ) {
395 throw new MWException(
"Need zlib support to read or write DiffHistoryBlob\n" );
405 if ( $this->mFrozen ) {
406 throw new MWException( __METHOD__ .
": Cannot add more items after sleep/wakeup" );
409 $this->mItems[] = $text;
410 $this->mSize += strlen( $text );
411 $this->mDiffs =
null;
412 return count( $this->mItems ) - 1;
420 return $this->mItems[$key];
427 $this->mDefaultKey = $this->
addItem( $text );
434 return $this->
getItem( $this->mDefaultKey );
441 if ( !function_exists(
'xdiff_string_rabdiff' ) ) {
442 throw new MWException(
"Need xdiff 1.5+ support to write DiffHistoryBlob\n" );
444 if ( isset( $this->mDiffs ) ) {
448 if ( !count( $this->mItems ) ) {
468 $mItemsCount = count( $this->mItems );
469 for ( $i = 0; $i < $mItemsCount; $i++ ) {
470 $text = $this->mItems[$i];
474 $mainTail = $sequences[
'main'][
'tail'];
475 if ( strlen( $text ) < strlen( $mainTail ) * $smallFactor ) {
481 $seq =& $sequences[$seqName];
482 $tail = $seq[
'tail'];
483 $diff = $this->
diff( $tail, $text );
484 $seq[
'diffs'][] = $diff;
486 $seq[
'tail'] = $text;
493 $this->mDiffMap = [];
494 foreach ( $sequences as $seq ) {
495 if ( !count( $seq[
'diffs'] ) ) {
498 if ( $tail ===
'' ) {
499 $this->mDiffs[] = $seq[
'diffs'][0];
501 $head = $this->
patch(
'', $seq[
'diffs'][0] );
502 $this->mDiffs[] = $this->
diff( $tail, $head );
504 $this->mDiffMap[] = $seq[
'map'][0];
505 $diffsCount = count( $seq[
'diffs'] );
506 for ( $i = 1; $i < $diffsCount; $i++ ) {
507 $this->mDiffs[] = $seq[
'diffs'][$i];
508 $this->mDiffMap[] = $seq[
'map'][$i];
510 $tail = $seq[
'tail'];
520 # Need to do a null concatenation with warnings off, due to bugs in the current version of xdiff
521 # "String is not zero-terminated"
522 Wikimedia\suppressWarnings();
523 $diff = xdiff_string_rabdiff( $t1, $t2 ) .
'';
524 Wikimedia\restoreWarnings();
534 if ( function_exists(
'xdiff_string_bpatch' ) ) {
535 Wikimedia\suppressWarnings();
536 $text = xdiff_string_bpatch(
$base, $diff ) .
'';
537 Wikimedia\restoreWarnings();
541 # Pure PHP implementation
543 $header = unpack(
'Vofp/Vcsize', substr( $diff, 0, 8 ) );
545 # Check the checksum if hash extension is available
547 if ( $ofp !==
false && $ofp !== substr( $diff, 0, 4 ) ) {
548 wfDebug( __METHOD__ .
": incorrect base checksum\n" );
552 wfDebug( __METHOD__ .
": incorrect base length\n" );
558 while ( $p < strlen( $diff ) ) {
559 $x = unpack(
'Cop', substr( $diff, $p, 1 ) );
564 $x = unpack(
'Csize', substr( $diff, $p, 1 ) );
566 $out .= substr( $diff, $p, $x[
'size'] );
570 $x = unpack(
'Vcsize', substr( $diff, $p, 4 ) );
572 $out .= substr( $diff, $p, $x[
'csize'] );
576 $x = unpack(
'Voff/Vcsize', substr( $diff, $p, 8 ) );
578 $out .= substr(
$base, $x[
'off'], $x[
'csize'] );
581 wfDebug( __METHOD__ .
": invalid op\n" );
596 if ( !function_exists(
'hash' ) ) {
601 if ( $init ===
null ) {
602 $init = str_repeat(
"\xf0", 205 ) .
"\xee" . str_repeat(
"\xf0", 67 ) .
"\x02";
608 return strrev( hash(
'adler32', $init .
$s,
true ) );
612 if ( !$this->mDiffs ) {
616 $mDiffsCount = count( $this->mDiffs );
617 for ( $diffKey = 0; $diffKey < $mDiffsCount; $diffKey++ ) {
618 $textKey = $this->mDiffMap[$diffKey];
619 $text = $this->
patch( $tail, $this->mDiffs[$diffKey] );
620 $this->mItems[$textKey] = $text;
630 if ( !count( $this->mItems ) ) {
637 foreach ( $this->mDiffMap as $i ) {
649 if ( isset( $this->mDefaultKey ) ) {
652 $this->mCompressed = gzdeflate(
serialize( $info ) );
653 return [
'mCompressed' ];
658 $this->mFrozen =
true;
659 $info =
unserialize( gzinflate( $this->mCompressed ) );
660 unset( $this->mCompressed );
667 if ( isset( $info[
'default'] ) ) {
668 $this->mDefaultKey = $info[
'default'];
670 $this->mDiffs = $info[
'diffs'];
671 if ( isset( $info[
'base'] ) ) {
673 $this->mDiffMap = range( 0, count( $this->mDiffs ) - 1 );
674 array_unshift( $this->mDiffs,
675 pack(
'VVCV', 0, 0, self::XDL_BDOP_INSB, strlen( $info[
'base'] ) ) .
679 $map = explode(
',', $info[
'map'] );
681 $this->mDiffMap = [];
682 foreach ( $map as $i ) {
684 $this->mDiffMap[] = $cur;
697 return $this->mSize < $this->mMaxSize
710 class_alias( ConcatenatedGzipHistoryBlob::class,
'concatenatedgziphistoryblob' );
711 class_alias( HistoryBlobCurStub::class,
'historyblobcurstub' );
712 class_alias( HistoryBlobStub::class,
'historyblobstub' );
unserialize( $serialized)
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Concatenated gzip (CGZ) storage Improves compression ratio by concatenating like objects before gzipp...
compress()
Compress the bulk data in the object.
isHappy()
Helper function for compression jobs Returns true until the object is "full" and ready to be committe...
uncompress()
Uncompress bulk data.
removeItem( $hash)
Remove an item.
Diff-based history compression Requires xdiff 1.5+ and zlib.
string $mCompressed
Compressed storage.
array $mDiffMap
The diff map, see above.
bool $mFrozen
True if the object is locked against further writes.
int $mSize
Total uncompressed size.
array $mItems
Uncompressed item cache.
xdiffAdler32( $s)
Compute a binary "Adler-32" checksum as defined by LibXDiff, i.e.
int $mMaxSize
The maximum uncompressed size before the object becomes sad Should be less than max_allowed_packet.
int $mMaxCount
The maximum number of text items before the object becomes sad.
isHappy()
Helper function for compression jobs Returns true until the object is "full" and ready to be committe...
int $mDefaultKey
The key for getText()
array $mDiffs
Array of diffs.
const XDL_BDOP_INS
Constants from xdiff.h.
To speed up conversion from 1.4 to 1.5 schema, text rows can refer to the leftover cur table as the b...
setLocation( $id)
Sets the location (cur_id) of the main object to which this object points.
Pointer object for an item within a CGZ blob stored in the text table.
setLocation( $id)
Sets the location (old_id) of the main object to which this object points.
getReferrer()
Gets the location of the referring object.
static array $blobCache
One-step cache variable to hold base blobs; operations that pull multiple revisions may often pull mu...
__construct( $hash='', $oldid=0)
getHash()
Get the content hash.
setReferrer( $id)
Sets the location (old_id) of the referring object.
also included in $newHeader if any indicating whether we should show just the diff
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Base class for general text storage via the "object" flag in old_flags, or two-part external storage ...
setText( $text)
Set the "default text" This concept is an odd property of the current DB schema, whereby each text it...
getText()
Get default text.
getItem( $key)
Get item by key, or false if the key is not present.
addItem( $text)
Adds an item of text, returns a stub object which points to the item.