Program: 110024
Project: 110024
Buggy source:
private Err doBackgroundImportYtPlaylist(final ImportYtPlaylistResult mtpr,MultiThreadRunner mtrunner,final long plid,final String ytplid,final ProgressListener progl) throws InterruptedException {
  DB db=DB.get();
  YTSearchHelper.SearchArg sarg=new YTSearchHelper.SearchArg(null,YTSearchHelper.SearchType.VID_PLAYLIST,ytplid,"String_Node_Str",1,YTSearchHelper.MAX_NR_RESULT_PER_PAGE);
  YTSearchHelper.SearchReturn sr;
  int maxPage=-1;
  int curPage=1;
  LinkedList<YTVideoFeed.Entry> plvl=new LinkedList<YTVideoFeed.Entry>();
  int lastPv=-1;
  int pvBase=0;
  int pvPortion=10;
  do {
    sarg.starti=YTSearchHelper.MAX_NR_RESULT_PER_PAGE * (curPage - 1) + 1;
    sr=YTSearchHelper.search(sarg);
    checkInterrupted();
    if (YTSearchHelper.Err.NO_ERR != sr.err)     return Err.map(sr.err);
    if (maxPage < 0) {
      int total;
      try {
        total=Integer.parseInt(sr.r.header.totalResults);
      }
 catch (      NumberFormatException e) {
        return Err.YTSEARCH;
      }
      maxPage=total / YTSearchHelper.MAX_NR_RESULT_PER_PAGE + 1;
    }
    YTVideoFeed.Entry[] ents=(YTVideoFeed.Entry[])sr.r.entries;
    for (    YTVideoFeed.Entry e : ents) {
      if (!db.containsVideo(plid,e.media.videoId))       plvl.addLast(e);
    }
    int curPv=pvBase + (curPage * 100 / maxPage) * pvPortion / 100;
    if (lastPv < curPv && null != progl) {
      lastPv=curPv;
      progl.onProgress(curPv);
    }
  }
 while (++curPage <= maxPage);
  pvBase+=pvPortion;
  pvPortion=100 - pvBase;
  Iterator<YTVideoFeed.Entry> itr=plvl.iterator();
  final int progressBase=pvBase;
  MultiThreadRunner.OnProgressListener progListener=new MultiThreadRunner.OnProgressListener(){
    @Override public void onProgress(    float prog){
      progl.onProgress((int)(progressBase + prog * 100));
    }
  }
;
  mtrunner.setOnProgressListener(progListener);
  Err err=Err.NO_ERR;
  while (itr.hasNext()) {
    final YTVideoFeed.Entry e=itr.next();
    mtrunner.appendJob(new Job<Integer>((float)pvPortion / (float)100 / plvl.size()){
      @Override public Integer doJob(){
        if (insertVideoToPlaylist(plid,e))         mtpr.nrDone.incrementAndGet();
 else         mtpr.nrIgnored.incrementAndGet();
        return 0;
      }
    }
);
  }
  mtrunner.waitAllDone();
  progl.onProgress(100);
  return err;
}

Fixed version (ground truth):
private Err doBackgroundImportYtPlaylist(final ImportYtPlaylistResult mtpr,MultiThreadRunner mtrunner,final long plid,final String ytplid,final ProgressListener progl) throws InterruptedException {
  DB db=DB.get();
  YTSearchHelper.SearchArg sarg=new YTSearchHelper.SearchArg(null,YTSearchHelper.SearchType.VID_PLAYLIST,ytplid,"String_Node_Str",1,YTSearchHelper.MAX_NR_RESULT_PER_PAGE);
  YTSearchHelper.SearchReturn sr;
  int maxPage=-1;
  int curPage=1;
  HashMap<String,YTVideoFeed.Entry> map=new HashMap<String,YTVideoFeed.Entry>();
  int lastPv=-1;
  int pvBase=0;
  int pvPortion=10;
  do {
    sarg.starti=YTSearchHelper.MAX_NR_RESULT_PER_PAGE * (curPage - 1) + 1;
    sr=YTSearchHelper.search(sarg);
    checkInterrupted();
    if (YTSearchHelper.Err.NO_ERR != sr.err)     return Err.map(sr.err);
    if (maxPage < 0) {
      int total;
      try {
        total=Integer.parseInt(sr.r.header.totalResults);
      }
 catch (      NumberFormatException e) {
        return Err.YTSEARCH;
      }
      maxPage=total / YTSearchHelper.MAX_NR_RESULT_PER_PAGE + 1;
    }
    YTVideoFeed.Entry[] ents=(YTVideoFeed.Entry[])sr.r.entries;
    for (    YTVideoFeed.Entry e : ents) {
      if (!db.containsVideo(plid,e.media.videoId))       map.put(e.media.videoId,e);
    }
    int curPv=pvBase + (curPage * 100 / maxPage) * pvPortion / 100;
    if (lastPv < curPv && null != progl) {
      lastPv=curPv;
      progl.onProgress(curPv);
    }
  }
 while (++curPage <= maxPage);
  pvBase+=pvPortion;
  pvPortion=100 - pvBase;
  final int progressBase=pvBase;
  MultiThreadRunner.OnProgressListener progListener=new MultiThreadRunner.OnProgressListener(){
    @Override public void onProgress(    float prog){
      progl.onProgress((int)(progressBase + prog * 100));
    }
  }
;
  mtrunner.setOnProgressListener(progListener);
  Err err=Err.NO_ERR;
  Map.Entry<String,YTVideoFeed.Entry>[] mes=map.entrySet().toArray(new Map.Entry[0]);
  for (  Map.Entry<String,YTVideoFeed.Entry> me : mes) {
    final YTVideoFeed.Entry e=me.getValue();
    mtrunner.appendJob(new Job<Integer>((float)pvPortion / (float)100 / mes.length){
      @Override public Integer doJob(){
        if (insertVideoToPlaylist(plid,e))         mtpr.nrDone.incrementAndGet();
 else         mtpr.nrIgnored.incrementAndGet();
        return 0;
      }
    }
);
  }
  mtrunner.waitAllDone();
  progl.onProgress(100);
  return err;
}