<commit_before>package com.be.android.library.worker.base;

import android.util.Log;
import android.util.SparseArray;

import com.be.android.library.worker.controllers.JobManager;
import com.be.android.library.worker.exceptions.JobExecutionException;
import com.be.android.library.worker.interfaces.Job;
import com.be.android.library.worker.interfaces.JobEventListener;
import com.be.android.library.worker.models.JobFutureResultStub;
import com.be.android.library.worker.models.JobId;
import com.be.android.library.worker.util.JobEventFilter;
import com.be.android.library.worker.util.JobFutureEvent;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public abstract class ForkJoinJob extends BaseJob {

    private static final String LOG_TAG = ForkJoinJob.class.getSimpleName();

    public interface ForkJoiner extends Future<JobEvent> {
        JobEvent join();
        int getJobId();
    }

    /**
     * JobFutureResult mapped to submitted job
     */
    private final SparseArray<Future<JobEvent>> mPendingResults;
    private final ReadWriteLock mLock;
    private final LinkedList<JobId> mParentJobsPath;
    private boolean shouldForwardForkEventsByDefault;

    protected ForkJoinJob() {
        this(false, (String[]) null);
    }

    protected ForkJoinJob(String... tags) {
        this(false, tags);
    }

    protected ForkJoinJob(boolean shouldForwardForkEventsByDefault) {
        this(shouldForwardForkEventsByDefault, (String[]) null);
    }

    protected ForkJoinJob(boolean shouldForwardForkEventsByDefault, String... tags) {
        super(tags);

        mPendingResults = new SparseArray<Future<JobEvent>>();
        mLock = new ReentrantReadWriteLock(false);
        mParentJobsPath = new LinkedList<JobId>();
        this.shouldForwardForkEventsByDefault = shouldForwardForkEventsByDefault;
    }

    @Override
    public void onReset() {
        mPendingResults.clear();
        mParentJobsPath.clear();
        shouldForwardForkEventsByDefault = false;
    }

    public boolean shouldForwardForkEventsByDefault() {
        return shouldForwardForkEventsByDefault;
    }

    public void setShouldForwardForkEventsByDefault(boolean shouldForwardForkEventsByDefault) {
        this.shouldForwardForkEventsByDefault = shouldForwardForkEventsByDefault;
    }

    /**
     * Set parent groups path
     * @param parents list of parent group identifiers
     */
    private void setParentJobsPath(Collection<JobId> parents) {
        mParentJobsPath.clear();
        mParentJobsPath.addAll(parents);
    }

    /**
     * Retrieve parent groups path
     */
    protected List<JobId> getParentJobsPath() {
        return Collections.unmodifiableList(mParentJobsPath);
    }

    protected JobId findParentForGroupId(int groupId) {
        final Lock lock = mLock.readLock();
        lock.lock();

        try {

            for (JobId id : mParentJobsPath) {
                if (id.getJobGroupId() == groupId) {
                    return id;
                }
            }

        } finally {
            lock.unlock();
        }

        return null;
    }

    protected ForkBuilder buildFork(ForkJoinJob job) {
        return new ForkBuilder(job);
    }

    /**
     * Similar to {@link #forkJob(ForkJoinJob)} but job will execute on specified group
     * @param jobGroupId job group to associate specified job with
     * @param job job to submit or execute
     * @return pending job result
     */
    protected ForkJoiner forkJob(int jobGroupId, ForkJoinJob job) throws JobExecutionException {
        return buildFork(job)
                .setForwardEvents(shouldForwardForkEventsByDefault())
                .groupOn(jobGroupId)
                .fork();
    }

    /**
     * Execute specified job asynchronously.
     * Job should have different group id to execute in parallel with caller job.
     * Same group id will cause job to execute immediately except
     * when {@link JobManager#JOB_GROUP_UNIQUE} or {@link JobManager#JOB_GROUP_DEDICATED} applied.
     *
     * @param forkJob job to submit or execute
     * @return pending job result
     */
    protected ForkJoiner forkJob(ForkJoinJob forkJob) throws JobExecutionException {
        return buildFork(forkJob)
                .setForwardEvents(shouldForwardForkEventsByDefault())
                .fork();
    }

    public boolean isValidForkGroup(int forkGroupId) {
        return JobManager.isSpecialJobGroup(forkGroupId)
                || JobManager.isDefaultJobGroup(forkGroupId)
                || findParentForGroupId(forkGroupId) == null;<commit_msg>Fixed job forks execution within the same group<commit_after>package com.be.android.library.worker.base;

import android.util.Log;
import android.util.SparseArray;

import com.be.android.library.worker.controllers.JobManager;
import com.be.android.library.worker.exceptions.JobExecutionException;
import com.be.android.library.worker.interfaces.Job;
import com.be.android.library.worker.interfaces.JobEventListener;
import com.be.android.library.worker.models.JobFutureResultStub;
import com.be.android.library.worker.models.JobId;
import com.be.android.library.worker.util.JobEventFilter;
import com.be.android.library.worker.util.JobFutureEvent;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public abstract class ForkJoinJob extends BaseJob {

    private static final String LOG_TAG = ForkJoinJob.class.getSimpleName();

    public interface ForkJoiner extends Future<JobEvent> {
        JobEvent join();
        int getJobId();
    }

    /**
     * JobFutureResult mapped to submitted job
     */
    private final SparseArray<Future<JobEvent>> mPendingResults;
    private final ReadWriteLock mLock;
    private final LinkedList<JobId> mParentJobsPath;
    private boolean shouldForwardForkEventsByDefault;

    protected ForkJoinJob() {
        this(false, (String[]) null);
    }

    protected ForkJoinJob(String... tags) {
        this(false, tags);
    }

    protected ForkJoinJob(boolean shouldForwardForkEventsByDefault) {
        this(shouldForwardForkEventsByDefault, (String[]) null);
    }

    protected ForkJoinJob(boolean shouldForwardForkEventsByDefault, String... tags) {
        super(tags);

        mPendingResults = new SparseArray<Future<JobEvent>>();
        mLock = new ReentrantReadWriteLock(false);
        mParentJobsPath = new LinkedList<JobId>();
        this.shouldForwardForkEventsByDefault = shouldForwardForkEventsByDefault;
    }

    @Override
    public void onReset() {
        mPendingResults.clear();
        mParentJobsPath.clear();
        shouldForwardForkEventsByDefault = false;
    }

    public boolean shouldForwardForkEventsByDefault() {
        return shouldForwardForkEventsByDefault;
    }

    public void setShouldForwardForkEventsByDefault(boolean shouldForwardForkEventsByDefault) {
        this.shouldForwardForkEventsByDefault = shouldForwardForkEventsByDefault;
    }

    /**
     * Set parent groups path
     * @param parents list of parent group identifiers
     */
    private void setParentJobsPath(Collection<JobId> parents) {
        mParentJobsPath.clear();
        mParentJobsPath.addAll(parents);
    }

    /**
     * Retrieve parent groups path
     */
    protected List<JobId> getParentJobsPath() {
        return Collections.unmodifiableList(mParentJobsPath);
    }

    protected JobId findParentForGroupId(int groupId) {
        final Lock lock = mLock.readLock();
        lock.lock();

        try {

            for (JobId id : mParentJobsPath) {
                if (id.getJobGroupId() == groupId) {
                    return id;
                }
            }

        } finally {
            lock.unlock();
        }

        return null;
    }

    protected ForkBuilder buildFork(ForkJoinJob job) {
        return new ForkBuilder(job);
    }

    /**
     * Similar to {@link #forkJob(ForkJoinJob)} but job will execute on specified group
     * @param jobGroupId job group to associate specified job with
     * @param job job to submit or execute
     * @return pending job result
     */
    protected ForkJoiner forkJob(int jobGroupId, ForkJoinJob job) throws JobExecutionException {
        return buildFork(job)
                .setForwardEvents(shouldForwardForkEventsByDefault())
                .groupOn(jobGroupId)
                .fork();
    }

    /**
     * Execute specified job asynchronously.
     * Job should have different group id to execute in parallel with caller job.
     * Same group id will cause job to execute immediately except
     * when {@link JobManager#JOB_GROUP_UNIQUE} or {@link JobManager#JOB_GROUP_DEDICATED} applied.
     *
     * @param forkJob job to submit or execute
     * @return pending job result
     */
    protected ForkJoiner forkJob(ForkJoinJob forkJob) throws JobExecutionException {
        return buildFork(forkJob)
                .setForwardEvents(shouldForwardForkEventsByDefault())
                .fork();
    }

    public boolean isValidForkGroup(int forkGroupId) {
        return forkGroupId == getGroupId()
                || JobManager.isSpecialJobGroup(forkGroupId)
                || JobManager.isDefaultJobGroup(forkGroupId)
                || findParentForGroupId(forkGroupId) == null;
{'fraction_non_alphanumeric': 0.084593339262773, 'fraction_numerical': 0.0, 'mean_word_length': 3.0905416329830233, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4443346', 'n_tokens_mistral': 2835, 'n_tokens_neox': 2754, 'n_words': 618}