/*
 * Copyright 2009-2010 by The Regents of the University of California
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * you may obtain a copy of the License from
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package edu.uci.ics.hyracks.control.nc.dataset;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Executor;

import edu.uci.ics.hyracks.api.comm.IFrameWriter;
import edu.uci.ics.hyracks.api.context.IHyracksTaskContext;
import edu.uci.ics.hyracks.api.dataset.IDatasetPartitionManager;
import edu.uci.ics.hyracks.api.dataset.IDatasetPartitionReader;
import edu.uci.ics.hyracks.api.dataset.ResultSetId;
import edu.uci.ics.hyracks.api.exceptions.HyracksException;
import edu.uci.ics.hyracks.api.io.IWorkspaceFileFactory;
import edu.uci.ics.hyracks.api.job.JobId;
import edu.uci.ics.hyracks.control.nc.NodeControllerService;
import edu.uci.ics.hyracks.control.nc.io.IOManager;
import edu.uci.ics.hyracks.control.nc.io.WorkspaceFileFactory;
import edu.uci.ics.hyracks.control.nc.resources.DefaultDeallocatableRegistry;

public class DatasetPartitionManager implements IDatasetPartitionManager {
    private final NodeControllerService ncs;

    private final Executor executor;

    private final Map<JobId, ResultState[]> partitionResultStateMap;

    private final DefaultDeallocatableRegistry deallocatableRegistry;

    private final IWorkspaceFileFactory fileFactory;

    private final DatasetMemoryManager datasetMemoryManager;

    public DatasetPartitionManager(NodeControllerService ncs, Executor executor, int availableMemory,
            final int resultHistorySize) {
        this.ncs = ncs;
        this.executor = executor;
        deallocatableRegistry = new DefaultDeallocatableRegistry();
        fileFactory = new WorkspaceFileFactory(deallocatableRegistry, (IOManager) ncs.getRootContext().getIOManager());
        datasetMemoryManager = new DatasetMemoryManager(availableMemory);
        partitionResultStateMap = new LinkedHashMap<JobId, ResultState[]>() {
            private static final long serialVersionUID = 1L;

            protected boolean removeEldestEntry(Map.Entry<JobId, ResultState[]> eldest) {
                if (size() > resultHistorySize) {
                    for (ResultState state : eldest.getValue()) {
                        state.deinit();
                    }
                    return true;
                }
                return false;
            }
        };
    }

    @Override
    public IFrameWriter createDatasetPartitionWriter(IHyracksTaskContext ctx, ResultSetId rsId, boolean orderedResult,
            int partition, int nPartitions) throws HyracksException {
        DatasetPartitionWriter dpw = null;
        JobId jobId = ctx.getJobletContext().getJobId();
        try {
            ncs.getClusterController().registerResultPartitionLocation(jobId, rsId, orderedResult, partition,
                    nPartitions, ncs.getDatasetNetworkManager().getNetworkAddress());
            dpw = new DatasetPartitionWriter(ctx, this, jobId, rsId, partition, datasetMemoryManager);

            ResultState[] resultStates = partitionResultStateMap.get(jobId);
            if (resultStates == null) {
                resultStates = new ResultState[nPartitions];
                partitionResultStateMap.put(jobId, resultStates);
            }
            resultStates[partition] = dpw.getResultState();
        } catch (Exception e) {
            throw new HyracksException(e);
        }

        return dpw;
    }

    @Override
    public void reportPartitionWriteCompletion(JobId jobId, ResultSetId rsId, int partition) throws HyracksException {
        try {
            ncs.getClusterController().reportResultPartitionWriteCompletion(jobId, rsId, partition);
        } catch (Exception e) {
            throw new HyracksException(e);
        }
    }

    @Override
    public void reportPartitionFailure(JobId jobId, ResultSetId rsId, int partition) throws HyracksException {
        try {
            ncs.getClusterController().reportResultPartitionFailure(jobId, rsId, partition);
        } catch (Exception e) {
            throw new HyracksException(e);
        }
    }

    @Override
    public void initializeDatasetPartitionReader(JobId jobId, int partition, IFrameWriter writer)
            throws HyracksException {
        ResultState[] resultStates = partitionResultStateMap.get(jobId);

        if (resultStates == null) {
            throw new HyracksException("Unknown JobId " + jobId);
        }

        ResultState resultState = resultStates[partition];
        if (resultState == null) {
            throw new HyracksException("No DatasetPartitionWriter for partition " + partition);
        }

        IDatasetPartitionReader dpr = new DatasetPartitionReader(datasetMemoryManager, executor, resultState);
        dpr.writeTo(writer);
    }

    @Override
    public IWorkspaceFileFactory getFileFactory() {
        return fileFactory;
    }

    @Override
    public void close() {
        deallocatableRegistry.close();
    }
}

@@ -3187,32 +3187,89 @@
 ;%0A        try %7B%0A
+            synchronized (partitionResultStateMap) %7B%0A    
             ncs.
@@ -3382,16 +3382,20 @@
         
+    
 nPartiti
@@ -3448,24 +3448,28 @@
 Address());%0A
+    
             
@@ -3564,32 +3564,36 @@
 );%0A%0A            
+    
 ResultState%5B%5D re
@@ -3645,32 +3645,36 @@
 d);%0A            
+   
+ 
 if (resultStates
@@ -3677,32 +3677,36 @@
 ates == null) %7B%0A
+    
                 
@@ -3758,32 +3758,36 @@
                 
+ 
+   
 partitionResultS
@@ -3820,16 +3820,20 @@
 tates);%0A
+    
         
@@ -3842,32 +3842,36 @@
   %7D%0A            
+    
 resultStates%5Bpar
@@ -3898,24 +3898,38 @@
 ultState();%0A
+            %7D%0A
         %7D ca
@@ -4835,32 +4835,118 @@
 acksException %7B%0A
+        ResultState resultState;%0A        synchronized (partitionResultStateMap) %7B%0A    
         ResultSt
@@ -5003,32 +5003,36 @@
 obId);%0A%0A        
+    
 if (resultStates
@@ -5047,32 +5047,36 @@
 ) %7B%0A            
+   
+ 
 throw new Hyrack
@@ -5125,30 +5125,26 @@
     
-%7D%0A%0A        ResultState
+    %7D%0A%0A           
  res
@@ -5179,32 +5179,36 @@
 ition%5D;%0A        
+    
 if (resultState 
@@ -5222,32 +5222,36 @@
 ) %7B%0A            
+  
+  
 throw new Hyrack
@@ -5310,32 +5310,46 @@
 %22 + partition);%0A
+            %7D%0A
         %7D%0A%0A     

Synchronize the hashmap access of result states correctly.