MediaWiki  1.32.0
UIDGenerator.php
Go to the documentation of this file.
1 <?php
22 use Wikimedia\Assert\Assert;
24 
30 class UIDGenerator {
32  protected static $instance = null;
34  protected $nodeIdFile;
36  protected $nodeId32;
38  protected $nodeId48;
39 
41  protected $lockFile88;
43  protected $lockFile128;
45  protected $lockFileUUID;
46 
48  protected $fileHandles = []; // cached file handles
49 
50  const QUICK_RAND = 1; // get randomness from fast and insecure sources
51  const QUICK_VOLATILE = 2; // use an APC like in-memory counter if available
52 
53  protected function __construct() {
54  $this->nodeIdFile = wfTempDir() . '/mw-' . __CLASS__ . '-UID-nodeid';
55  $nodeId = '';
56  if ( is_file( $this->nodeIdFile ) ) {
57  $nodeId = file_get_contents( $this->nodeIdFile );
58  }
59  // Try to get some ID that uniquely identifies this machine (RFC 4122)...
60  if ( !preg_match( '/^[0-9a-f]{12}$/i', $nodeId ) ) {
61  Wikimedia\suppressWarnings();
62  if ( wfIsWindows() ) {
63  // https://technet.microsoft.com/en-us/library/bb490913.aspx
64  $csv = trim( wfShellExec( 'getmac /NH /FO CSV' ) );
65  $line = substr( $csv, 0, strcspn( $csv, "\n" ) );
66  $info = str_getcsv( $line );
67  $nodeId = isset( $info[0] ) ? str_replace( '-', '', $info[0] ) : '';
68  } elseif ( is_executable( '/sbin/ifconfig' ) ) { // Linux/BSD/Solaris/OS X
69  // See https://linux.die.net/man/8/ifconfig
70  $m = [];
71  preg_match( '/\s([0-9a-f]{2}(:[0-9a-f]{2}){5})\s/',
72  wfShellExec( '/sbin/ifconfig -a' ), $m );
73  $nodeId = isset( $m[1] ) ? str_replace( ':', '', $m[1] ) : '';
74  }
75  Wikimedia\restoreWarnings();
76  if ( !preg_match( '/^[0-9a-f]{12}$/i', $nodeId ) ) {
77  $nodeId = MWCryptRand::generateHex( 12, true );
78  $nodeId[1] = dechex( hexdec( $nodeId[1] ) | 0x1 ); // set multicast bit
79  }
80  file_put_contents( $this->nodeIdFile, $nodeId ); // cache
81  }
82  $this->nodeId32 = Wikimedia\base_convert( substr( sha1( $nodeId ), 0, 8 ), 16, 2, 32 );
83  $this->nodeId48 = Wikimedia\base_convert( $nodeId, 16, 2, 48 );
84  // If different processes run as different users, they may have different temp dirs.
85  // This is dealt with by initializing the clock sequence number and counters randomly.
86  $this->lockFile88 = wfTempDir() . '/mw-' . __CLASS__ . '-UID-88';
87  $this->lockFile128 = wfTempDir() . '/mw-' . __CLASS__ . '-UID-128';
88  $this->lockFileUUID = wfTempDir() . '/mw-' . __CLASS__ . '-UUID-128';
89  }
90 
95  protected static function singleton() {
96  if ( self::$instance === null ) {
97  self::$instance = new self();
98  }
99 
100  return self::$instance;
101  }
102 
118  public static function newTimestampedUID88( $base = 10 ) {
119  Assert::parameterType( 'integer', $base, '$base' );
120  Assert::parameter( $base <= 36, '$base', 'must be <= 36' );
121  Assert::parameter( $base >= 2, '$base', 'must be >= 2' );
122 
123  $gen = self::singleton();
124  $info = $gen->getTimeAndDelay( 'lockFile88', 1, 1024, 1024 );
125  $info['offsetCounter'] = $info['offsetCounter'] % 1024;
126  return Wikimedia\base_convert( $gen->getTimestampedID88( $info ), 2, $base );
127  }
128 
135  protected function getTimestampedID88( array $info ) {
136  if ( isset( $info['time'] ) ) {
137  $time = $info['time'];
138  $counter = $info['offsetCounter'];
139  } else {
140  $time = $info[0];
141  $counter = $info[1];
142  }
143  // Take the 46 LSBs of "milliseconds since epoch"
144  $id_bin = $this->millisecondsSinceEpochBinary( $time );
145  // Add a 10 bit counter resulting in 56 bits total
146  $id_bin .= str_pad( decbin( $counter ), 10, '0', STR_PAD_LEFT );
147  // Add the 32 bit node ID resulting in 88 bits total
148  $id_bin .= $this->nodeId32;
149  // Convert to a 1-27 digit integer string
150  if ( strlen( $id_bin ) !== 88 ) {
151  throw new RuntimeException( "Detected overflow for millisecond timestamp." );
152  }
153 
154  return $id_bin;
155  }
156 
171  public static function newTimestampedUID128( $base = 10 ) {
172  Assert::parameterType( 'integer', $base, '$base' );
173  Assert::parameter( $base <= 36, '$base', 'must be <= 36' );
174  Assert::parameter( $base >= 2, '$base', 'must be >= 2' );
175 
176  $gen = self::singleton();
177  $info = $gen->getTimeAndDelay( 'lockFile128', 16384, 1048576, 1048576 );
178  $info['offsetCounter'] = $info['offsetCounter'] % 1048576;
179 
180  return Wikimedia\base_convert( $gen->getTimestampedID128( $info ), 2, $base );
181  }
182 
189  protected function getTimestampedID128( array $info ) {
190  if ( isset( $info['time'] ) ) {
191  $time = $info['time'];
192  $counter = $info['offsetCounter'];
193  $clkSeq = $info['clkSeq'];
194  } else {
195  $time = $info[0];
196  $counter = $info[1];
197  $clkSeq = $info[2];
198  }
199  // Take the 46 LSBs of "milliseconds since epoch"
200  $id_bin = $this->millisecondsSinceEpochBinary( $time );
201  // Add a 20 bit counter resulting in 66 bits total
202  $id_bin .= str_pad( decbin( $counter ), 20, '0', STR_PAD_LEFT );
203  // Add a 14 bit clock sequence number resulting in 80 bits total
204  $id_bin .= str_pad( decbin( $clkSeq ), 14, '0', STR_PAD_LEFT );
205  // Add the 48 bit node ID resulting in 128 bits total
206  $id_bin .= $this->nodeId48;
207  // Convert to a 1-39 digit integer string
208  if ( strlen( $id_bin ) !== 128 ) {
209  throw new RuntimeException( "Detected overflow for millisecond timestamp." );
210  }
211 
212  return $id_bin;
213  }
214 
222  public static function newUUIDv1() {
223  $gen = self::singleton();
224  // There can be up to 10000 intervals for the same millisecond timestamp.
225  // [0,4999] counter + [0,5000] offset is in [0,9999] for the offset counter.
226  // Add this onto the timestamp to allow making up to 5000 IDs per second.
227  return $gen->getUUIDv1( $gen->getTimeAndDelay( 'lockFileUUID', 16384, 5000, 5001 ) );
228  }
229 
237  public static function newRawUUIDv1() {
238  return str_replace( '-', '', self::newUUIDv1() );
239  }
240 
245  protected function getUUIDv1( array $info ) {
246  $clkSeq_bin = Wikimedia\base_convert( $info['clkSeq'], 10, 2, 14 );
247  $time_bin = $this->intervalsSinceGregorianBinary( $info['time'], $info['offsetCounter'] );
248  // Take the 32 bits of "time low"
249  $id_bin = substr( $time_bin, 28, 32 );
250  // Add 16 bits of "time mid" resulting in 48 bits total
251  $id_bin .= substr( $time_bin, 12, 16 );
252  // Add 4 bit version resulting in 52 bits total
253  $id_bin .= '0001';
254  // Add 12 bits of "time high" resulting in 64 bits total
255  $id_bin .= substr( $time_bin, 0, 12 );
256  // Add 2 bits of "variant" resulting in 66 bits total
257  $id_bin .= '10';
258  // Add 6 bits of "clock seq high" resulting in 72 bits total
259  $id_bin .= substr( $clkSeq_bin, 0, 6 );
260  // Add 8 bits of "clock seq low" resulting in 80 bits total
261  $id_bin .= substr( $clkSeq_bin, 6, 8 );
262  // Add the 48 bit node ID resulting in 128 bits total
263  $id_bin .= $this->nodeId48;
264  // Convert to a 32 char hex string with dashes
265  if ( strlen( $id_bin ) !== 128 ) {
266  throw new RuntimeException( "Detected overflow for millisecond timestamp." );
267  }
268  $hex = Wikimedia\base_convert( $id_bin, 2, 16, 32 );
269  return sprintf( '%s-%s-%s-%s-%s',
270  // "time_low" (32 bits)
271  substr( $hex, 0, 8 ),
272  // "time_mid" (16 bits)
273  substr( $hex, 8, 4 ),
274  // "time_hi_and_version" (16 bits)
275  substr( $hex, 12, 4 ),
276  // "clk_seq_hi_res" (8 bits) and "clk_seq_low" (8 bits)
277  substr( $hex, 16, 4 ),
278  // "node" (48 bits)
279  substr( $hex, 20, 12 )
280  );
281  }
282 
290  public static function newUUIDv4( $flags = 0 ) {
291  $hex = ( $flags & self::QUICK_RAND )
292  ? wfRandomString( 31 )
293  : MWCryptRand::generateHex( 31 );
294 
295  return sprintf( '%s-%s-%s-%s-%s',
296  // "time_low" (32 bits)
297  substr( $hex, 0, 8 ),
298  // "time_mid" (16 bits)
299  substr( $hex, 8, 4 ),
300  // "time_hi_and_version" (16 bits)
301  '4' . substr( $hex, 12, 3 ),
302  // "clk_seq_hi_res" (8 bits, variant is binary 10x) and "clk_seq_low" (8 bits)
303  dechex( 0x8 | ( hexdec( $hex[15] ) & 0x3 ) ) . $hex[16] . substr( $hex, 17, 2 ),
304  // "node" (48 bits)
305  substr( $hex, 19, 12 )
306  );
307  }
308 
316  public static function newRawUUIDv4( $flags = 0 ) {
317  return str_replace( '-', '', self::newUUIDv4( $flags ) );
318  }
319 
332  public static function newSequentialPerNodeID( $bucket, $bits = 48, $flags = 0 ) {
333  return current( self::newSequentialPerNodeIDs( $bucket, $bits, 1, $flags ) );
334  }
335 
347  public static function newSequentialPerNodeIDs( $bucket, $bits, $count, $flags = 0 ) {
348  $gen = self::singleton();
349  return $gen->getSequentialPerNodeIDs( $bucket, $bits, $count, $flags );
350  }
351 
363  protected function getSequentialPerNodeIDs( $bucket, $bits, $count, $flags ) {
364  if ( $count <= 0 ) {
365  return []; // nothing to do
366  }
367  if ( $bits < 16 || $bits > 48 ) {
368  throw new RuntimeException( "Requested bit size ($bits) is out of range." );
369  }
370 
371  $counter = null; // post-increment persistent counter value
372 
373  // Use APC/etc if requested, available, and not in CLI mode;
374  // Counter values would not survive across script instances in CLI mode.
375  $cache = null;
376  if ( ( $flags & self::QUICK_VOLATILE ) && !wfIsCLI() ) {
377  $cache = MediaWikiServices::getInstance()->getLocalServerObjectCache();
378  }
379  if ( $cache ) {
380  $counter = $cache->incrWithInit( $bucket, $cache::TTL_INDEFINITE, $count, $count );
381  if ( $counter === false ) {
382  throw new RuntimeException( 'Unable to set value to ' . get_class( $cache ) );
383  }
384  }
385 
386  // Note: use of fmod() avoids "division by zero" on 32 bit machines
387  if ( $counter === null ) {
388  $path = wfTempDir() . '/mw-' . __CLASS__ . '-' . rawurlencode( $bucket ) . '-48';
389  // Get the UID lock file handle
390  if ( isset( $this->fileHandles[$path] ) ) {
391  $handle = $this->fileHandles[$path];
392  } else {
393  $handle = fopen( $path, 'cb+' );
394  $this->fileHandles[$path] = $handle ?: null; // cache
395  }
396  // Acquire the UID lock file
397  if ( $handle === false ) {
398  throw new RuntimeException( "Could not open '{$path}'." );
399  }
400  if ( !flock( $handle, LOCK_EX ) ) {
401  fclose( $handle );
402  throw new RuntimeException( "Could not acquire '{$path}'." );
403  }
404  // Fetch the counter value and increment it...
405  rewind( $handle );
406  $counter = floor( trim( fgets( $handle ) ) ) + $count; // fetch as float
407  // Write back the new counter value
408  ftruncate( $handle, 0 );
409  rewind( $handle );
410  fwrite( $handle, fmod( $counter, 2 ** 48 ) ); // warp-around as needed
411  fflush( $handle );
412  // Release the UID lock file
413  flock( $handle, LOCK_UN );
414  }
415 
416  $ids = [];
417  $divisor = 2 ** $bits;
418  $currentId = floor( $counter - $count ); // pre-increment counter value
419  for ( $i = 0; $i < $count; ++$i ) {
420  $ids[] = fmod( ++$currentId, $divisor );
421  }
422 
423  return $ids;
424  }
425 
443  protected function getTimeAndDelay( $lockFile, $clockSeqSize, $counterSize, $offsetSize ) {
444  // Get the UID lock file handle
445  if ( isset( $this->fileHandles[$lockFile] ) ) {
446  $handle = $this->fileHandles[$lockFile];
447  } else {
448  $handle = fopen( $this->$lockFile, 'cb+' );
449  $this->fileHandles[$lockFile] = $handle ?: null; // cache
450  }
451  // Acquire the UID lock file
452  if ( $handle === false ) {
453  throw new RuntimeException( "Could not open '{$this->$lockFile}'." );
454  }
455  if ( !flock( $handle, LOCK_EX ) ) {
456  fclose( $handle );
457  throw new RuntimeException( "Could not acquire '{$this->$lockFile}'." );
458  }
459 
460  // The formatters that use this method expect a timestamp with millisecond
461  // precision and a counter upto a certain size. When more IDs than the counter
462  // size are generated during the same timestamp, an exception is thrown as we
463  // cannot increment further, because the formatted ID would not have enough
464  // bits to fit the counter.
465  //
466  // To orchestrate this between independant PHP processes on the same hosts,
467  // we must have a common sense of time so that we only have to maintain
468  // a single counter in a single lock file.
469  //
470  // Given that:
471  // * The system clock can be observed via time(), without milliseconds.
472  // * Some other clock can be observed via microtime(), which also offers
473  // millisecond precision.
474  // * microtime() drifts in-process further and further away from the system
475  // clock the longer the longer the process runs for.
476  // For example, on 2018-10-03 an HHVM 3.18 JobQueue process at WMF,
477  // that ran for 9 min 55 sec, drifted 7 seconds.
478  // The drift is immediate for processes running while the system clock changes.
479  // time() does not have this problem. See https://bugs.php.net/bug.php?id=42659.
480  //
481  // We have two choices:
482  //
483  // 1. Use microtime() with the following caveats:
484  // - The last stored time may be in the future, or our current time
485  // may be in the past, in which case we'll frequently enter the slow
486  // timeWaitUntil() method to try and "sync" the current process with
487  // the previous process. We mustn't block for long though, max 10ms?
488  // - For any drift above 10ms, we pretend that the clock went backwards,
489  // and treat it the same way as after an NTP sync, by incrementing clock
490  // sequence instead. Given this rolls over automatically and silently
491  // and is meant to be rare, this is essentially sacrifices a reasonable
492  // guarantee of uniqueness.
493  // - For long running processes (e.g. longer than a few seconds) the drift
494  // can easily be more than 2 seconds. Because we only have a single lock
495  // file and don't want to keep too many counters and deal with clearing
496  // those, we fatal the user and refuse to make an ID. (T94522)
497  // 2. Use time() and expand the counter by 1000x and use the first digits
498  // as if they are the millisecond fraction of the timestamp.
499  // Known caveats or perf impact: None.
500  //
501  // We choose the latter.
502  $msecCounterSize = $counterSize * 1000;
503 
504  rewind( $handle );
505  // Format of lock file contents:
506  // "<clk seq> <sec> <msec counter> <rand offset>"
507  $data = explode( ' ', fgets( $handle ) );
508 
509  if ( count( $data ) === 4 ) {
510  // The UID lock file was already initialized
511  $clkSeq = (int)$data[0] % $clockSeqSize;
512  $prevSec = (int)$data[1];
513  // Counter for UIDs with the same timestamp,
514  $msecCounter = 0;
515  $randOffset = (int)$data[3] % $counterSize;
516 
517  // If the system clock moved backwards by an NTP sync,
518  // or if the last writer process had its clock drift ahead,
519  // Try to catch up if the gap is small, so that we can keep a single
520  // monotonic logic file.
521  $sec = $this->timeWaitUntil( $prevSec );
522  if ( $sec === false ) {
523  // Gap is too big. Looks like the clock got moved back significantly.
524  // Start a new clock sequence, and re-randomize the extra offset,
525  // which is useful for UIDs that do not include the clock sequence number.
526  $clkSeq = ( $clkSeq + 1 ) % $clockSeqSize;
527  $sec = time();
528  $randOffset = mt_rand( 0, $offsetSize - 1 );
529  trigger_error( "Clock was set back; sequence number incremented." );
530  } elseif ( $sec === $prevSec ) {
531  // Sanity check, only keep remainder if a previous writer wrote
532  // something here that we don't accept.
533  $msecCounter = (int)$data[2] % $msecCounterSize;
534  // Bump the counter if the time has not changed yet
535  if ( ++$msecCounter >= $msecCounterSize ) {
536  // More IDs generated with the same time than counterSize can accomodate
537  flock( $handle, LOCK_UN );
538  throw new RuntimeException( "Counter overflow for timestamp value." );
539  }
540  }
541  } else {
542  // Initialize UID lock file information
543  $clkSeq = mt_rand( 0, $clockSeqSize - 1 );
544  $sec = time();
545  $msecCounter = 0;
546  $randOffset = mt_rand( 0, $offsetSize - 1 );
547  }
548 
549  // Update and release the UID lock file
550  ftruncate( $handle, 0 );
551  rewind( $handle );
552  fwrite( $handle, "{$clkSeq} {$sec} {$msecCounter} {$randOffset}" );
553  fflush( $handle );
554  flock( $handle, LOCK_UN );
555 
556  // Split msecCounter back into msec and counter
557  $msec = (int)( $msecCounter / 1000 );
558  $counter = $msecCounter % 1000;
559 
560  return [
561  'time' => [ $sec, $msec ],
562  'counter' => $counter,
563  'clkSeq' => $clkSeq,
564  'offset' => $randOffset,
565  'offsetCounter' => $counter + $randOffset,
566  ];
567  }
568 
576  protected function timeWaitUntil( $time ) {
577  $start = microtime( true );
578  do {
579  $ct = time();
580  // https://secure.php.net/manual/en/language.operators.comparison.php
581  if ( $ct >= $time ) {
582  // current time is higher than or equal to than $time
583  return $ct;
584  }
585  } while ( ( microtime( true ) - $start ) <= 0.010 ); // upto 10ms
586 
587  return false;
588  }
589 
595  protected function millisecondsSinceEpochBinary( array $time ) {
596  list( $sec, $msec ) = $time;
597  $ts = 1000 * $sec + $msec;
598  if ( $ts > 2 ** 52 ) {
599  throw new RuntimeException( __METHOD__ .
600  ': sorry, this function doesn\'t work after the year 144680' );
601  }
602 
603  return substr( Wikimedia\base_convert( $ts, 10, 2, 46 ), -46 );
604  }
605 
612  protected function intervalsSinceGregorianBinary( array $time, $delta = 0 ) {
613  list( $sec, $msec ) = $time;
614  $offset = '122192928000000000';
615  if ( PHP_INT_SIZE >= 8 ) { // 64 bit integers
616  $ts = ( 1000 * $sec + $msec ) * 10000 + (int)$offset + $delta;
617  $id_bin = str_pad( decbin( $ts % ( 2 ** 60 ) ), 60, '0', STR_PAD_LEFT );
618  } elseif ( extension_loaded( 'gmp' ) ) {
619  $ts = gmp_add( gmp_mul( (string)$sec, '1000' ), (string)$msec ); // ms
620  $ts = gmp_add( gmp_mul( $ts, '10000' ), $offset ); // 100ns intervals
621  $ts = gmp_add( $ts, (string)$delta );
622  $ts = gmp_mod( $ts, gmp_pow( '2', '60' ) ); // wrap around
623  $id_bin = str_pad( gmp_strval( $ts, 2 ), 60, '0', STR_PAD_LEFT );
624  } elseif ( extension_loaded( 'bcmath' ) ) {
625  $ts = bcadd( bcmul( $sec, 1000 ), $msec ); // ms
626  $ts = bcadd( bcmul( $ts, 10000 ), $offset ); // 100ns intervals
627  $ts = bcadd( $ts, $delta );
628  $ts = bcmod( $ts, bcpow( 2, 60 ) ); // wrap around
629  $id_bin = Wikimedia\base_convert( $ts, 10, 2, 60 );
630  } else {
631  throw new RuntimeException( 'bcmath or gmp extension required for 32 bit machines.' );
632  }
633  return $id_bin;
634  }
635 
648  private function deleteCacheFiles() {
649  // T46850
650  foreach ( $this->fileHandles as $path => $handle ) {
651  if ( $handle !== null ) {
652  fclose( $handle );
653  }
654  if ( is_file( $path ) ) {
655  unlink( $path );
656  }
657  unset( $this->fileHandles[$path] );
658  }
659  if ( is_file( $this->nodeIdFile ) ) {
660  unlink( $this->nodeIdFile );
661  }
662  }
663 
677  public static function unitTestTearDown() {
678  // T46850
679  $gen = self::singleton();
680  $gen->deleteCacheFiles();
681  }
682 
683  function __destruct() {
684  array_map( 'fclose', array_filter( $this->fileHandles ) );
685  }
686 }
UIDGenerator\newTimestampedUID128
static newTimestampedUID128( $base=10)
Get a statistically unique 128-bit unsigned integer ID string.
Definition: UIDGenerator.php:171
UIDGenerator\QUICK_RAND
const QUICK_RAND
Definition: UIDGenerator.php:50
UIDGenerator\getTimestampedID128
getTimestampedID128(array $info)
Definition: UIDGenerator.php:189
UIDGenerator\intervalsSinceGregorianBinary
intervalsSinceGregorianBinary(array $time, $delta=0)
Definition: UIDGenerator.php:612
UIDGenerator\$nodeId48
string $nodeId48
Node ID in binary (48 bits)
Definition: UIDGenerator.php:38
captcha-old.count
count
Definition: captcha-old.py:249
UIDGenerator\newUUIDv1
static newUUIDv1()
Return an RFC4122 compliant v1 UUID.
Definition: UIDGenerator.php:222
UIDGenerator
Class for getting statistically unique IDs.
Definition: UIDGenerator.php:30
$base
$base
Definition: generateLocalAutoload.php:11
UIDGenerator\getSequentialPerNodeIDs
getSequentialPerNodeIDs( $bucket, $bits, $count, $flags)
Return IDs that are sequential only for this node and bucket.
Definition: UIDGenerator.php:363
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
UIDGenerator\$lockFileUUID
string $lockFileUUID
Local file path.
Definition: UIDGenerator.php:45
UIDGenerator\newRawUUIDv4
static newRawUUIDv4( $flags=0)
Return an RFC4122 compliant v4 UUID.
Definition: UIDGenerator.php:316
UIDGenerator\newSequentialPerNodeID
static newSequentialPerNodeID( $bucket, $bits=48, $flags=0)
Return an ID that is sequential only for this node and bucket.
Definition: UIDGenerator.php:332
UIDGenerator\millisecondsSinceEpochBinary
millisecondsSinceEpochBinary(array $time)
Definition: UIDGenerator.php:595
UIDGenerator\getTimeAndDelay
getTimeAndDelay( $lockFile, $clockSeqSize, $counterSize, $offsetSize)
Get a (time,counter,clock sequence) where (time,counter) is higher than any previous (time,...
Definition: UIDGenerator.php:443
UIDGenerator\deleteCacheFiles
deleteCacheFiles()
Delete all cache files that have been created.
Definition: UIDGenerator.php:648
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
$time
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1841
array
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
UIDGenerator\$nodeId32
string $nodeId32
Node ID in binary (32 bits)
Definition: UIDGenerator.php:36
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
$line
$line
Definition: cdb.php:59
UIDGenerator\newTimestampedUID88
static newTimestampedUID88( $base=10)
Get a statistically unique 88-bit unsigned integer ID string.
Definition: UIDGenerator.php:118
UIDGenerator\newUUIDv4
static newUUIDv4( $flags=0)
Return an RFC4122 compliant v4 UUID.
Definition: UIDGenerator.php:290
wfIsCLI
wfIsCLI()
Check if we are running from the commandline.
Definition: GlobalFunctions.php:2016
UIDGenerator\unitTestTearDown
static unitTestTearDown()
Cleanup resources when tearing down after a unit test.
Definition: UIDGenerator.php:677
UIDGenerator\$nodeIdFile
string $nodeIdFile
Local file path.
Definition: UIDGenerator.php:34
wfIsWindows
wfIsWindows()
Check if the operating system is Windows.
Definition: GlobalFunctions.php:1993
UIDGenerator\$fileHandles
array $fileHandles
Cached file handles.
Definition: UIDGenerator.php:48
UIDGenerator\singleton
static singleton()
Definition: UIDGenerator.php:95
UIDGenerator\$instance
static UIDGenerator $instance
Definition: UIDGenerator.php:32
UIDGenerator\__construct
__construct()
Definition: UIDGenerator.php:53
MWCryptRand\generateHex
static generateHex( $chars)
Generate a run of cryptographically random data and return it in hexadecimal string format.
Definition: MWCryptRand.php:71
UIDGenerator\timeWaitUntil
timeWaitUntil( $time)
Wait till the current timestamp reaches $time and return the current timestamp.
Definition: UIDGenerator.php:576
UIDGenerator\getTimestampedID88
getTimestampedID88(array $info)
Definition: UIDGenerator.php:135
wfTempDir
wfTempDir()
Tries to get the system directory for temporary files.
Definition: GlobalFunctions.php:2031
$cache
$cache
Definition: mcc.php:33
UIDGenerator\newRawUUIDv1
static newRawUUIDv1()
Return an RFC4122 compliant v1 UUID.
Definition: UIDGenerator.php:237
$path
$path
Definition: NoLocalSettings.php:25
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
Wikimedia
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...
UIDGenerator\getUUIDv1
getUUIDv1(array $info)
Definition: UIDGenerator.php:245
UIDGenerator\QUICK_VOLATILE
const QUICK_VOLATILE
Definition: UIDGenerator.php:51
UIDGenerator\newSequentialPerNodeIDs
static newSequentialPerNodeIDs( $bucket, $bits, $count, $flags=0)
Return IDs that are sequential only for this node and bucket.
Definition: UIDGenerator.php:347
MediaWikiServices
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
UIDGenerator\$lockFile128
string $lockFile128
Local file path.
Definition: UIDGenerator.php:43
UIDGenerator\$lockFile88
string $lockFile88
Local file path.
Definition: UIDGenerator.php:41
UIDGenerator\__destruct
__destruct()
Definition: UIDGenerator.php:683
wfShellExec
wfShellExec( $cmd, &$retval=null, $environ=[], $limits=[], $options=[])
Execute a shell command, with time and memory limits mirrored from the PHP configuration if supported...
Definition: GlobalFunctions.php:2210
wfRandomString
wfRandomString( $length=32)
Get a random string containing a number of pseudo-random hex characters.
Definition: GlobalFunctions.php:296