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    
019    package org.apache.hadoop.mapred.join;
020    
021    import java.io.IOException;
022    
023    import org.apache.hadoop.classification.InterfaceAudience;
024    import org.apache.hadoop.classification.InterfaceStability;
025    import org.apache.hadoop.io.Writable;
026    import org.apache.hadoop.io.WritableComparable;
027    import org.apache.hadoop.io.WritableComparator;
028    import org.apache.hadoop.io.WritableUtils;
029    import org.apache.hadoop.mapred.RecordReader;
030    
031    /**
032     * Proxy class for a RecordReader participating in the join framework.
033     * This class keeps track of the "head" key-value pair for the
034     * provided RecordReader and keeps a store of values matching a key when
035     * this source is participating in a join.
036     * @deprecated Use 
037     * {@link org.apache.hadoop.mapreduce.lib.join.WrappedRecordReader} instead
038     */
039    @Deprecated
040    @InterfaceAudience.Public
041    @InterfaceStability.Stable
042    public class WrappedRecordReader<K extends WritableComparable,
043                              U extends Writable>
044        implements ComposableRecordReader<K,U> {
045    
046      private boolean empty = false;
047      private RecordReader<K,U> rr;
048      private int id;  // index at which values will be inserted in collector
049    
050      private K khead; // key at the top of this RR
051      private U vhead; // value assoc with khead
052      private WritableComparator cmp;
053    
054      private ResetableIterator<U> vjoin;
055    
056      /**
057       * For a given RecordReader rr, occupy position id in collector.
058       */
059      WrappedRecordReader(int id, RecordReader<K,U> rr,
060          Class<? extends WritableComparator> cmpcl) throws IOException {
061        this.id = id;
062        this.rr = rr;
063        khead = rr.createKey();
064        vhead = rr.createValue();
065        try {
066          cmp = (null == cmpcl)
067            ? WritableComparator.get(khead.getClass())
068            : cmpcl.newInstance();
069        } catch (InstantiationException e) {
070          throw (IOException)new IOException().initCause(e);
071        } catch (IllegalAccessException e) {
072          throw (IOException)new IOException().initCause(e);
073        }
074        vjoin = new StreamBackedIterator<U>();
075        next();
076      }
077    
078      /** {@inheritDoc} */
079      public int id() {
080        return id;
081      }
082    
083      /**
084       * Return the key at the head of this RR.
085       */
086      public K key() {
087        return khead;
088      }
089    
090      /**
091       * Clone the key at the head of this RR into the object supplied.
092       */
093      public void key(K qkey) throws IOException {
094        WritableUtils.cloneInto(qkey, khead);
095      }
096    
097      /**
098       * Return true if the RR- including the k,v pair stored in this object-
099       * is exhausted.
100       */
101      public boolean hasNext() {
102        return !empty;
103      }
104    
105      /**
106       * Skip key-value pairs with keys less than or equal to the key provided.
107       */
108      public void skip(K key) throws IOException {
109        if (hasNext()) {
110          while (cmp.compare(khead, key) <= 0 && next());
111        }
112      }
113    
114      /**
115       * Read the next k,v pair into the head of this object; return true iff
116       * the RR and this are exhausted.
117       */
118      protected boolean next() throws IOException {
119        empty = !rr.next(khead, vhead);
120        return hasNext();
121      }
122    
123      /**
124       * Add an iterator to the collector at the position occupied by this
125       * RecordReader over the values in this stream paired with the key
126       * provided (ie register a stream of values from this source matching K
127       * with a collector).
128       */
129                                     // JoinCollector comes from parent, which has
130      @SuppressWarnings("unchecked") // no static type for the slot this sits in
131      public void accept(CompositeRecordReader.JoinCollector i, K key)
132          throws IOException {
133        vjoin.clear();
134        if (0 == cmp.compare(key, khead)) {
135          do {
136            vjoin.add(vhead);
137          } while (next() && 0 == cmp.compare(key, khead));
138        }
139        i.add(id, vjoin);
140      }
141    
142      /**
143       * Write key-value pair at the head of this stream to the objects provided;
144       * get next key-value pair from proxied RR.
145       */
146      public boolean next(K key, U value) throws IOException {
147        if (hasNext()) {
148          WritableUtils.cloneInto(key, khead);
149          WritableUtils.cloneInto(value, vhead);
150          next();
151          return true;
152        }
153        return false;
154      }
155    
156      /**
157       * Request new key from proxied RR.
158       */
159      public K createKey() {
160        return rr.createKey();
161      }
162    
163      /**
164       * Request new value from proxied RR.
165       */
166      public U createValue() {
167        return rr.createValue();
168      }
169    
170      /**
171       * Request progress from proxied RR.
172       */
173      public float getProgress() throws IOException {
174        return rr.getProgress();
175      }
176    
177      /**
178       * Request position from proxied RR.
179       */
180      public long getPos() throws IOException {
181        return rr.getPos();
182      }
183    
184      /**
185       * Forward close request to proxied RR.
186       */
187      public void close() throws IOException {
188        rr.close();
189      }
190    
191      /**
192       * Implement Comparable contract (compare key at head of proxied RR
193       * with that of another).
194       */
195      public int compareTo(ComposableRecordReader<K,?> other) {
196        return cmp.compare(key(), other.key());
197      }
198    
199      /**
200       * Return true iff compareTo(other) retn true.
201       */
202      @SuppressWarnings("unchecked") // Explicit type check prior to cast
203      public boolean equals(Object other) {
204        return other instanceof ComposableRecordReader
205            && 0 == compareTo((ComposableRecordReader)other);
206      }
207    
208      public int hashCode() {
209        assert false : "hashCode not designed";
210        return 42;
211      }
212    
213    }