001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.counter.service.persistence.impl;
016    
017    import com.liferay.portal.kernel.io.BigEndianCodec;
018    
019    /**
020     * @author Michael C. Han
021     * @author Shuyang Zhou
022     */
023    public class MultiDataCenterCounterFinderImpl extends CounterFinderImpl {
024    
025            public MultiDataCenterCounterFinderImpl(
026                    int dataCenterCount, int dataCenterDeploymentId) {
027    
028                    _multiDataCenterBits = getBits(dataCenterCount - 1);
029    
030                    if (_multiDataCenterBits > _BYTE_SHIFTS_MAX) {
031                            throw new IllegalArgumentException(
032                                    "Unable to shift more than 8 bits");
033                    }
034    
035                    if (getBits(dataCenterDeploymentId) > _multiDataCenterBits) {
036                            throw new IllegalArgumentException(
037                                    "Invalid data center count " + dataCenterCount +
038                                            " or data center deployment ID " + dataCenterDeploymentId);
039                    }
040    
041                    int bits = (_BYTE_SHIFTS_MAX - _multiDataCenterBits);
042    
043                    _mostSignificantByte = (byte)(dataCenterDeploymentId << bits);
044            }
045    
046            @Override
047            public long increment(String name, int size) {
048                    return getMultiClusterSafeValue(super.increment(name, size));
049            }
050    
051            protected static int getBits(int value) {
052                    if (value == 0) {
053                            return 0;
054                    }
055    
056                    return 32 - Integer.numberOfLeadingZeros(value);
057            }
058    
059            protected long getMultiClusterSafeValue(long value) {
060                    byte[] bytes = new byte[8];
061    
062                    BigEndianCodec.putLong(bytes, 0, value);
063    
064                    int modifiedLeftMostByte = (bytes[0] >>> _multiDataCenterBits);
065    
066                    bytes[0] = (byte)(modifiedLeftMostByte + _mostSignificantByte);
067    
068                    return BigEndianCodec.getLong(bytes, 0);
069            }
070    
071            private static final int _BYTE_SHIFTS_MAX = 7;
072    
073            private final byte _mostSignificantByte;
074            private final int _multiDataCenterBits;
075    
076    }