/// <summary>Pull a slot out of a preexisting shared memory segment.</summary> /// <remarks> /// Pull a slot out of a preexisting shared memory segment. /// Must be called with the manager lock held. /// </remarks> /// <param name="blockId">The blockId to put inside the Slot object.</param> /// <returns> /// null if none of our shared memory segments contain a /// free slot; the slot object otherwise. /// </returns> private ShortCircuitShm.Slot AllocSlotFromExistingShm(ExtendedBlockId blockId) { if (this.notFull.IsEmpty()) { return(null); } KeyValuePair <ShortCircuitShm.ShmId, DfsClientShm> entry = this.notFull.FirstEntry (); DfsClientShm shm = entry.Value; ShortCircuitShm.ShmId shmId = shm.GetShmId(); ShortCircuitShm.Slot slot = shm.AllocAndRegisterSlot(blockId); if (shm.IsFull()) { if (DfsClientShmManager.Log.IsTraceEnabled()) { DfsClientShmManager.Log.Trace(this + ": pulled the last slot " + slot.GetSlotIdx( ) + " out of " + shm); } DfsClientShm removedShm = Sharpen.Collections.Remove(this.notFull, shmId); Preconditions.CheckState(removedShm == shm); this.full[shmId] = shm; } else { if (DfsClientShmManager.Log.IsTraceEnabled()) { DfsClientShmManager.Log.Trace(this + ": pulled slot " + slot.GetSlotIdx() + " out of " + shm); } } return(slot); }
/// <summary>Stop tracking a slot.</summary> /// <remarks> /// Stop tracking a slot. /// Must be called with the EndpointShmManager lock held. /// </remarks> /// <param name="slot">The slot to release.</param> internal virtual void FreeSlot(ShortCircuitShm.Slot slot) { DfsClientShm shm = (DfsClientShm)slot.GetShm(); shm.UnregisterSlot(slot.GetSlotIdx()); if (shm.IsDisconnected()) { // Stale shared memory segments should not be tracked here. Preconditions.CheckState(!this.full.Contains(shm.GetShmId())); Preconditions.CheckState(!this.notFull.Contains(shm.GetShmId())); if (shm.IsEmpty()) { if (DfsClientShmManager.Log.IsTraceEnabled()) { DfsClientShmManager.Log.Trace(this + ": freeing empty stale " + shm); } shm.Free(); } } else { ShortCircuitShm.ShmId shmId = shm.GetShmId(); Sharpen.Collections.Remove(this.full, shmId); // The shm can't be full if we just freed a slot. if (shm.IsEmpty()) { Sharpen.Collections.Remove(this.notFull, shmId); // If the shared memory segment is now empty, we call shutdown(2) on // the UNIX domain socket associated with it. The DomainSocketWatcher, // which is watching this socket, will call DfsClientShm#handle, // cleaning up this shared memory segment. // // See #{DfsClientShmManager#domainSocketWatcher} for details about why // we don't want to call DomainSocketWatcher#remove directly here. // // Note that we could experience 'fragmentation' here, where the // DFSClient allocates a bunch of slots in different shared memory // segments, and then frees most of them, but never fully empties out // any segment. We make some attempt to avoid this fragmentation by // always allocating new slots out of the shared memory segment with the // lowest ID, but it could still occur. In most workloads, // fragmentation should not be a major concern, since it doesn't impact // peak file descriptor usage or the speed of allocation. if (DfsClientShmManager.Log.IsTraceEnabled()) { DfsClientShmManager.Log.Trace(this + ": shutting down UNIX domain socket for " + "empty " + shm); } this.Shutdown(shm); } else { this.notFull[shmId] = shm; } } }
/// <exception cref="System.IO.IOException"/> public void Visit(Dictionary <DatanodeInfo, DfsClientShmManager.PerDatanodeVisitorInfo > info) { NUnit.Framework.Assert.IsTrue(info[datanode].full.IsEmpty()); NUnit.Framework.Assert.IsFalse(info[datanode].disabled); NUnit.Framework.Assert.AreEqual(1, info[datanode].notFull.Values.Count); DfsClientShm shm = info[datanode].notFull.Values.GetEnumerator().Next(); NUnit.Framework.Assert.IsFalse(shm.IsDisconnected()); }
internal void Shutdown(DfsClientShm shm) { try { shm.GetPeer().GetDomainSocket().Shutdown(); } catch (IOException e) { DfsClientShmManager.Log.Warn(this + ": error shutting down shm: got IOException calling " + "shutdown(SHUT_RDWR)", e); } }
public virtual void FreeSlot(ShortCircuitShm.Slot slot) { Lock.Lock(); try { DfsClientShm shm = (DfsClientShm)slot.GetShm(); shm.GetEndpointShmManager().FreeSlot(slot); } finally { Lock.Unlock(); } }
/// <exception cref="System.IO.IOException"/> public void Visit(Dictionary <DatanodeInfo, DfsClientShmManager.PerDatanodeVisitorInfo > info) { NUnit.Framework.Assert.IsTrue(info[datanode].full.IsEmpty()); NUnit.Framework.Assert.IsFalse(info[datanode].disabled); NUnit.Framework.Assert.AreEqual(1, info[datanode].notFull.Values.Count); DfsClientShm shm = info[datanode].notFull.Values.GetEnumerator().Next(); for (IEnumerator <ShortCircuitShm.Slot> iter = shm.SlotIterator(); iter.HasNext();) { ShortCircuitShm.Slot slot = iter.Next(); if (slot.IsValid()) { this._enclosing.done.SetValue(false); } } }
/// <summary>Ask the DataNode for a new shared memory segment.</summary> /// <remarks> /// Ask the DataNode for a new shared memory segment. This function must be /// called with the manager lock held. We will release the lock while /// communicating with the DataNode. /// </remarks> /// <param name="clientName">The current client name.</param> /// <param name="peer">The peer to use to talk to the DataNode.</param> /// <returns> /// Null if the DataNode does not support shared memory /// segments, or experienced an error creating the /// shm. The shared memory segment itself on success. /// </returns> /// <exception cref="System.IO.IOException"> /// If there was an error communicating over the socket. /// We will not throw an IOException unless the socket /// itself (or the network) is the problem. /// </exception> private DfsClientShm RequestNewShm(string clientName, DomainPeer peer) { DataOutputStream @out = new DataOutputStream(new BufferedOutputStream(peer.GetOutputStream ())); new Sender(@out).RequestShortCircuitShm(clientName); DataTransferProtos.ShortCircuitShmResponseProto resp = DataTransferProtos.ShortCircuitShmResponseProto .ParseFrom(PBHelper.VintPrefixed(peer.GetInputStream())); string error = resp.HasError() ? resp.GetError() : "(unknown)"; switch (resp.GetStatus()) { case DataTransferProtos.Status.Success: { DomainSocket sock = peer.GetDomainSocket(); byte[] buf = new byte[1]; FileInputStream[] fis = new FileInputStream[1]; if (sock.RecvFileInputStreams(fis, buf, 0, buf.Length) < 0) { throw new EOFException("got EOF while trying to transfer the " + "file descriptor for the shared memory segment." ); } if (fis[0] == null) { throw new IOException("the datanode " + this.datanode + " failed to " + "pass a file descriptor for the shared memory segment." ); } try { DfsClientShm shm = new DfsClientShm(PBHelper.Convert(resp.GetId()), fis[0], this, peer); if (DfsClientShmManager.Log.IsTraceEnabled()) { DfsClientShmManager.Log.Trace(this + ": createNewShm: created " + shm); } return(shm); } finally { IOUtils.Cleanup(DfsClientShmManager.Log, fis[0]); } goto case DataTransferProtos.Status.ErrorUnsupported; } case DataTransferProtos.Status.ErrorUnsupported: { // The DataNode just does not support short-circuit shared memory // access, and we should stop asking. DfsClientShmManager.Log.Info(this + ": datanode does not support short-circuit " + "shared memory access: " + error); this.disabled = true; return(null); } default: { // The datanode experienced some kind of unexpected error when trying to // create the short-circuit shared memory segment. DfsClientShmManager.Log.Warn(this + ": error requesting short-circuit shared memory " + "access: " + error); return(null); } } }