View Javadoc

1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.regionserver.wal;
22  
23  import java.io.IOException;
24  
25  import org.apache.hadoop.conf.Configuration;
26  import org.apache.hadoop.fs.FSDataInputStream;
27  import org.apache.hadoop.fs.FileSystem;
28  import org.apache.hadoop.fs.Path;
29  import org.apache.hadoop.hbase.regionserver.wal.HLog;
30  import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
31  import org.apache.hadoop.io.SequenceFile;
32  
33  public class SequenceFileLogReader implements HLog.Reader {
34  
35    /**
36     * Hack just to set the correct file length up in SequenceFile.Reader.
37     * See HADOOP-6307.  The below is all about setting the right length on the
38     * file we are reading.  fs.getFileStatus(file).getLen() is passed down to
39     * a private SequenceFile.Reader constructor.  This won't work.  Need to do
40     * the available on the stream.  The below is ugly.  It makes getPos, the
41     * first time its called, return length of the file -- i.e. tell a lie -- just
42     * so this line up in SF.Reader's constructor ends up with right answer:
43     *
44     *         this.end = in.getPos() + length;
45     *
46     */
47    private static class WALReader extends SequenceFile.Reader {
48  
49      WALReader(final FileSystem fs, final Path p, final Configuration c)
50      throws IOException {
51        super(fs, p, c);
52  
53      }
54  
55      @Override
56      protected FSDataInputStream openFile(FileSystem fs, Path file,
57        int bufferSize, long length)
58      throws IOException {
59        return new WALReaderFSDataInputStream(super.openFile(fs, file,
60          bufferSize, length), length);
61      }
62  
63      /**
64       * Override just so can intercept first call to getPos.
65       */
66      static class WALReaderFSDataInputStream extends FSDataInputStream {
67        private boolean firstGetPosInvocation = true;
68        private long length;
69  
70        WALReaderFSDataInputStream(final FSDataInputStream is, final long l)
71        throws IOException {
72          super(is);
73          this.length = l;
74        }
75  
76        @Override
77        public long getPos() throws IOException {
78          if (this.firstGetPosInvocation) {
79            this.firstGetPosInvocation = false;
80            // Tell a lie.  We're doing this just so that this line up in
81            // SequenceFile.Reader constructor comes out with the correct length
82            // on the file:
83            //         this.end = in.getPos() + length;
84            long available = this.in.available();
85            // Length gets added up in the SF.Reader constructor so subtract the
86            // difference.  If available < this.length, then return this.length.
87            return available >= this.length? available - this.length: this.length;
88          }
89          return super.getPos();
90        }
91      }
92    }
93  
94    Configuration conf;
95    WALReader reader;
96  
97    public SequenceFileLogReader() { }
98  
99    @Override
100   public void init(FileSystem fs, Path path, Configuration conf)
101       throws IOException {
102     this.conf = conf;
103     reader = new WALReader(fs, path, conf);
104   }
105 
106   @Override
107   public void close() throws IOException {
108     reader.close();
109   }
110 
111   @Override
112   public HLog.Entry next() throws IOException {
113     return next(null);
114   }
115 
116   @Override
117   public HLog.Entry next(HLog.Entry reuse) throws IOException {
118     if (reuse == null) {
119       HLogKey key = HLog.newKey(conf);
120       WALEdit val = new WALEdit();
121       if (reader.next(key, val)) {
122         return new HLog.Entry(key, val);
123       }
124     } else if (reader.next(reuse.getKey(), reuse.getEdit())) {
125       return reuse;
126     }
127     return null;
128   }
129 
130   @Override
131   public void seek(long pos) throws IOException {
132     reader.seek(pos);
133   }
134 
135   @Override
136   public long getPosition() throws IOException {
137     return reader.getPosition();
138   }
139 
140 }