1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17.  
  18. package org.apache.spark.storage
  19.  
  20. import java.io._
  21. import java.lang.ref.{ReferenceQueue => JReferenceQueue, WeakReference}
  22. import java.nio.ByteBuffer
  23. import java.nio.channels.Channels
  24. import java.util.Collections
  25. import java.util.concurrent.ConcurrentHashMap
  26.  
  27. import scala.collection.mutable
  28. import scala.collection.mutable.HashMap
  29. import scala.concurrent.{ExecutionContext, Future}
  30. import scala.concurrent.duration._
  31. import scala.reflect.ClassTag
  32. import scala.util.Random
  33. import scala.util.control.NonFatal
  34.  
  35. import com.codahale.metrics.{MetricRegistry, MetricSet}
  36.  
  37. import org.apache.spark._
  38. import org.apache.spark.executor.{DataReadMethod, ShuffleWriteMetrics}
  39. import org.apache.spark.internal.{config, Logging}
  40. import org.apache.spark.memory.{MemoryManager, MemoryMode}
  41. import org.apache.spark.metrics.source.Source
  42. import org.apache.spark.network._
  43. import org.apache.spark.network.buffer.ManagedBuffer
  44. import org.apache.spark.network.netty.SparkTransportConf
  45. import org.apache.spark.network.shuffle.{ExternalShuffleClient, TempFileManager}
  46. import org.apache.spark.network.shuffle.protocol.ExecutorShuffleInfo
  47. import org.apache.spark.rpc.RpcEnv
  48. import org.apache.spark.serializer.{SerializerInstance, SerializerManager}
  49. import org.apache.spark.shuffle.ShuffleManager
  50. import org.apache.spark.storage.memory._
  51. import org.apache.spark.unsafe.Platform
  52. import org.apache.spark.util._
  53. import org.apache.spark.util.io.ChunkedByteBuffer
  54.  
  55. /* Class for returning a fetched block and associated metrics. */
  56. private[spark] class BlockResult(
  57. val data: Iterator[Any],
  58. val readMethod: DataReadMethod.Value,
  59. val bytes: Long)
  60.  
  61. /**
  62. * Abstracts away how blocks are stored and provides different ways to read the underlying block
  63. * data. Callers should call [[dispose()]] when they're done with the block.
  64. */
  65. private[spark] trait BlockData {
  66.  
  67. def toInputStream(): InputStream
  68.  
  69. /**
  70. * Returns a Netty-friendly wrapper for the block's data.
  71. *
  72. * Please see `ManagedBuffer.convertToNetty()` for more details.
  73. */
  74. def toNetty(): Object
  75.  
  76. def toChunkedByteBuffer(allocator: Int => ByteBuffer): ChunkedByteBuffer
  77.  
  78. def toByteBuffer(): ByteBuffer
  79.  
  80. def size: Long
  81.  
  82. def dispose(): Unit
  83.  
  84. }
  85.  
  86. private[spark] class ByteBufferBlockData(
  87. val buffer: ChunkedByteBuffer,
  88. val shouldDispose: Boolean) extends BlockData {
  89.  
  90. override def toInputStream(): InputStream = buffer.toInputStream(dispose = false)
  91.  
  92. override def toNetty(): Object = buffer.toNetty
  93.  
  94. override def toChunkedByteBuffer(allocator: Int => ByteBuffer): ChunkedByteBuffer = {
  95. buffer.copy(allocator)
  96. }
  97.  
  98. override def toByteBuffer(): ByteBuffer = buffer.toByteBuffer
  99.  
  100. override def size: Long = buffer.size
  101.  
  102. override def dispose(): Unit = {
  103. if (shouldDispose) {
  104. buffer.dispose()
  105. }
  106. }
  107.  
  108. }
  109.  
  110. /**
  111. * Manager running on every node (driver and executors) which provides interfaces for putting and
  112. * retrieving blocks both locally and remotely into various stores (memory, disk, and off-heap).
  113. *
  114. * Note that [[initialize()]] must be called before the BlockManager is usable.
  115. */
  116. private[spark] class BlockManager(
  117. executorId: String,
  118. rpcEnv: RpcEnv,
  119. val master: BlockManagerMaster,
  120. val serializerManager: SerializerManager,
  121. val conf: SparkConf,
  122. memoryManager: MemoryManager,
  123. mapOutputTracker: MapOutputTracker,
  124. shuffleManager: ShuffleManager,
  125. val blockTransferService: BlockTransferService,
  126. securityManager: SecurityManager,
  127. numUsableCores: Int)
  128. extends BlockDataManager with BlockEvictionHandler with Logging {
  129.  
  130. private[spark] val externalShuffleServiceEnabled =
  131. conf.getBoolean("spark.shuffle.service.enabled", false)
  132.  
  133. val diskBlockManager = {
  134. // Only perform cleanup if an external service is not serving our shuffle files.
  135. val deleteFilesOnStop =
  136. !externalShuffleServiceEnabled || executorId == SparkContext.DRIVER_IDENTIFIER
  137. new DiskBlockManager(conf, deleteFilesOnStop)
  138. }
  139.  
  140. // Visible for testing
  141. private[storage] val blockInfoManager = new BlockInfoManager
  142.  
  143. private val futureExecutionContext = ExecutionContext.fromExecutorService(
  144. ThreadUtils.newDaemonCachedThreadPool("block-manager-future", ))
  145.  
  146. // Actual storage of where blocks are kept
  147. private[spark] val memoryStore =
  148. new MemoryStore(conf, blockInfoManager, serializerManager, memoryManager, this)
  149. private[spark] val diskStore = new DiskStore(conf, diskBlockManager, securityManager)
  150. memoryManager.setMemoryStore(memoryStore)
  151.  
  152. // Note: depending on the memory manager, `maxMemory` may actually vary over time.
  153. // However, since we use this only for reporting and logging, what we actually want here is
  154. // the absolute maximum value that `maxMemory` can ever possibly reach. We may need
  155. // to revisit whether reporting this value as the "max" is intuitive to the user.
  156. private val maxOnHeapMemory = memoryManager.maxOnHeapStorageMemory
  157. private val maxOffHeapMemory = memoryManager.maxOffHeapStorageMemory
  158.  
  159. // Port used by the external shuffle service. In Yarn mode, this may be already be
  160. // set through the Hadoop configuration as the server is launched in the Yarn NM.
  161. private val externalShuffleServicePort = {
  162. val tmpPort = Utils.getSparkOrYarnConfig(conf, "spark.shuffle.service.port", "").toInt
  163. if (tmpPort == ) {
  164. // for testing, we set "spark.shuffle.service.port" to 0 in the yarn config, so yarn finds
  165. // an open port. But we still need to tell our spark apps the right port to use. So
  166. // only if the yarn config has the port set to 0, we prefer the value in the spark config
  167. conf.get("spark.shuffle.service.port").toInt
  168. } else {
  169. tmpPort
  170. }
  171. }
  172.  
  173. var blockManagerId: BlockManagerId = _
  174.  
  175. // Address of the server that serves this executor's shuffle files. This is either an external
  176. // service, or just our own Executor's BlockManager.
  177. private[spark] var shuffleServerId: BlockManagerId = _
  178.  
  179. // Client to read other executors' shuffle files. This is either an external service, or just the
  180. // standard BlockTransferService to directly connect to other Executors.
  181. private[spark] val shuffleClient = if (externalShuffleServiceEnabled) {
  182. val transConf = SparkTransportConf.fromSparkConf(conf, "shuffle", numUsableCores)
  183. new ExternalShuffleClient(transConf, securityManager,
  184. securityManager.isAuthenticationEnabled(), conf.get(config.SHUFFLE_REGISTRATION_TIMEOUT))
  185. } else {
  186. blockTransferService
  187. }
  188.  
  189. // Max number of failures before this block manager refreshes the block locations from the driver
  190. private val maxFailuresBeforeLocationRefresh =
  191. conf.getInt("spark.block.failures.beforeLocationRefresh", )
  192.  
  193. private val slaveEndpoint = rpcEnv.setupEndpoint(
  194. "BlockManagerEndpoint" + BlockManager.ID_GENERATOR.next,
  195. new BlockManagerSlaveEndpoint(rpcEnv, this, mapOutputTracker))
  196.  
  197. // Pending re-registration action being executed asynchronously or null if none is pending.
  198. // Accesses should synchronize on asyncReregisterLock.
  199. private var asyncReregisterTask: Future[Unit] = null
  200. private val asyncReregisterLock = new Object
  201.  
  202. // Field related to peer block managers that are necessary for block replication
  203. @volatile private var cachedPeers: Seq[BlockManagerId] = _
  204. private val peerFetchLock = new Object
  205. private var lastPeerFetchTime = 0L
  206.  
  207. private var blockReplicationPolicy: BlockReplicationPolicy = _
  208.  
  209. // A TempFileManager used to track all the files of remote blocks which above the
  210. // specified memory threshold. Files will be deleted automatically based on weak reference.
  211. // Exposed for test
  212. private[storage] val remoteBlockTempFileManager =
  213. new BlockManager.RemoteBlockTempFileManager(this)
  214. private val maxRemoteBlockToMem = conf.get(config.MAX_REMOTE_BLOCK_SIZE_FETCH_TO_MEM)
  215.  
  216. /**
  217. * Initializes the BlockManager with the given appId. This is not performed in the constructor as
  218. * the appId may not be known at BlockManager instantiation time (in particular for the driver,
  219. * where it is only learned after registration with the TaskScheduler).
  220. *
  221. * This method initializes the BlockTransferService and ShuffleClient, registers with the
  222. * BlockManagerMaster, starts the BlockManagerWorker endpoint, and registers with a local shuffle
  223. * service if configured.
  224. */
  225. def initialize(appId: String): Unit = {
  226. blockTransferService.init(this)
  227. shuffleClient.init(appId)
  228.  
  229. blockReplicationPolicy = {
  230. val priorityClass = conf.get(
  231. "spark.storage.replication.policy", classOf[RandomBlockReplicationPolicy].getName)
  232. val clazz = Utils.classForName(priorityClass)
  233. val ret = clazz.newInstance.asInstanceOf[BlockReplicationPolicy]
  234. logInfo(s"Using $priorityClass for block replication policy")
  235. ret
  236. }
  237.  
  238. val id =
  239. BlockManagerId(executorId, blockTransferService.hostName, blockTransferService.port, None)
  240.  
  241. val idFromMaster = master.registerBlockManager(
  242. id,
  243. maxOnHeapMemory,
  244. maxOffHeapMemory,
  245. slaveEndpoint)
  246.  
  247. blockManagerId = if (idFromMaster != null) idFromMaster else id
  248.  
  249. shuffleServerId = if (externalShuffleServiceEnabled) {
  250. logInfo(s"external shuffle service port = $externalShuffleServicePort")
  251. BlockManagerId(executorId, blockTransferService.hostName, externalShuffleServicePort)
  252. } else {
  253. blockManagerId
  254. }
  255.  
  256. // Register Executors' configuration with the local shuffle service, if one should exist.
  257. if (externalShuffleServiceEnabled && !blockManagerId.isDriver) {
  258. registerWithExternalShuffleServer()
  259. }
  260.  
  261. logInfo(s"Initialized BlockManager: $blockManagerId")
  262. }
  263.  
  264. def shuffleMetricsSource: Source = {
  265. import BlockManager._
  266.  
  267. if (externalShuffleServiceEnabled) {
  268. new ShuffleMetricsSource("ExternalShuffle", shuffleClient.shuffleMetrics())
  269. } else {
  270. new ShuffleMetricsSource("NettyBlockTransfer", shuffleClient.shuffleMetrics())
  271. }
  272. }
  273.  
  274. private def registerWithExternalShuffleServer() {
  275. logInfo("Registering executor with local external shuffle service.")
  276. val shuffleConfig = new ExecutorShuffleInfo(
  277. diskBlockManager.localDirs.map(_.toString),
  278. diskBlockManager.subDirsPerLocalDir,
  279. shuffleManager.getClass.getName)
  280.  
  281. val MAX_ATTEMPTS = conf.get(config.SHUFFLE_REGISTRATION_MAX_ATTEMPTS)
  282. val SLEEP_TIME_SECS =
  283.  
  284. for (i <- to MAX_ATTEMPTS) {
  285. try {
  286. // Synchronous and will throw an exception if we cannot connect.
  287. shuffleClient.asInstanceOf[ExternalShuffleClient].registerWithShuffleServer(
  288. shuffleServerId.host, shuffleServerId.port, shuffleServerId.executorId, shuffleConfig)
  289. return
  290. } catch {
  291. case e: Exception if i < MAX_ATTEMPTS =>
  292. logError(s"Failed to connect to external shuffle server, will retry ${MAX_ATTEMPTS - i}"
  293. + s" more times after waiting $SLEEP_TIME_SECS seconds...", e)
  294. Thread.sleep(SLEEP_TIME_SECS * )
  295. case NonFatal(e) =>
  296. throw new SparkException("Unable to register with external shuffle server due to : " +
  297. e.getMessage, e)
  298. }
  299. }
  300. }
  301.  
  302. /**
  303. * Report all blocks to the BlockManager again. This may be necessary if we are dropped
  304. * by the BlockManager and come back or if we become capable of recovering blocks on disk after
  305. * an executor crash.
  306. *
  307. * This function deliberately fails silently if the master returns false (indicating that
  308. * the slave needs to re-register). The error condition will be detected again by the next
  309. * heart beat attempt or new block registration and another try to re-register all blocks
  310. * will be made then.
  311. */
  312. private def reportAllBlocks(): Unit = {
  313. logInfo(s"Reporting ${blockInfoManager.size} blocks to the master.")
  314. for ((blockId, info) <- blockInfoManager.entries) {
  315. val status = getCurrentBlockStatus(blockId, info)
  316. if (info.tellMaster && !tryToReportBlockStatus(blockId, status)) {
  317. logError(s"Failed to report $blockId to master; giving up.")
  318. return
  319. }
  320. }
  321. }
  322.  
  323. /**
  324. * Re-register with the master and report all blocks to it. This will be called by the heart beat
  325. * thread if our heartbeat to the block manager indicates that we were not registered.
  326. *
  327. * Note that this method must be called without any BlockInfo locks held.
  328. */
  329. def reregister(): Unit = {
  330. // TODO: We might need to rate limit re-registering.
  331. logInfo(s"BlockManager $blockManagerId re-registering with master")
  332. master.registerBlockManager(blockManagerId, maxOnHeapMemory, maxOffHeapMemory, slaveEndpoint)
  333. reportAllBlocks()
  334. }
  335.  
  336. /**
  337. * Re-register with the master sometime soon.
  338. */
  339. private def asyncReregister(): Unit = {
  340. asyncReregisterLock.synchronized {
  341. if (asyncReregisterTask == null) {
  342. asyncReregisterTask = Future[Unit] {
  343. // This is a blocking action and should run in futureExecutionContext which is a cached
  344. // thread pool
  345. reregister()
  346. asyncReregisterLock.synchronized {
  347. asyncReregisterTask = null
  348. }
  349. }(futureExecutionContext)
  350. }
  351. }
  352. }
  353.  
  354. /**
  355. * For testing. Wait for any pending asynchronous re-registration; otherwise, do nothing.
  356. */
  357. def waitForAsyncReregister(): Unit = {
  358. val task = asyncReregisterTask
  359. if (task != null) {
  360. try {
  361. ThreadUtils.awaitReady(task, Duration.Inf)
  362. } catch {
  363. case NonFatal(t) =>
  364. throw new Exception("Error occurred while waiting for async. reregistration", t)
  365. }
  366. }
  367. }
  368.  
  369. /**
  370. * Interface to get local block data. Throws an exception if the block cannot be found or
  371. * cannot be read successfully.
  372. */
  373. override def getBlockData(blockId: BlockId): ManagedBuffer = {
  374. if (blockId.isShuffle) {
  375. shuffleManager.shuffleBlockResolver.getBlockData(blockId.asInstanceOf[ShuffleBlockId])
  376. } else {
  377. getLocalBytes(blockId) match {
  378. case Some(blockData) =>
  379. new BlockManagerManagedBuffer(blockInfoManager, blockId, blockData, true)
  380. case None =>
  381. // If this block manager receives a request for a block that it doesn't have then it's
  382. // likely that the master has outdated block statuses for this block. Therefore, we send
  383. // an RPC so that this block is marked as being unavailable from this block manager.
  384. reportBlockStatus(blockId, BlockStatus.empty)
  385. throw new BlockNotFoundException(blockId.toString)
  386. }
  387. }
  388. }
  389.  
  390. /**
  391. * Put the block locally, using the given storage level.
  392. *
  393. * '''Important!''' Callers must not mutate or release the data buffer underlying `bytes`. Doing
  394. * so may corrupt or change the data stored by the `BlockManager`.
  395. */
  396. override def putBlockData(
  397. blockId: BlockId,
  398. data: ManagedBuffer,
  399. level: StorageLevel,
  400. classTag: ClassTag[_]): Boolean = {
  401. putBytes(blockId, new ChunkedByteBuffer(data.nioByteBuffer()), level)(classTag)
  402. }
  403.  
  404. /**
  405. * Get the BlockStatus for the block identified by the given ID, if it exists.
  406. * NOTE: This is mainly for testing.
  407. */
  408. def getStatus(blockId: BlockId): Option[BlockStatus] = {
  409. blockInfoManager.get(blockId).map { info =>
  410. val memSize = if (memoryStore.contains(blockId)) memoryStore.getSize(blockId) else 0L
  411. val diskSize = if (diskStore.contains(blockId)) diskStore.getSize(blockId) else 0L
  412. BlockStatus(info.level, memSize = memSize, diskSize = diskSize)
  413. }
  414. }
  415.  
  416. /**
  417. * Get the ids of existing blocks that match the given filter. Note that this will
  418. * query the blocks stored in the disk block manager (that the block manager
  419. * may not know of).
  420. */
  421. def getMatchingBlockIds(filter: BlockId => Boolean): Seq[BlockId] = {
  422. // The `toArray` is necessary here in order to force the list to be materialized so that we
  423. // don't try to serialize a lazy iterator when responding to client requests.
  424. (blockInfoManager.entries.map(_._1) ++ diskBlockManager.getAllBlocks())
  425. .filter(filter)
  426. .toArray
  427. .toSeq
  428. }
  429.  
  430. /**
  431. * Tell the master about the current storage status of a block. This will send a block update
  432. * message reflecting the current status, *not* the desired storage level in its block info.
  433. * For example, a block with MEMORY_AND_DISK set might have fallen out to be only on disk.
  434. *
  435. * droppedMemorySize exists to account for when the block is dropped from memory to disk (so
  436. * it is still valid). This ensures that update in master will compensate for the increase in
  437. * memory on slave.
  438. */
  439. private def reportBlockStatus(
  440. blockId: BlockId,
  441. status: BlockStatus,
  442. droppedMemorySize: Long = 0L): Unit = {
  443. val needReregister = !tryToReportBlockStatus(blockId, status, droppedMemorySize)
  444. if (needReregister) {
  445. logInfo(s"Got told to re-register updating block $blockId")
  446. // Re-registering will report our new block for free.
  447. asyncReregister()
  448. }
  449. logDebug(s"Told master about block $blockId")
  450. }
  451.  
  452. /**
  453. * Actually send a UpdateBlockInfo message. Returns the master's response,
  454. * which will be true if the block was successfully recorded and false if
  455. * the slave needs to re-register.
  456. */
  457. private def tryToReportBlockStatus(
  458. blockId: BlockId,
  459. status: BlockStatus,
  460. droppedMemorySize: Long = 0L): Boolean = {
  461. val storageLevel = status.storageLevel
  462. val inMemSize = Math.max(status.memSize, droppedMemorySize)
  463. val onDiskSize = status.diskSize
  464. master.updateBlockInfo(blockManagerId, blockId, storageLevel, inMemSize, onDiskSize)
  465. }
  466.  
  467. /**
  468. * Return the updated storage status of the block with the given ID. More specifically, if
  469. * the block is dropped from memory and possibly added to disk, return the new storage level
  470. * and the updated in-memory and on-disk sizes.
  471. */
  472. private def getCurrentBlockStatus(blockId: BlockId, info: BlockInfo): BlockStatus = {
  473. info.synchronized {
  474. info.level match {
  475. case null =>
  476. BlockStatus.empty
  477. case level =>
  478. val inMem = level.useMemory && memoryStore.contains(blockId)
  479. val onDisk = level.useDisk && diskStore.contains(blockId)
  480. val deserialized = if (inMem) level.deserialized else false
  481. val replication = if (inMem || onDisk) level.replication else
  482. val storageLevel = StorageLevel(
  483. useDisk = onDisk,
  484. useMemory = inMem,
  485. useOffHeap = level.useOffHeap,
  486. deserialized = deserialized,
  487. replication = replication)
  488. val memSize = if (inMem) memoryStore.getSize(blockId) else 0L
  489. val diskSize = if (onDisk) diskStore.getSize(blockId) else 0L
  490. BlockStatus(storageLevel, memSize, diskSize)
  491. }
  492. }
  493. }
  494.  
  495. /**
  496. * Get locations of an array of blocks.
  497. */
  498. private def getLocationBlockIds(blockIds: Array[BlockId]): Array[Seq[BlockManagerId]] = {
  499. val startTimeMs = System.currentTimeMillis
  500. val locations = master.getLocations(blockIds).toArray
  501. logDebug("Got multiple block location in %s".format(Utils.getUsedTimeMs(startTimeMs)))
  502. locations
  503. }
  504.  
  505. /**
  506. * Cleanup code run in response to a failed local read.
  507. * Must be called while holding a read lock on the block.
  508. */
  509. private def handleLocalReadFailure(blockId: BlockId): Nothing = {
  510. releaseLock(blockId)
  511. // Remove the missing block so that its unavailability is reported to the driver
  512. removeBlock(blockId)
  513. throw new SparkException(s"Block $blockId was not found even though it's read-locked")
  514. }
  515.  
  516. /**
  517. * Get block from local block manager as an iterator of Java objects.
  518. */
  519. def getLocalValues(blockId: BlockId): Option[BlockResult] = {
  520. logDebug(s"Getting local block $blockId")
  521. blockInfoManager.lockForReading(blockId) match {
  522. case None =>
  523. logDebug(s"Block $blockId was not found")
  524. None
  525. case Some(info) =>
  526. val level = info.level
  527. logDebug(s"Level for block $blockId is $level")
  528. val taskAttemptId = Option(TaskContext.get()).map(_.taskAttemptId())
  529. if (level.useMemory && memoryStore.contains(blockId)) {
  530. val iter: Iterator[Any] = if (level.deserialized) {
  531. memoryStore.getValues(blockId).get
  532. } else {
  533. serializerManager.dataDeserializeStream(
  534. blockId, memoryStore.getBytes(blockId).get.toInputStream())(info.classTag)
  535. }
  536. // We need to capture the current taskId in case the iterator completion is triggered
  537. // from a different thread which does not have TaskContext set; see SPARK-18406 for
  538. // discussion.
  539. val ci = CompletionIterator[Any, Iterator[Any]](iter, {
  540. releaseLock(blockId, taskAttemptId)
  541. })
  542. Some(new BlockResult(ci, DataReadMethod.Memory, info.size))
  543. } else if (level.useDisk && diskStore.contains(blockId)) {
  544. val diskData = diskStore.getBytes(blockId)
  545. val iterToReturn: Iterator[Any] = {
  546. if (level.deserialized) {
  547. val diskValues = serializerManager.dataDeserializeStream(
  548. blockId,
  549. diskData.toInputStream())(info.classTag)
  550. maybeCacheDiskValuesInMemory(info, blockId, level, diskValues)
  551. } else {
  552. val stream = maybeCacheDiskBytesInMemory(info, blockId, level, diskData)
  553. .map { _.toInputStream(dispose = false) }
  554. .getOrElse { diskData.toInputStream() }
  555. serializerManager.dataDeserializeStream(blockId, stream)(info.classTag)
  556. }
  557. }
  558. val ci = CompletionIterator[Any, Iterator[Any]](iterToReturn, {
  559. releaseLockAndDispose(blockId, diskData, taskAttemptId)
  560. })
  561. Some(new BlockResult(ci, DataReadMethod.Disk, info.size))
  562. } else {
  563. handleLocalReadFailure(blockId)
  564. }
  565. }
  566. }
  567.  
  568. /**
  569. * Get block from the local block manager as serialized bytes.
  570. */
  571. def getLocalBytes(blockId: BlockId): Option[BlockData] = {
  572. logDebug(s"Getting local block $blockId as bytes")
  573. // As an optimization for map output fetches, if the block is for a shuffle, return it
  574. // without acquiring a lock; the disk store never deletes (recent) items so this should work
  575. if (blockId.isShuffle) {
  576. val shuffleBlockResolver = shuffleManager.shuffleBlockResolver
  577. // TODO: This should gracefully handle case where local block is not available. Currently
  578. // downstream code will throw an exception.
  579. val buf = new ChunkedByteBuffer(
  580. shuffleBlockResolver.getBlockData(blockId.asInstanceOf[ShuffleBlockId]).nioByteBuffer())
  581. Some(new ByteBufferBlockData(buf, true))
  582. } else {
  583. blockInfoManager.lockForReading(blockId).map { info => doGetLocalBytes(blockId, info) }
  584. }
  585. }
  586.  
  587. /**
  588. * Get block from the local block manager as serialized bytes.
  589. *
  590. * Must be called while holding a read lock on the block.
  591. * Releases the read lock upon exception; keeps the read lock upon successful return.
  592. */
  593. private def doGetLocalBytes(blockId: BlockId, info: BlockInfo): BlockData = {
  594. val level = info.level
  595. logDebug(s"Level for block $blockId is $level")
  596. // In order, try to read the serialized bytes from memory, then from disk, then fall back to
  597. // serializing in-memory objects, and, finally, throw an exception if the block does not exist.
  598. if (level.deserialized) {
  599. // Try to avoid expensive serialization by reading a pre-serialized copy from disk:
  600. if (level.useDisk && diskStore.contains(blockId)) {
  601. // Note: we purposely do not try to put the block back into memory here. Since this branch
  602. // handles deserialized blocks, this block may only be cached in memory as objects, not
  603. // serialized bytes. Because the caller only requested bytes, it doesn't make sense to
  604. // cache the block's deserialized objects since that caching may not have a payoff.
  605. diskStore.getBytes(blockId)
  606. } else if (level.useMemory && memoryStore.contains(blockId)) {
  607. // The block was not found on disk, so serialize an in-memory copy:
  608. new ByteBufferBlockData(serializerManager.dataSerializeWithExplicitClassTag(
  609. blockId, memoryStore.getValues(blockId).get, info.classTag), true)
  610. } else {
  611. handleLocalReadFailure(blockId)
  612. }
  613. } else { // storage level is serialized
  614. if (level.useMemory && memoryStore.contains(blockId)) {
  615. new ByteBufferBlockData(memoryStore.getBytes(blockId).get, false)
  616. } else if (level.useDisk && diskStore.contains(blockId)) {
  617. val diskData = diskStore.getBytes(blockId)
  618. maybeCacheDiskBytesInMemory(info, blockId, level, diskData)
  619. .map(new ByteBufferBlockData(_, false))
  620. .getOrElse(diskData)
  621. } else {
  622. handleLocalReadFailure(blockId)
  623. }
  624. }
  625. }
  626.  
  627. /**
  628. * Get block from remote block managers.
  629. *
  630. * This does not acquire a lock on this block in this JVM.
  631. */
  632. private def getRemoteValues[T: ClassTag](blockId: BlockId): Option[BlockResult] = {
  633. val ct = implicitly[ClassTag[T]]
  634. getRemoteBytes(blockId).map { data =>
  635. val values =
  636. serializerManager.dataDeserializeStream(blockId, data.toInputStream(dispose = true))(ct)
  637. new BlockResult(values, DataReadMethod.Network, data.size)
  638. }
  639. }
  640.  
  641. /**
  642. * Return a list of locations for the given block, prioritizing the local machine since
  643. * multiple block managers can share the same host, followed by hosts on the same rack.
  644. */
  645. private def sortLocations(locations: Seq[BlockManagerId]): Seq[BlockManagerId] = {
  646. val locs = Random.shuffle(locations)
  647. val (preferredLocs, otherLocs) = locs.partition { loc => blockManagerId.host == loc.host }
  648. blockManagerId.topologyInfo match {
  649. case None => preferredLocs ++ otherLocs
  650. case Some(_) =>
  651. val (sameRackLocs, differentRackLocs) = otherLocs.partition {
  652. loc => blockManagerId.topologyInfo == loc.topologyInfo
  653. }
  654. preferredLocs ++ sameRackLocs ++ differentRackLocs
  655. }
  656. }
  657.  
  658. /**
  659. * Get block from remote block managers as serialized bytes.
  660. */
  661. def getRemoteBytes(blockId: BlockId): Option[ChunkedByteBuffer] = {
  662. logDebug(s"Getting remote block $blockId")
  663. require(blockId != null, "BlockId is null")
  664. var runningFailureCount =
  665. var totalFailureCount =
  666.  
  667. // Because all the remote blocks are registered in driver, it is not necessary to ask
  668. // all the slave executors to get block status.
  669. val locationsAndStatus = master.getLocationsAndStatus(blockId)
  670. val blockSize = locationsAndStatus.map { b =>
  671. b.status.diskSize.max(b.status.memSize)
  672. }.getOrElse(0L)
  673. val blockLocations = locationsAndStatus.map(_.locations).getOrElse(Seq.empty)
  674.  
  675. // If the block size is above the threshold, we should pass our FileManger to
  676. // BlockTransferService, which will leverage it to spill the block; if not, then passed-in
  677. // null value means the block will be persisted in memory.
  678. val tempFileManager = if (blockSize > maxRemoteBlockToMem) {
  679. remoteBlockTempFileManager
  680. } else {
  681. null
  682. }
  683.  
  684. val locations = sortLocations(blockLocations)
  685. val maxFetchFailures = locations.size
  686. var locationIterator = locations.iterator
  687. while (locationIterator.hasNext) {
  688. val loc = locationIterator.next()
  689. logDebug(s"Getting remote block $blockId from $loc")
  690. val data = try {
  691. blockTransferService.fetchBlockSync(
  692. loc.host, loc.port, loc.executorId, blockId.toString, tempFileManager).nioByteBuffer()
  693. } catch {
  694. case NonFatal(e) =>
  695. runningFailureCount +=
  696. totalFailureCount +=
  697.  
  698. if (totalFailureCount >= maxFetchFailures) {
  699. // Give up trying anymore locations. Either we've tried all of the original locations,
  700. // or we've refreshed the list of locations from the master, and have still
  701. // hit failures after trying locations from the refreshed list.
  702. logWarning(s"Failed to fetch block after $totalFailureCount fetch failures. " +
  703. s"Most recent failure cause:", e)
  704. return None
  705. }
  706.  
  707. logWarning(s"Failed to fetch remote block $blockId " +
  708. s"from $loc (failed attempt $runningFailureCount)", e)
  709.  
  710. // If there is a large number of executors then locations list can contain a
  711. // large number of stale entries causing a large number of retries that may
  712. // take a significant amount of time. To get rid of these stale entries
  713. // we refresh the block locations after a certain number of fetch failures
  714. if (runningFailureCount >= maxFailuresBeforeLocationRefresh) {
  715. locationIterator = sortLocations(master.getLocations(blockId)).iterator
  716. logDebug(s"Refreshed locations from the driver " +
  717. s"after ${runningFailureCount} fetch failures.")
  718. runningFailureCount =
  719. }
  720.  
  721. // This location failed, so we retry fetch from a different one by returning null here
  722. null
  723. }
  724.  
  725. if (data != null) {
  726. return Some(new ChunkedByteBuffer(data))
  727. }
  728. logDebug(s"The value of block $blockId is null")
  729. }
  730. logDebug(s"Block $blockId not found")
  731. None
  732. }
  733.  
  734. /**
  735. * Get a block from the block manager (either local or remote).
  736. *
  737. * This acquires a read lock on the block if the block was stored locally and does not acquire
  738. * any locks if the block was fetched from a remote block manager. The read lock will
  739. * automatically be freed once the result's `data` iterator is fully consumed.
  740. */
  741. def get[T: ClassTag](blockId: BlockId): Option[BlockResult] = {
  742. val local = getLocalValues(blockId)
  743. if (local.isDefined) {
  744. logInfo(s"Found block $blockId locally")
  745. return local
  746. }
  747. val remote = getRemoteValues[T](blockId)
  748. if (remote.isDefined) {
  749. logInfo(s"Found block $blockId remotely")
  750. return remote
  751. }
  752. None
  753. }
  754.  
  755. /**
  756. * Downgrades an exclusive write lock to a shared read lock.
  757. */
  758. def downgradeLock(blockId: BlockId): Unit = {
  759. blockInfoManager.downgradeLock(blockId)
  760. }
  761.  
  762. /**
  763. * Release a lock on the given block with explicit TID.
  764. * The param `taskAttemptId` should be passed in case we can't get the correct TID from
  765. * TaskContext, for example, the input iterator of a cached RDD iterates to the end in a child
  766. * thread.
  767. */
  768. def releaseLock(blockId: BlockId, taskAttemptId: Option[Long] = None): Unit = {
  769. blockInfoManager.unlock(blockId, taskAttemptId)
  770. }
  771.  
  772. /**
  773. * Registers a task with the BlockManager in order to initialize per-task bookkeeping structures.
  774. */
  775. def registerTask(taskAttemptId: Long): Unit = {
  776. blockInfoManager.registerTask(taskAttemptId)
  777. }
  778.  
  779. /**
  780. * Release all locks for the given task.
  781. *
  782. * @return the blocks whose locks were released.
  783. */
  784. def releaseAllLocksForTask(taskAttemptId: Long): Seq[BlockId] = {
  785. blockInfoManager.releaseAllLocksForTask(taskAttemptId)
  786. }
  787.  
  788. /**
  789. * Retrieve the given block if it exists, otherwise call the provided `makeIterator` method
  790. * to compute the block, persist it, and return its values.
  791. *
  792. * @return either a BlockResult if the block was successfully cached, or an iterator if the block
  793. * could not be cached.
  794. */
  795. def getOrElseUpdate[T](
  796. blockId: BlockId,
  797. level: StorageLevel,
  798. classTag: ClassTag[T],
  799. makeIterator: () => Iterator[T]): Either[BlockResult, Iterator[T]] = {
  800. // Attempt to read the block from local or remote storage. If it's present, then we don't need
  801. // to go through the local-get-or-put path.
  802. get[T](blockId)(classTag) match {
  803. case Some(block) =>
  804. return Left(block)
  805. case _ =>
  806. // Need to compute the block.
  807. }
  808. // Initially we hold no locks on this block.
  809. doPutIterator(blockId, makeIterator, level, classTag, keepReadLock = true) match {
  810. case None =>
  811. // doPut() didn't hand work back to us, so the block already existed or was successfully
  812. // stored. Therefore, we now hold a read lock on the block.
  813. val blockResult = getLocalValues(blockId).getOrElse {
  814. // Since we held a read lock between the doPut() and get() calls, the block should not
  815. // have been evicted, so get() not returning the block indicates some internal error.
  816. releaseLock(blockId)
  817. throw new SparkException(s"get() failed for block $blockId even though we held a lock")
  818. }
  819. // We already hold a read lock on the block from the doPut() call and getLocalValues()
  820. // acquires the lock again, so we need to call releaseLock() here so that the net number
  821. // of lock acquisitions is 1 (since the caller will only call release() once).
  822. releaseLock(blockId)
  823. Left(blockResult)
  824. case Some(iter) =>
  825. // The put failed, likely because the data was too large to fit in memory and could not be
  826. // dropped to disk. Therefore, we need to pass the input iterator back to the caller so
  827. // that they can decide what to do with the values (e.g. process them without caching).
  828. Right(iter)
  829. }
  830. }
  831.  
  832. /**
  833. * @return true if the block was stored or false if an error occurred.
  834. */
  835. def putIterator[T: ClassTag](
  836. blockId: BlockId,
  837. values: Iterator[T],
  838. level: StorageLevel,
  839. tellMaster: Boolean = true): Boolean = {
  840. require(values != null, "Values is null")
  841. doPutIterator(blockId, () => values, level, implicitly[ClassTag[T]], tellMaster) match {
  842. case None =>
  843. true
  844. case Some(iter) =>
  845. // Caller doesn't care about the iterator values, so we can close the iterator here
  846. // to free resources earlier
  847. iter.close()
  848. false
  849. }
  850. }
  851.  
  852. /**
  853. * A short circuited method to get a block writer that can write data directly to disk.
  854. * The Block will be appended to the File specified by filename. Callers should handle error
  855. * cases.
  856. */
  857. def getDiskWriter(
  858. blockId: BlockId,
  859. file: File,
  860. serializerInstance: SerializerInstance,
  861. bufferSize: Int,
  862. writeMetrics: ShuffleWriteMetrics): DiskBlockObjectWriter = {
  863. val syncWrites = conf.getBoolean("spark.shuffle.sync", false)
  864. new DiskBlockObjectWriter(file, serializerManager, serializerInstance, bufferSize,
  865. syncWrites, writeMetrics, blockId)
  866. }
  867.  
  868. /**
  869. * Put a new block of serialized bytes to the block manager.
  870. *
  871. * '''Important!''' Callers must not mutate or release the data buffer underlying `bytes`. Doing
  872. * so may corrupt or change the data stored by the `BlockManager`.
  873. *
  874. * @return true if the block was stored or false if an error occurred.
  875. */
  876. def putBytes[T: ClassTag](
  877. blockId: BlockId,
  878. bytes: ChunkedByteBuffer,
  879. level: StorageLevel,
  880. tellMaster: Boolean = true): Boolean = {
  881. require(bytes != null, "Bytes is null")
  882. doPutBytes(blockId, bytes, level, implicitly[ClassTag[T]], tellMaster)
  883. }
  884.  
  885. /**
  886. * Put the given bytes according to the given level in one of the block stores, replicating
  887. * the values if necessary.
  888. *
  889. * If the block already exists, this method will not overwrite it.
  890. *
  891. * '''Important!''' Callers must not mutate or release the data buffer underlying `bytes`. Doing
  892. * so may corrupt or change the data stored by the `BlockManager`.
  893. *
  894. * @param keepReadLock if true, this method will hold the read lock when it returns (even if the
  895. * block already exists). If false, this method will hold no locks when it
  896. * returns.
  897. * @return true if the block was already present or if the put succeeded, false otherwise.
  898. */
  899. private def doPutBytes[T](
  900. blockId: BlockId,
  901. bytes: ChunkedByteBuffer,
  902. level: StorageLevel,
  903. classTag: ClassTag[T],
  904. tellMaster: Boolean = true,
  905. keepReadLock: Boolean = false): Boolean = {
  906. doPut(blockId, level, classTag, tellMaster = tellMaster, keepReadLock = keepReadLock) { info =>
  907. val startTimeMs = System.currentTimeMillis
  908. // Since we're storing bytes, initiate the replication before storing them locally.
  909. // This is faster as data is already serialized and ready to send.
  910. val replicationFuture = if (level.replication > ) {
  911. Future {
  912. // This is a blocking action and should run in futureExecutionContext which is a cached
  913. // thread pool. The ByteBufferBlockData wrapper is not disposed of to avoid releasing
  914. // buffers that are owned by the caller.
  915. replicate(blockId, new ByteBufferBlockData(bytes, false), level, classTag)
  916. }(futureExecutionContext)
  917. } else {
  918. null
  919. }
  920.  
  921. val size = bytes.size
  922.  
  923. if (level.useMemory) {
  924. // Put it in memory first, even if it also has useDisk set to true;
  925. // We will drop it to disk later if the memory store can't hold it.
  926. val putSucceeded = if (level.deserialized) {
  927. val values =
  928. serializerManager.dataDeserializeStream(blockId, bytes.toInputStream())(classTag)
  929. memoryStore.putIteratorAsValues(blockId, values, classTag) match {
  930. case Right(_) => true
  931. case Left(iter) =>
  932. // If putting deserialized values in memory failed, we will put the bytes directly to
  933. // disk, so we don't need this iterator and can close it to free resources earlier.
  934. iter.close()
  935. false
  936. }
  937. } else {
  938. val memoryMode = level.memoryMode
  939. memoryStore.putBytes(blockId, size, memoryMode, () => {
  940. if (memoryMode == MemoryMode.OFF_HEAP &&
  941. bytes.chunks.exists(buffer => !buffer.isDirect)) {
  942. bytes.copy(Platform.allocateDirectBuffer)
  943. } else {
  944. bytes
  945. }
  946. })
  947. }
  948. if (!putSucceeded && level.useDisk) {
  949. logWarning(s"Persisting block $blockId to disk instead.")
  950. diskStore.putBytes(blockId, bytes)
  951. }
  952. } else if (level.useDisk) {
  953. diskStore.putBytes(blockId, bytes)
  954. }
  955.  
  956. val putBlockStatus = getCurrentBlockStatus(blockId, info)
  957. val blockWasSuccessfullyStored = putBlockStatus.storageLevel.isValid
  958. if (blockWasSuccessfullyStored) {
  959. // Now that the block is in either the memory or disk store,
  960. // tell the master about it.
  961. info.size = size
  962. if (tellMaster && info.tellMaster) {
  963. reportBlockStatus(blockId, putBlockStatus)
  964. }
  965. addUpdatedBlockStatusToTaskMetrics(blockId, putBlockStatus)
  966. }
  967. logDebug("Put block %s locally took %s".format(blockId, Utils.getUsedTimeMs(startTimeMs)))
  968. if (level.replication > ) {
  969. // Wait for asynchronous replication to finish
  970. try {
  971. ThreadUtils.awaitReady(replicationFuture, Duration.Inf)
  972. } catch {
  973. case NonFatal(t) =>
  974. throw new Exception("Error occurred while waiting for replication to finish", t)
  975. }
  976. }
  977. if (blockWasSuccessfullyStored) {
  978. None
  979. } else {
  980. Some(bytes)
  981. }
  982. }.isEmpty
  983. }
  984.  
  985. /**
  986. * Helper method used to abstract common code from [[doPutBytes()]] and [[doPutIterator()]].
  987. *
  988. * @param putBody a function which attempts the actual put() and returns None on success
  989. * or Some on failure.
  990. */
  991. private def doPut[T](
  992. blockId: BlockId,
  993. level: StorageLevel,
  994. classTag: ClassTag[_],
  995. tellMaster: Boolean,
  996. keepReadLock: Boolean)(putBody: BlockInfo => Option[T]): Option[T] = {
  997.  
  998. require(blockId != null, "BlockId is null")
  999. require(level != null && level.isValid, "StorageLevel is null or invalid")
  1000.  
  1001. val putBlockInfo = {
  1002. val newInfo = new BlockInfo(level, classTag, tellMaster)
  1003. if (blockInfoManager.lockNewBlockForWriting(blockId, newInfo)) {
  1004. newInfo
  1005. } else {
  1006. logWarning(s"Block $blockId already exists on this machine; not re-adding it")
  1007. if (!keepReadLock) {
  1008. // lockNewBlockForWriting returned a read lock on the existing block, so we must free it:
  1009. releaseLock(blockId)
  1010. }
  1011. return None
  1012. }
  1013. }
  1014.  
  1015. val startTimeMs = System.currentTimeMillis
  1016. var exceptionWasThrown: Boolean = true
  1017. val result: Option[T] = try {
  1018. val res = putBody(putBlockInfo)
  1019. exceptionWasThrown = false
  1020. if (res.isEmpty) {
  1021. // the block was successfully stored
  1022. if (keepReadLock) {
  1023. blockInfoManager.downgradeLock(blockId)
  1024. } else {
  1025. blockInfoManager.unlock(blockId)
  1026. }
  1027. } else {
  1028. removeBlockInternal(blockId, tellMaster = false)
  1029. logWarning(s"Putting block $blockId failed")
  1030. }
  1031. res
  1032. } catch {
  1033. // Since removeBlockInternal may throw exception,
  1034. // we should print exception first to show root cause.
  1035. case NonFatal(e) =>
  1036. logWarning(s"Putting block $blockId failed due to exception $e.")
  1037. throw e
  1038. } finally {
  1039. // This cleanup is performed in a finally block rather than a `catch` to avoid having to
  1040. // catch and properly re-throw InterruptedException.
  1041. if (exceptionWasThrown) {
  1042. // If an exception was thrown then it's possible that the code in `putBody` has already
  1043. // notified the master about the availability of this block, so we need to send an update
  1044. // to remove this block location.
  1045. removeBlockInternal(blockId, tellMaster = tellMaster)
  1046. // The `putBody` code may have also added a new block status to TaskMetrics, so we need
  1047. // to cancel that out by overwriting it with an empty block status. We only do this if
  1048. // the finally block was entered via an exception because doing this unconditionally would
  1049. // cause us to send empty block statuses for every block that failed to be cached due to
  1050. // a memory shortage (which is an expected failure, unlike an uncaught exception).
  1051. addUpdatedBlockStatusToTaskMetrics(blockId, BlockStatus.empty)
  1052. }
  1053. }
  1054. if (level.replication > ) {
  1055. logDebug("Putting block %s with replication took %s"
  1056. .format(blockId, Utils.getUsedTimeMs(startTimeMs)))
  1057. } else {
  1058. logDebug("Putting block %s without replication took %s"
  1059. .format(blockId, Utils.getUsedTimeMs(startTimeMs)))
  1060. }
  1061. result
  1062. }
  1063.  
  1064. /**
  1065. * Put the given block according to the given level in one of the block stores, replicating
  1066. * the values if necessary.
  1067. *
  1068. * If the block already exists, this method will not overwrite it.
  1069. *
  1070. * @param keepReadLock if true, this method will hold the read lock when it returns (even if the
  1071. * block already exists). If false, this method will hold no locks when it
  1072. * returns.
  1073. * @return None if the block was already present or if the put succeeded, or Some(iterator)
  1074. * if the put failed.
  1075. */
  1076. private def doPutIterator[T](
  1077. blockId: BlockId,
  1078. iterator: () => Iterator[T],
  1079. level: StorageLevel,
  1080. classTag: ClassTag[T],
  1081. tellMaster: Boolean = true,
  1082. keepReadLock: Boolean = false): Option[PartiallyUnrolledIterator[T]] = {
  1083. doPut(blockId, level, classTag, tellMaster = tellMaster, keepReadLock = keepReadLock) { info =>
  1084. val startTimeMs = System.currentTimeMillis
  1085. var iteratorFromFailedMemoryStorePut: Option[PartiallyUnrolledIterator[T]] = None
  1086. // Size of the block in bytes
  1087. var size = 0L
  1088. if (level.useMemory) {
  1089. // Put it in memory first, even if it also has useDisk set to true;
  1090. // We will drop it to disk later if the memory store can't hold it.
  1091. if (level.deserialized) {
  1092. memoryStore.putIteratorAsValues(blockId, iterator(), classTag) match {
  1093. case Right(s) =>
  1094. size = s
  1095. case Left(iter) =>
  1096. // Not enough space to unroll this block; drop to disk if applicable
  1097. if (level.useDisk) {
  1098. logWarning(s"Persisting block $blockId to disk instead.")
  1099. diskStore.put(blockId) { channel =>
  1100. val out = Channels.newOutputStream(channel)
  1101. serializerManager.dataSerializeStream(blockId, out, iter)(classTag)
  1102. }
  1103. size = diskStore.getSize(blockId)
  1104. } else {
  1105. iteratorFromFailedMemoryStorePut = Some(iter)
  1106. }
  1107. }
  1108. } else { // !level.deserialized
  1109. memoryStore.putIteratorAsBytes(blockId, iterator(), classTag, level.memoryMode) match {
  1110. case Right(s) =>
  1111. size = s
  1112. case Left(partiallySerializedValues) =>
  1113. // Not enough space to unroll this block; drop to disk if applicable
  1114. if (level.useDisk) {
  1115. logWarning(s"Persisting block $blockId to disk instead.")
  1116. diskStore.put(blockId) { channel =>
  1117. val out = Channels.newOutputStream(channel)
  1118. partiallySerializedValues.finishWritingToStream(out)
  1119. }
  1120. size = diskStore.getSize(blockId)
  1121. } else {
  1122. iteratorFromFailedMemoryStorePut = Some(partiallySerializedValues.valuesIterator)
  1123. }
  1124. }
  1125. }
  1126.  
  1127. } else if (level.useDisk) {
  1128. diskStore.put(blockId) { channel =>
  1129. val out = Channels.newOutputStream(channel)
  1130. serializerManager.dataSerializeStream(blockId, out, iterator())(classTag)
  1131. }
  1132. size = diskStore.getSize(blockId)
  1133. }
  1134.  
  1135. val putBlockStatus = getCurrentBlockStatus(blockId, info)
  1136. val blockWasSuccessfullyStored = putBlockStatus.storageLevel.isValid
  1137. if (blockWasSuccessfullyStored) {
  1138. // Now that the block is in either the memory or disk store, tell the master about it.
  1139. info.size = size
  1140. if (tellMaster && info.tellMaster) {
  1141. reportBlockStatus(blockId, putBlockStatus)
  1142. }
  1143. addUpdatedBlockStatusToTaskMetrics(blockId, putBlockStatus)
  1144. logDebug("Put block %s locally took %s".format(blockId, Utils.getUsedTimeMs(startTimeMs)))
  1145. if (level.replication > ) {
  1146. val remoteStartTime = System.currentTimeMillis
  1147. val bytesToReplicate = doGetLocalBytes(blockId, info)
  1148. // [SPARK-16550] Erase the typed classTag when using default serialization, since
  1149. // NettyBlockRpcServer crashes when deserializing repl-defined classes.
  1150. // TODO(ekl) remove this once the classloader issue on the remote end is fixed.
  1151. val remoteClassTag = if (!serializerManager.canUseKryo(classTag)) {
  1152. scala.reflect.classTag[Any]
  1153. } else {
  1154. classTag
  1155. }
  1156. try {
  1157. replicate(blockId, bytesToReplicate, level, remoteClassTag)
  1158. } finally {
  1159. bytesToReplicate.dispose()
  1160. }
  1161. logDebug("Put block %s remotely took %s"
  1162. .format(blockId, Utils.getUsedTimeMs(remoteStartTime)))
  1163. }
  1164. }
  1165. assert(blockWasSuccessfullyStored == iteratorFromFailedMemoryStorePut.isEmpty)
  1166. iteratorFromFailedMemoryStorePut
  1167. }
  1168. }
  1169.  
  1170. /**
  1171. * Attempts to cache spilled bytes read from disk into the MemoryStore in order to speed up
  1172. * subsequent reads. This method requires the caller to hold a read lock on the block.
  1173. *
  1174. * @return a copy of the bytes from the memory store if the put succeeded, otherwise None.
  1175. * If this returns bytes from the memory store then the original disk store bytes will
  1176. * automatically be disposed and the caller should not continue to use them. Otherwise,
  1177. * if this returns None then the original disk store bytes will be unaffected.
  1178. */
  1179. private def maybeCacheDiskBytesInMemory(
  1180. blockInfo: BlockInfo,
  1181. blockId: BlockId,
  1182. level: StorageLevel,
  1183. diskData: BlockData): Option[ChunkedByteBuffer] = {
  1184. require(!level.deserialized)
  1185. if (level.useMemory) {
  1186. // Synchronize on blockInfo to guard against a race condition where two readers both try to
  1187. // put values read from disk into the MemoryStore.
  1188. blockInfo.synchronized {
  1189. if (memoryStore.contains(blockId)) {
  1190. diskData.dispose()
  1191. Some(memoryStore.getBytes(blockId).get)
  1192. } else {
  1193. val allocator = level.memoryMode match {
  1194. case MemoryMode.ON_HEAP => ByteBuffer.allocate _
  1195. case MemoryMode.OFF_HEAP => Platform.allocateDirectBuffer _
  1196. }
  1197. val putSucceeded = memoryStore.putBytes(blockId, diskData.size, level.memoryMode, () => {
  1198. // https://issues.apache.org/jira/browse/SPARK-6076
  1199. // If the file size is bigger than the free memory, OOM will happen. So if we
  1200. // cannot put it into MemoryStore, copyForMemory should not be created. That's why
  1201. // this action is put into a `() => ChunkedByteBuffer` and created lazily.
  1202. diskData.toChunkedByteBuffer(allocator)
  1203. })
  1204. if (putSucceeded) {
  1205. diskData.dispose()
  1206. Some(memoryStore.getBytes(blockId).get)
  1207. } else {
  1208. None
  1209. }
  1210. }
  1211. }
  1212. } else {
  1213. None
  1214. }
  1215. }
  1216.  
  1217. /**
  1218. * Attempts to cache spilled values read from disk into the MemoryStore in order to speed up
  1219. * subsequent reads. This method requires the caller to hold a read lock on the block.
  1220. *
  1221. * @return a copy of the iterator. The original iterator passed this method should no longer
  1222. * be used after this method returns.
  1223. */
  1224. private def maybeCacheDiskValuesInMemory[T](
  1225. blockInfo: BlockInfo,
  1226. blockId: BlockId,
  1227. level: StorageLevel,
  1228. diskIterator: Iterator[T]): Iterator[T] = {
  1229. require(level.deserialized)
  1230. val classTag = blockInfo.classTag.asInstanceOf[ClassTag[T]]
  1231. if (level.useMemory) {
  1232. // Synchronize on blockInfo to guard against a race condition where two readers both try to
  1233. // put values read from disk into the MemoryStore.
  1234. blockInfo.synchronized {
  1235. if (memoryStore.contains(blockId)) {
  1236. // Note: if we had a means to discard the disk iterator, we would do that here.
  1237. memoryStore.getValues(blockId).get
  1238. } else {
  1239. memoryStore.putIteratorAsValues(blockId, diskIterator, classTag) match {
  1240. case Left(iter) =>
  1241. // The memory store put() failed, so it returned the iterator back to us:
  1242. iter
  1243. case Right(_) =>
  1244. // The put() succeeded, so we can read the values back:
  1245. memoryStore.getValues(blockId).get
  1246. }
  1247. }
  1248. }.asInstanceOf[Iterator[T]]
  1249. } else {
  1250. diskIterator
  1251. }
  1252. }
  1253.  
  1254. /**
  1255. * Get peer block managers in the system.
  1256. */
  1257. private def getPeers(forceFetch: Boolean): Seq[BlockManagerId] = {
  1258. peerFetchLock.synchronized {
  1259. val cachedPeersTtl = conf.getInt("spark.storage.cachedPeersTtl", * ) // milliseconds
  1260. val timeout = System.currentTimeMillis - lastPeerFetchTime > cachedPeersTtl
  1261. if (cachedPeers == null || forceFetch || timeout) {
  1262. cachedPeers = master.getPeers(blockManagerId).sortBy(_.hashCode)
  1263. lastPeerFetchTime = System.currentTimeMillis
  1264. logDebug("Fetched peers from master: " + cachedPeers.mkString("[", ",", "]"))
  1265. }
  1266. cachedPeers
  1267. }
  1268. }
  1269.  
  1270. /**
  1271. * Called for pro-active replenishment of blocks lost due to executor failures
  1272. *
  1273. * @param blockId blockId being replicate
  1274. * @param existingReplicas existing block managers that have a replica
  1275. * @param maxReplicas maximum replicas needed
  1276. */
  1277. def replicateBlock(
  1278. blockId: BlockId,
  1279. existingReplicas: Set[BlockManagerId],
  1280. maxReplicas: Int): Unit = {
  1281. logInfo(s"Using $blockManagerId to pro-actively replicate $blockId")
  1282. blockInfoManager.lockForReading(blockId).foreach { info =>
  1283. val data = doGetLocalBytes(blockId, info)
  1284. val storageLevel = StorageLevel(
  1285. useDisk = info.level.useDisk,
  1286. useMemory = info.level.useMemory,
  1287. useOffHeap = info.level.useOffHeap,
  1288. deserialized = info.level.deserialized,
  1289. replication = maxReplicas)
  1290. // we know we are called as a result of an executor removal, so we refresh peer cache
  1291. // this way, we won't try to replicate to a missing executor with a stale reference
  1292. getPeers(forceFetch = true)
  1293. try {
  1294. replicate(blockId, data, storageLevel, info.classTag, existingReplicas)
  1295. } finally {
  1296. logDebug(s"Releasing lock for $blockId")
  1297. releaseLockAndDispose(blockId, data)
  1298. }
  1299. }
  1300. }
  1301.  
  1302. /**
  1303. * Replicate block to another node. Note that this is a blocking call that returns after
  1304. * the block has been replicated.
  1305. */
  1306. private def replicate(
  1307. blockId: BlockId,
  1308. data: BlockData,
  1309. level: StorageLevel,
  1310. classTag: ClassTag[_],
  1311. existingReplicas: Set[BlockManagerId] = Set.empty): Unit = {
  1312.  
  1313. val maxReplicationFailures = conf.getInt("spark.storage.maxReplicationFailures", )
  1314. val tLevel = StorageLevel(
  1315. useDisk = level.useDisk,
  1316. useMemory = level.useMemory,
  1317. useOffHeap = level.useOffHeap,
  1318. deserialized = level.deserialized,
  1319. replication = )
  1320.  
  1321. val numPeersToReplicateTo = level.replication -
  1322. val startTime = System.nanoTime
  1323.  
  1324. val peersReplicatedTo = mutable.HashSet.empty ++ existingReplicas
  1325. val peersFailedToReplicateTo = mutable.HashSet.empty[BlockManagerId]
  1326. var numFailures =
  1327.  
  1328. val initialPeers = getPeers(false).filterNot(existingReplicas.contains)
  1329.  
  1330. var peersForReplication = blockReplicationPolicy.prioritize(
  1331. blockManagerId,
  1332. initialPeers,
  1333. peersReplicatedTo,
  1334. blockId,
  1335. numPeersToReplicateTo)
  1336.  
  1337. while(numFailures <= maxReplicationFailures &&
  1338. !peersForReplication.isEmpty &&
  1339. peersReplicatedTo.size < numPeersToReplicateTo) {
  1340. val peer = peersForReplication.head
  1341. try {
  1342. val onePeerStartTime = System.nanoTime
  1343. logTrace(s"Trying to replicate $blockId of ${data.size} bytes to $peer")
  1344. blockTransferService.uploadBlockSync(
  1345. peer.host,
  1346. peer.port,
  1347. peer.executorId,
  1348. blockId,
  1349. new BlockManagerManagedBuffer(blockInfoManager, blockId, data, false),
  1350. tLevel,
  1351. classTag)
  1352. logTrace(s"Replicated $blockId of ${data.size} bytes to $peer" +
  1353. s" in ${(System.nanoTime - onePeerStartTime).toDouble / 1e6} ms")
  1354. peersForReplication = peersForReplication.tail
  1355. peersReplicatedTo += peer
  1356. } catch {
  1357. case NonFatal(e) =>
  1358. logWarning(s"Failed to replicate $blockId to $peer, failure #$numFailures", e)
  1359. peersFailedToReplicateTo += peer
  1360. // we have a failed replication, so we get the list of peers again
  1361. // we don't want peers we have already replicated to and the ones that
  1362. // have failed previously
  1363. val filteredPeers = getPeers(true).filter { p =>
  1364. !peersFailedToReplicateTo.contains(p) && !peersReplicatedTo.contains(p)
  1365. }
  1366.  
  1367. numFailures +=
  1368. peersForReplication = blockReplicationPolicy.prioritize(
  1369. blockManagerId,
  1370. filteredPeers,
  1371. peersReplicatedTo,
  1372. blockId,
  1373. numPeersToReplicateTo - peersReplicatedTo.size)
  1374. }
  1375. }
  1376. logDebug(s"Replicating $blockId of ${data.size} bytes to " +
  1377. s"${peersReplicatedTo.size} peer(s) took ${(System.nanoTime - startTime) / 1e6} ms")
  1378. if (peersReplicatedTo.size < numPeersToReplicateTo) {
  1379. logWarning(s"Block $blockId replicated to only " +
  1380. s"${peersReplicatedTo.size} peer(s) instead of $numPeersToReplicateTo peers")
  1381. }
  1382.  
  1383. logDebug(s"block $blockId replicated to ${peersReplicatedTo.mkString(", ")}")
  1384. }
  1385.  
  1386. /**
  1387. * Read a block consisting of a single object.
  1388. */
  1389. def getSingle[T: ClassTag](blockId: BlockId): Option[T] = {
  1390. get[T](blockId).map(_.data.next().asInstanceOf[T])
  1391. }
  1392.  
  1393. /**
  1394. * Write a block consisting of a single object.
  1395. *
  1396. * @return true if the block was stored or false if the block was already stored or an
  1397. * error occurred.
  1398. */
  1399. def putSingle[T: ClassTag](
  1400. blockId: BlockId,
  1401. value: T,
  1402. level: StorageLevel,
  1403. tellMaster: Boolean = true): Boolean = {
  1404. putIterator(blockId, Iterator(value), level, tellMaster)
  1405. }
  1406.  
  1407. /**
  1408. * Drop a block from memory, possibly putting it on disk if applicable. Called when the memory
  1409. * store reaches its limit and needs to free up space.
  1410. *
  1411. * If `data` is not put on disk, it won't be created.
  1412. *
  1413. * The caller of this method must hold a write lock on the block before calling this method.
  1414. * This method does not release the write lock.
  1415. *
  1416. * @return the block's new effective StorageLevel.
  1417. */
  1418. private[storage] override def dropFromMemory[T: ClassTag](
  1419. blockId: BlockId,
  1420. data: () => Either[Array[T], ChunkedByteBuffer]): StorageLevel = {
  1421. logInfo(s"Dropping block $blockId from memory")
  1422. val info = blockInfoManager.assertBlockIsLockedForWriting(blockId)
  1423. var blockIsUpdated = false
  1424. val level = info.level
  1425.  
  1426. // Drop to disk, if storage level requires
  1427. if (level.useDisk && !diskStore.contains(blockId)) {
  1428. logInfo(s"Writing block $blockId to disk")
  1429. data() match {
  1430. case Left(elements) =>
  1431. diskStore.put(blockId) { channel =>
  1432. val out = Channels.newOutputStream(channel)
  1433. serializerManager.dataSerializeStream(
  1434. blockId,
  1435. out,
  1436. elements.toIterator)(info.classTag.asInstanceOf[ClassTag[T]])
  1437. }
  1438. case Right(bytes) =>
  1439. diskStore.putBytes(blockId, bytes)
  1440. }
  1441. blockIsUpdated = true
  1442. }
  1443.  
  1444. // Actually drop from memory store
  1445. val droppedMemorySize =
  1446. if (memoryStore.contains(blockId)) memoryStore.getSize(blockId) else 0L
  1447. val blockIsRemoved = memoryStore.remove(blockId)
  1448. if (blockIsRemoved) {
  1449. blockIsUpdated = true
  1450. } else {
  1451. logWarning(s"Block $blockId could not be dropped from memory as it does not exist")
  1452. }
  1453.  
  1454. val status = getCurrentBlockStatus(blockId, info)
  1455. if (info.tellMaster) {
  1456. reportBlockStatus(blockId, status, droppedMemorySize)
  1457. }
  1458. if (blockIsUpdated) {
  1459. addUpdatedBlockStatusToTaskMetrics(blockId, status)
  1460. }
  1461. status.storageLevel
  1462. }
  1463.  
  1464. /**
  1465. * Remove all blocks belonging to the given RDD.
  1466. *
  1467. * @return The number of blocks removed.
  1468. */
  1469. def removeRdd(rddId: Int): Int = {
  1470. // TODO: Avoid a linear scan by creating another mapping of RDD.id to blocks.
  1471. logInfo(s"Removing RDD $rddId")
  1472. val blocksToRemove = blockInfoManager.entries.flatMap(_._1.asRDDId).filter(_.rddId == rddId)
  1473. blocksToRemove.foreach { blockId => removeBlock(blockId, tellMaster = false) }
  1474. blocksToRemove.size
  1475. }
  1476.  
  1477. /**
  1478. * Remove all blocks belonging to the given broadcast.
  1479. */
  1480. def removeBroadcast(broadcastId: Long, tellMaster: Boolean): Int = {
  1481. logDebug(s"Removing broadcast $broadcastId")
  1482. val blocksToRemove = blockInfoManager.entries.map(_._1).collect {
  1483. case bid @ BroadcastBlockId(`broadcastId`, _) => bid
  1484. }
  1485. blocksToRemove.foreach { blockId => removeBlock(blockId, tellMaster) }
  1486. blocksToRemove.size
  1487. }
  1488.  
  1489. /**
  1490. * Remove a block from both memory and disk.
  1491. */
  1492. def removeBlock(blockId: BlockId, tellMaster: Boolean = true): Unit = {
  1493. logDebug(s"Removing block $blockId")
  1494. blockInfoManager.lockForWriting(blockId) match {
  1495. case None =>
  1496. // The block has already been removed; do nothing.
  1497. logWarning(s"Asked to remove block $blockId, which does not exist")
  1498. case Some(info) =>
  1499. removeBlockInternal(blockId, tellMaster = tellMaster && info.tellMaster)
  1500. addUpdatedBlockStatusToTaskMetrics(blockId, BlockStatus.empty)
  1501. }
  1502. }
  1503.  
  1504. /**
  1505. * Internal version of [[removeBlock()]] which assumes that the caller already holds a write
  1506. * lock on the block.
  1507. */
  1508. private def removeBlockInternal(blockId: BlockId, tellMaster: Boolean): Unit = {
  1509. // Removals are idempotent in disk store and memory store. At worst, we get a warning.
  1510. val removedFromMemory = memoryStore.remove(blockId)
  1511. val removedFromDisk = diskStore.remove(blockId)
  1512. if (!removedFromMemory && !removedFromDisk) {
  1513. logWarning(s"Block $blockId could not be removed as it was not found on disk or in memory")
  1514. }
  1515. blockInfoManager.removeBlock(blockId)
  1516. if (tellMaster) {
  1517. reportBlockStatus(blockId, BlockStatus.empty)
  1518. }
  1519. }
  1520.  
  1521. private def addUpdatedBlockStatusToTaskMetrics(blockId: BlockId, status: BlockStatus): Unit = {
  1522. if (conf.get(config.TASK_METRICS_TRACK_UPDATED_BLOCK_STATUSES)) {
  1523. Option(TaskContext.get()).foreach { c =>
  1524. c.taskMetrics().incUpdatedBlockStatuses(blockId -> status)
  1525. }
  1526. }
  1527. }
  1528.  
  1529. def releaseLockAndDispose(
  1530. blockId: BlockId,
  1531. data: BlockData,
  1532. taskAttemptId: Option[Long] = None): Unit = {
  1533. releaseLock(blockId, taskAttemptId)
  1534. data.dispose()
  1535. }
  1536.  
  1537. def stop(): Unit = {
  1538. blockTransferService.close()
  1539. if (shuffleClient ne blockTransferService) {
  1540. // Closing should be idempotent, but maybe not for the NioBlockTransferService.
  1541. shuffleClient.close()
  1542. }
  1543. remoteBlockTempFileManager.stop()
  1544. diskBlockManager.stop()
  1545. rpcEnv.stop(slaveEndpoint)
  1546. blockInfoManager.clear()
  1547. memoryStore.clear()
  1548. futureExecutionContext.shutdownNow()
  1549. logInfo("BlockManager stopped")
  1550. }
  1551. }
  1552.  
  1553. private[spark] object BlockManager {
  1554. private val ID_GENERATOR = new IdGenerator
  1555.  
  1556. def blockIdsToHosts(
  1557. blockIds: Array[BlockId],
  1558. env: SparkEnv,
  1559. blockManagerMaster: BlockManagerMaster = null): Map[BlockId, Seq[String]] = {
  1560.  
  1561. // blockManagerMaster != null is used in tests
  1562. assert(env != null || blockManagerMaster != null)
  1563. val blockLocations: Seq[Seq[BlockManagerId]] = if (blockManagerMaster == null) {
  1564. env.blockManager.getLocationBlockIds(blockIds)
  1565. } else {
  1566. blockManagerMaster.getLocations(blockIds)
  1567. }
  1568.  
  1569. val blockManagers = new HashMap[BlockId, Seq[String]]
  1570. for (i <- until blockIds.length) {
  1571. blockManagers(blockIds(i)) = blockLocations(i).map(_.host)
  1572. }
  1573. blockManagers.toMap
  1574. }
  1575.  
  1576. private class ShuffleMetricsSource(
  1577. override val sourceName: String,
  1578. metricSet: MetricSet) extends Source {
  1579.  
  1580. override val metricRegistry = new MetricRegistry
  1581. metricRegistry.registerAll(metricSet)
  1582. }
  1583.  
  1584. class RemoteBlockTempFileManager(blockManager: BlockManager)
  1585. extends TempFileManager with Logging {
  1586.  
  1587. private class ReferenceWithCleanup(file: File, referenceQueue: JReferenceQueue[File])
  1588. extends WeakReference[File](file, referenceQueue) {
  1589. private val filePath = file.getAbsolutePath
  1590.  
  1591. def cleanUp(): Unit = {
  1592. logDebug(s"Clean up file $filePath")
  1593.  
  1594. if (!new File(filePath).delete()) {
  1595. logDebug(s"Fail to delete file $filePath")
  1596. }
  1597. }
  1598. }
  1599.  
  1600. private val referenceQueue = new JReferenceQueue[File]
  1601. private val referenceBuffer = Collections.newSetFromMap[ReferenceWithCleanup](
  1602. new ConcurrentHashMap)
  1603.  
  1604. private val POLL_TIMEOUT =
  1605. @volatile private var stopped = false
  1606.  
  1607. private val cleaningThread = new Thread() { override def run() { keepCleaning() } }
  1608. cleaningThread.setDaemon(true)
  1609. cleaningThread.setName("RemoteBlock-temp-file-clean-thread")
  1610. cleaningThread.start()
  1611.  
  1612. override def createTempFile(): File = {
  1613. blockManager.diskBlockManager.createTempLocalBlock()._2
  1614. }
  1615.  
  1616. override def registerTempFileToClean(file: File): Boolean = {
  1617. referenceBuffer.add(new ReferenceWithCleanup(file, referenceQueue))
  1618. }
  1619.  
  1620. def stop(): Unit = {
  1621. stopped = true
  1622. cleaningThread.interrupt()
  1623. cleaningThread.join()
  1624. }
  1625.  
  1626. private def keepCleaning(): Unit = {
  1627. while (!stopped) {
  1628. try {
  1629. Option(referenceQueue.remove(POLL_TIMEOUT))
  1630. .map(_.asInstanceOf[ReferenceWithCleanup])
  1631. .foreach { ref =>
  1632. referenceBuffer.remove(ref)
  1633. ref.cleanUp()
  1634. }
  1635. } catch {
  1636. case _: InterruptedException =>
  1637. // no-op
  1638. case NonFatal(e) =>
  1639. logError("Error in cleaning thread", e)
  1640. }
  1641. }
  1642. }
  1643. }
  1644. }

6.7 块管理器BlockManager的更多相关文章

  1. Spark源码剖析 - SparkContext的初始化(八)_初始化管理器BlockManager

    8.初始化管理器BlockManager 无论是Spark的初始化阶段还是任务提交.执行阶段,始终离不开存储体系.Spark为了避免Hadoop读写磁盘的I/O操作成为性能瓶颈,优先将配置信息.计算结 ...

  2. Python 上下文管理器和else块

    最终,上下文管理器可能几乎与子程序(subroutine)本身一样重要.目前,我们只了解了上下文管理器的皮毛--Basic 语言有with 语句,而且很多语言都有.但是,在各种语言中 with 语句的 ...

  3. 第15章 上下文管理器和else块

    #<流流畅的Python>第15章 上下文管理器和else块 #15.1 先做这个,再做那个:if语句之外的else块 #else子句不仅能在if语句中使用,还能在for.while和tr ...

  4. 流畅的python第十五章上下文管理器和else块学习记录

    with 语句和上下文管理器for.while 和 try 语句的 else 子句 with 语句会设置一个临时的上下文,交给上下文管理器对象控制,并且负责清理上下文.这么做能避免错误并减少样板代码, ...

  5. 上下文管理器和else块

    一.if 语句之外的 else块 else 子句不仅能在 if 语句中使用,还能在for.while和try语句中使用. (1)for :仅当 for 循环运行完毕时(即 for 循环没有被break ...

  6. spark内存管理器--MemoryManager源码解析

    MemoryManager内存管理器 内存管理器可以说是spark内核中最重要的基础模块之一,shuffle时的排序,rdd缓存,展开内存,广播变量,Task运行结果的存储等等,凡是需要使用内存的地方 ...

  7. Node.js包管理器Yarn的入门介绍与安装

    FAST, RELIABLE, AND SECURE DEPENDENCY MANAGEMENT. 就在昨天, Facebook 发布了新的 node.js 包管理器 Yarn 用以替代 npm .咱 ...

  8. python2.7高级编程 笔记一(Python中的with语句与上下文管理器学习总结)

    0.关于上下文管理器上下文管理器是可以在with语句中使用,拥有__enter__和__exit__方法的对象. with manager as var: do_something(var) 相当于以 ...

  9. [连载]《C#通讯(串口和网络)框架的设计与实现》-4.设备驱动管理器的设计

    目       录 第四章           设备驱动管理器的设计... 2 4.1           接口定义... 2 4.2           设备容器... 7 4.3          ...

随机推荐

  1. [linux] C语言Linux系统编程-socket开发

    struct sockaddr_in serv_addr; 1.定义结构体变量,结构体是一种数据类型,那么就可以用它来定义变量 2.struct 结构体名 变量名; (struct sockaddr* ...

  2. [Linux]C语言Linux系统编程创建进程

    1.进程ID 每一个进程都由一个唯一的标识符表示,即进程ID,简称pid.系统保证在某时刻每个pid都是唯一的. 1.1分配进程ID 缺省情况下,内核将进程ID的最大值限制为32768,可以在此处设置 ...

  3. GPUImage使用

    GPUImage项目下载地址:https://github.com/BradLarson/GPUImage.git 下载项目时如果下载不下来可以直接check一份(之前下载了好多次都是下载失败,最后没 ...

  4. 三、synchronized同步锁

    一.简介 在Java多线程中,我们要实现同步串行最早接触的就是synchronized关键字. 基本语法如下: synchronized(锁) { // 代码块 } sychronized关键字的锁主 ...

  5. GIT 基础-基础命令

    环境 centos7 1.安装 #yum install git 2.创建本地仓库 ( 这里用 /www/git) 这里里有个隐藏的文件夹 ```.git``` 为git仓库的配置文件夹, 不可随意修 ...

  6. python模块之numpy与pandas

    一.numpy numpy是python数据分析和机器学习的基础模块之一.它有两个作用:1.区别于list列表,提供了数组操作.数组运算.以及统计分布和简单的数学模型:2.计算速度快[甚至要由于pyt ...

  7. Fill Table Row(it’s an IQ test question)

    Here is a table include the 2 rows. And the cells in the first row have been filled with 0~4. Now yo ...

  8. HTML中的Head标签学习

    在页面加载完成的时候,标签head里的内容,是不会在页面中显示出来的.它包含了像页面的<title>(标题) ,CSS(如果你想用CSS来美化页面内容),图标和其他的元数据(比如 作者,关 ...

  9. Akka - Basis for Distributed Computing

    Some concepts as blow: Welcome to Akka, a set of open-source libraries for designing scalable, resil ...

  10. 颤振错误:当前Flutter SDK版本为2.1.0-dev.0.0.flutter-be6309690f?

    我刚刚升级了我的扑动,升级后我无法在Android Studio上运行任何扑动项目.我收到此错误消息. The current Dart SDK version -dev.0.0.flutter-be ...