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 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 */
046public 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}