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 */
018package org.apache.hadoop.hdfs.client;
019
020import java.io.FileInputStream;
021import java.io.IOException;
022import java.util.Iterator;
023
024import org.apache.hadoop.hdfs.ShortCircuitShm;
025import org.apache.hadoop.hdfs.client.DfsClientShmManager.EndpointShmManager;
026import org.apache.hadoop.hdfs.net.DomainPeer;
027import org.apache.hadoop.net.unix.DomainSocket;
028import org.apache.hadoop.net.unix.DomainSocketWatcher;
029
030import com.google.common.base.Preconditions;
031
032/**
033 * DfsClientShm is a subclass of ShortCircuitShm which is used by the
034 * DfsClient.
035 * When the UNIX domain socket associated with this shared memory segment
036 * closes unexpectedly, we mark the slots inside this segment as stale.
037 * ShortCircuitReplica objects that contain stale slots are themselves stale,
038 * and will not be used to service new reads or mmap operations.
039 * However, in-progress read or mmap operations will continue to proceed.
040 * Once the last slot is deallocated, the segment can be safely munmapped.
041 */
042public class DfsClientShm extends ShortCircuitShm
043    implements DomainSocketWatcher.Handler {
044  /**
045   * The EndpointShmManager associated with this shared memory segment.
046   */
047  private final EndpointShmManager manager;
048
049  /**
050   * The UNIX domain socket associated with this DfsClientShm.
051   * We rely on the DomainSocketWatcher to close the socket associated with
052   * this DomainPeer when necessary.
053   */
054  private final DomainPeer peer;
055
056  /**
057   * True if this shared memory segment has lost its connection to the
058   * DataNode.
059   *
060   * {@link DfsClientShm#handle} sets this to true.
061   */
062  private boolean stale = false;
063
064  DfsClientShm(ShmId shmId, FileInputStream stream, EndpointShmManager manager,
065      DomainPeer peer) throws IOException {
066    super(shmId, stream);
067    this.manager = manager;
068    this.peer = peer;
069  }
070
071  public EndpointShmManager getEndpointShmManager() {
072    return manager;
073  }
074
075  public DomainPeer getPeer() {
076    return peer;
077  }
078
079  /**
080   * Determine if the shared memory segment is stale.
081   *
082   * This must be called with the DfsClientShmManager lock held.
083   *
084   * @return   True if the shared memory segment is stale.
085   */
086  public synchronized boolean isStale() {
087    return stale;
088  }
089
090  /**
091   * Handle the closure of the UNIX domain socket associated with this shared
092   * memory segment by marking this segment as stale.
093   *
094   * If there are no slots associated with this shared memory segment, it will
095   * be freed immediately in this function.
096   */
097  @Override
098  public boolean handle(DomainSocket sock) {
099    manager.unregisterShm(getShmId());
100    synchronized (this) {
101      Preconditions.checkState(!stale);
102      stale = true;
103      boolean hadSlots = false;
104      for (Iterator<Slot> iter = slotIterator(); iter.hasNext(); ) {
105        Slot slot = iter.next();
106        slot.makeInvalid();
107        hadSlots = true;
108      }
109      if (!hadSlots) {
110        free();
111      }
112    }
113    return true;
114  }
115}