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