Package edu.cmu.graphchi

Source Code of edu.cmu.graphchi.ChiVertex$Edge

package edu.cmu.graphchi;

import edu.cmu.graphchi.datablocks.BytesToValueConverter;
import edu.cmu.graphchi.datablocks.ChiPointer;
import edu.cmu.graphchi.datablocks.DataBlockManager;
import edu.cmu.graphchi.engine.auxdata.VertexDegree;
import sun.misc.Unsafe;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

import java.lang.reflect.Field;
import java.security.AccessController;
import java.util.concurrent.atomic.AtomicInteger;

/**
* Copyright [2012] [Aapo Kyrola, Guy Blelloch, Carlos Guestrin / Carnegie Mellon University]
*
* 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 at
*
* 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.
*/

/**
* Represents a vertex. Vertex contains a value and a set of in- and out-edges.
* @param <VertexValue>
* @param <EdgeValue>
*/
public class ChiVertex<VertexValue, EdgeValue> {

    /**
     *  To save memory, support now only 32-bit vertex ids.
     */
    private int id;
    public static DataBlockManager blockManager;
    public static BytesToValueConverter vertexValueConverter;
    public static BytesToValueConverter edgeValueConverter;
    public static boolean disableInedges = false;
    public static boolean disableOutedges = false;

    private volatile int nInedges = 0;
    private int[] inEdgeDataArray = null;

    private volatile int nOutedges = 0;
    private int[] outEdgeDataArray = null;

    /* Internal management */
    public boolean parallelSafe = true;

    /* We replicate the behavior of atomic integer to save some memory and improve performance */

    @SuppressWarnings("restriction")
    // http://stackoverflow.com/questions/13003871/how-do-i-get-the-instance-of-sun-misc-unsafe
    private static Unsafe getUnsafe() {
        try {

            Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
            singleoneInstanceField.setAccessible(true);
            return (Unsafe) singleoneInstanceField.get(null);

        } catch (IllegalArgumentException e) {
            throw e;
        } catch (SecurityException e) {
            throw e;
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    private static final Unsafe unsafe = getUnsafe();
    private static final long valueOffset_nInedges;
    private static final long valueOffset_nOutedges;

    static {
        try {
            valueOffset_nInedges = unsafe.objectFieldOffset
                    (ChiVertex.class.getDeclaredField("nInedges"));
            valueOffset_nOutedges = unsafe.objectFieldOffset
                    (ChiVertex.class.getDeclaredField("nOutedges"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    private ChiPointer vertexPtr;

    public ChiVertex(int id, VertexDegree degree) {
        this.id = id;

        if (degree != null) {
            if (!disableInedges) {
                inEdgeDataArray = new int[degree.inDegree * (edgeValueConverter != null ? 3 : 1)];
            } else {
                nInedges =  degree.inDegree;
            }
            if (!disableOutedges) {
                outEdgeDataArray = new int[degree.outDegree * (edgeValueConverter != null ? 3 : 1)];
            } else {
                nOutedges = degree.outDegree;
            }
        }
    }


    public int getId() {
        return this.id;
    }

    public void setDataPtr(ChiPointer vertexPtr) {
        this.vertexPtr = vertexPtr;
    }


    /**
     * Access the value of a vertex
     */
    public VertexValue getValue() {
        return blockManager.dereference(vertexPtr, (BytesToValueConverter<VertexValue>)
                vertexValueConverter);
    }

    /**
     * Set the value of the vertex.
     * @param x new value
     */
    public void setValue(VertexValue x) {
        blockManager.writeValue(vertexPtr, vertexValueConverter, x);
    }


    /**
     * Returns a random out-neighbors vertex id.
     * @return
     */
    public int getRandomOutNeighbor() {
        int i = (int) (Math.random() * numOutEdges());
        if (edgeValueConverter != null) {
            int idx = i * 3;
            return outEdgeDataArray[idx + 2];
        } else {
            return outEdgeDataArray[i];
        }
    }

    /**
     * Returns a random neighbor's vertex id.
     * @return
     */
    public int getRandomNeighbor() {
        if (numEdges() == 0) {
            return -1;
        }
        int i = (int) (Math.random() * numEdges());
        return edge(i).getVertexId();
    }



    public int numOutEdges() {
        return nOutedges;
    }


    public int numInEdges() {
        return nInedges;
    }

    /**
     * INTERNAL USE ONLY    (TODO: separate better)
     */
    public void addInEdge(int chunkId, int offset, int vertexId) {
        int tmpInEdges;
        /* Note: it would be nicer to use AtomicInteger, but I want to save as much memory as possible */
        for (;;) {
            int current = nInedges;
            tmpInEdges = current + 1;
            if (unsafe.compareAndSwapInt(this, valueOffset_nInedges, current, tmpInEdges)) {
                break;
            }
        }

        tmpInEdges--;
        if (edgeValueConverter != null) {
            int idx = tmpInEdges * 3;
            inEdgeDataArray[idx] = chunkId;
            inEdgeDataArray[idx + 1] = offset;
            inEdgeDataArray[idx + 2] = vertexId;
        } else {
            if (inEdgeDataArray != null)
                inEdgeDataArray[tmpInEdges] = vertexId;
        }
    }


    /**
     * INTERNAL USE ONLY  (TODO: separate better)
     */
    public void addOutEdge(int chunkId, int offset,  int vertexId) {
        int tmpOutEdges;
        /* Note: it would be nicer to use AtomicInteger, but I want to save as much memory as possible */
        for (;;) {
            int current = nOutedges;
            tmpOutEdges = current + 1;
            if (unsafe.compareAndSwapInt(this, valueOffset_nOutedges, current, tmpOutEdges)) {
                break;
            }
        }
        tmpOutEdges--;
        if (edgeValueConverter != null) {
            int idx = tmpOutEdges * 3;
            outEdgeDataArray[idx] = chunkId;
            outEdgeDataArray[idx + 1] = offset;
            outEdgeDataArray[idx + 2] = vertexId;
        } else {
            if (outEdgeDataArray != null)
                outEdgeDataArray[tmpOutEdges] = vertexId;
        }
    }

    /**
     * Get i'th in-edge
     * @param i
     * @return edge object
     */
    public ChiEdge<EdgeValue> inEdge(int i) {
        if (edgeValueConverter != null) {
            int idx = i * 3;
            return new Edge(new ChiPointer(inEdgeDataArray[idx], inEdgeDataArray[idx + 1]), inEdgeDataArray[idx + 2]);
        } else {
            return new Edge(null, inEdgeDataArray[i]);
        }
    }

    /**
     * Get i'th outedge
     * @param i
     * @return  edge object
     */
    public ChiEdge<EdgeValue>  outEdge(int i) {
        if (edgeValueConverter != null) {
            int idx = i * 3;
            return new Edge(new ChiPointer(outEdgeDataArray[idx], outEdgeDataArray[idx + 1]), outEdgeDataArray[idx + 2]);
        } else {
            return new Edge(null, outEdgeDataArray[i]);
        }
    }

    /**
     * Get vertex-id of the i'th out edge (avoid creating the edge-object).
     * @param i
     */
    public int getOutEdgeId(int i) {
        if (edgeValueConverter != null) {
            int idx = i * 3;
            return outEdgeDataArray[idx + 2];
        } else {
            return outEdgeDataArray[i];
        }
    }

    /**
     * Get i'th edge (in- our out-edge).
     * @param i
     * @return  edge object
     */
    public ChiEdge<EdgeValue> edge(int i) {
        if (i < nInedges) return inEdge(i);
        else return outEdge(i - nInedges);
    }

    /**
     * @return the number of in- and out-edges
     */
    public int numEdges() {
        return nInedges + nOutedges;
    }

    /**
     * ONLY ADVANCED USE
     */
    public int[] getOutNeighborArray() {
        if (edgeValueConverter != null) {
            int[] nbrs = new int[numOutEdges()];
            for(int i=0; i<nbrs.length; i++) {
                nbrs[i] = outEdgeDataArray[(i * 3) + 2];
            }
            return nbrs;
        } else {
            return outEdgeDataArray.clone();
        }
    }

    /**
     * Returns the value of i'th outedge (short-cut to outEdge(i)->getValue())
     * @param i
     * @return  the value of i'th outedge (short-cut to outEdge(i)->getValue())
     */
    public EdgeValue getOutEdgeValue(int i) {
        int idx = i * 3;
        return blockManager.dereference(new ChiPointer(outEdgeDataArray[idx], outEdgeDataArray[idx + 1]),
                (BytesToValueConverter<EdgeValue>) edgeValueConverter);
    }




    class Edge implements ChiEdge<EdgeValue> {
        Edge(ChiPointer dataPtr, int vertexId) {
            this.dataPtr = dataPtr;
            this.vertexId = vertexId;
        }

        ChiPointer dataPtr;
        int vertexId;

        public int getVertexId() {
            return  vertexId;
        }


        public EdgeValue getValue() {
            return blockManager.dereference(dataPtr, (BytesToValueConverter<EdgeValue>) edgeValueConverter);
        }

        public void setValue(EdgeValue x) {
            blockManager.writeValue(dataPtr, edgeValueConverter, x);
        }
    }

}
TOP

Related Classes of edu.cmu.graphchi.ChiVertex$Edge

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.