001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.apache.hadoop.hdfs.shortcircuit;
019    
020    import java.io.FileInputStream;
021    import java.io.IOException;
022    import java.util.Iterator;
023    
024    import org.apache.hadoop.hdfs.net.DomainPeer;
025    import org.apache.hadoop.hdfs.shortcircuit.DfsClientShmManager.EndpointShmManager;
026    import org.apache.hadoop.net.unix.DomainSocket;
027    import org.apache.hadoop.net.unix.DomainSocketWatcher;
028    
029    import com.google.common.base.Preconditions;
030    
031    /**
032     * DfsClientShm is a subclass of ShortCircuitShm which is used by the
033     * DfsClient.
034     * When the UNIX domain socket associated with this shared memory segment
035     * closes unexpectedly, we mark the slots inside this segment as disconnected.
036     * ShortCircuitReplica objects that contain disconnected slots are stale,
037     * and will not be used to service new reads or mmap operations.
038     * However, in-progress read or mmap operations will continue to proceed.
039     * Once the last slot is deallocated, the segment can be safely munmapped.
040     *
041     * Slots may also become stale because the associated replica has been deleted
042     * on the DataNode.  In this case, the DataNode will clear the 'valid' bit.
043     * The client will then see these slots as stale (see
044     * #{ShortCircuitReplica#isStale}).
045     */
046    public class DfsClientShm extends ShortCircuitShm
047        implements DomainSocketWatcher.Handler {
048      /**
049       * The EndpointShmManager associated with this shared memory segment.
050       */
051      private final EndpointShmManager manager;
052    
053      /**
054       * The UNIX domain socket associated with this DfsClientShm.
055       * We rely on the DomainSocketWatcher to close the socket associated with
056       * this DomainPeer when necessary.
057       */
058      private final DomainPeer peer;
059    
060      /**
061       * True if this shared memory segment has lost its connection to the
062       * DataNode.
063       *
064       * {@link DfsClientShm#handle} sets this to true.
065       */
066      private boolean disconnected = false;
067    
068      DfsClientShm(ShmId shmId, FileInputStream stream, EndpointShmManager manager,
069          DomainPeer peer) throws IOException {
070        super(shmId, stream);
071        this.manager = manager;
072        this.peer = peer;
073      }
074    
075      public EndpointShmManager getEndpointShmManager() {
076        return manager;
077      }
078    
079      public DomainPeer getPeer() {
080        return peer;
081      }
082    
083      /**
084       * Determine if the shared memory segment is disconnected from the DataNode.
085       *
086       * This must be called with the DfsClientShmManager lock held.
087       *
088       * @return   True if the shared memory segment is stale.
089       */
090      public synchronized boolean isDisconnected() {
091        return disconnected;
092      }
093    
094      /**
095       * Handle the closure of the UNIX domain socket associated with this shared
096       * memory segment by marking this segment as stale.
097       *
098       * If there are no slots associated with this shared memory segment, it will
099       * be freed immediately in this function.
100       */
101      @Override
102      public boolean handle(DomainSocket sock) {
103        manager.unregisterShm(getShmId());
104        synchronized (this) {
105          Preconditions.checkState(!disconnected);
106          disconnected = true;
107          boolean hadSlots = false;
108          for (Iterator<Slot> iter = slotIterator(); iter.hasNext(); ) {
109            Slot slot = iter.next();
110            slot.makeInvalid();
111            hadSlots = true;
112          }
113          if (!hadSlots) {
114            free();
115          }
116        }
117        return true;
118      }
119    }