+ public function set( $key, $value, $exptime = 0, $flags = 0 ) {
+ if (
+ ( $flags & self::WRITE_ALLOW_SEGMENTS ) != self::WRITE_ALLOW_SEGMENTS ||
+ is_infinite( $this->segmentationSize )
+ ) {
+ return $this->doSet( $key, $value, $exptime, $flags );
+ }
+
+ $serialized = $this->serialize( $value );
+ $segmentSize = $this->getSegmentationSize();
+ $maxTotalSize = $this->getSegmentedValueMaxSize();
+
+ $size = strlen( $serialized );
+ if ( $size <= $segmentSize ) {
+ // Since the work of serializing it was already done, just use it inline
+ return $this->doSet(
+ $key,
+ SerializedValueContainer::newUnified( $serialized ),
+ $exptime,
+ $flags
+ );
+ } elseif ( $size > $maxTotalSize ) {
+ $this->setLastError( "Key $key exceeded $maxTotalSize bytes." );
+
+ return false;
+ }
+
+ $chunksByKey = [];
+ $segmentHashes = [];
+ $count = intdiv( $size, $segmentSize ) + ( ( $size % $segmentSize ) ? 1 : 0 );
+ for ( $i = 0; $i < $count; ++$i ) {
+ $segment = substr( $serialized, $i * $segmentSize, $segmentSize );
+ $hash = sha1( $segment );
+ $chunkKey = $this->makeGlobalKey( self::SEGMENT_COMPONENT, $key, $hash );
+ $chunksByKey[$chunkKey] = $segment;
+ $segmentHashes[] = $hash;
+ }
+
+ $ok = $this->setMulti( $chunksByKey, $exptime, $flags );
+ if ( $ok ) {
+ // Only when all segments are stored should the main key be changed
+ $ok = $this->doSet(
+ $key,
+ SerializedValueContainer::newSegmented( $segmentHashes ),
+ $exptime,
+ $flags
+ );
+ }
+
+ return $ok;
+ }
+
+ /**
+ * Set an item
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param int $exptime Either an interval in seconds or a unix timestamp for expiry
+ * @param int $flags Bitfield of BagOStuff::WRITE_* constants
+ * @return bool Success
+ */
+ abstract protected function doSet( $key, $value, $exptime = 0, $flags = 0 );