[ 
https://issues.apache.org/jira/browse/FLINK-3385?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15141490#comment-15141490
 ] 

Greg Hogan commented on FLINK-3385:
-----------------------------------

Here is the simple function I was using to isolate this case, and constraining 
available memory with -Xmx200m. What is the best way to force spilling in an 
automated test?

{code}
        public void testBrokenOuterJoin() throws Exception {
                final int NUMBER_OF_ELEMENTS = 2 * 1000 * 1000;

                final ExecutionEnvironment env = 
ExecutionEnvironment.getExecutionEnvironment();
                env.setParallelism(1);

                DataSet<Long> ds1 = env
                        .fromParallelCollection(new NumberSequenceIterator(0, 
NUMBER_OF_ELEMENTS - 1), Long.class);

                DataSet<Long> ds2 = ds1
                        .filter(new FilterFunction<Long>() {
                                @Override
                                public boolean filter(Long value) throws 
Exception {
                                        return false;
                                }
                        });

                DataSet<Long> joinDs = ds1
                        .leftOuterJoin(ds2, JoinHint.REPARTITION_HASH_FIRST)
                        .where("*")
                        .equalTo("*")
                        .with(new JoinFunction<Long, Long, Long>() {
                                @Override
                                public Long join(Long first, Long second) 
throws Exception {
                                        return (first == null) ? second : first;
                                }
                        });

//              List<Long> result = joinDs
//                      .collect();
//              Collections.sort(result);

                long count = joinDs
                        .count();

                assertEquals(NUMBER_OF_ELEMENTS, count);
        }
{code}

> Fix outer join skipping unprobed partitions
> -------------------------------------------
>
>                 Key: FLINK-3385
>                 URL: https://issues.apache.org/jira/browse/FLINK-3385
>             Project: Flink
>          Issue Type: Bug
>          Components: Distributed Runtime
>            Reporter: Greg Hogan
>            Priority: Critical
>             Fix For: 1.0.0
>
>
> {{MutableHashTable.nextRecord}} performs three steps for a build-side outer 
> join:
> {code}
>       public boolean nextRecord() throws IOException {
>               if (buildSideOuterJoin) {
>                       return processProbeIter() || 
> processUnmatchedBuildIter() || prepareNextPartition();
>               } else {
>                       return processProbeIter() || prepareNextPartition();
>               }
>       }
> {code}
> {{MutableHashTable.processUnmatchedBuildIter}} eventually calls through to 
> {{MutableHashTable.moveToNextBucket}} which is unable to process spilled 
> partitions:
> {code}
>                       if (p.isInMemory()) {
>                               ...
>                       } else {
>                               return false;
>                       }
> {code}
> {{MutableHashTable.prepareNextPartition}} calls 
> {{HashPartition.finalizeProbePhase}} which only spills the partition (to be 
> read and processed in the next instantiation of {{MutableHashTable}}) if 
> probe-side records were spilled. In an equi-join this is fine but with an 
> outer join the unmatched build-side records must still be retained (though no 
> further probing is necessary, so could this be short-circuited when loaded by 
> the next {{MutableHashTable}}?).
> {code}
>               if (isInMemory()) {
>                       ...
>               }
>               else if (this.probeSideRecordCounter == 0) {
>                       // partition is empty, no spilled buffers
>                       // return the memory buffer
>                       
> freeMemory.add(this.probeSideBuffer.getCurrentSegment());
>                       // delete the spill files
>                       this.probeSideChannel.close();
>                       this.buildSideChannel.deleteChannel();
>                       this.probeSideChannel.deleteChannel();
>                       return 0;
>               }
>               else {
>                       // flush the last probe side buffer and register this 
> partition as pending
>                       this.probeSideBuffer.close();
>                       this.probeSideChannel.close();
>                       spilledPartitions.add(this);
>                       return 1;
>               }
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to