1 // Copyright 2013 Google Inc. All Rights Reserved.
2 package com
.google
.appengine
.api
.labs
.datastore
.overlay
;
5 * The set of id allocation policies available.
6 * The map of (counter value, id policy) to valid ids is one-to-one.
8 enum IdAllocationPolicy
implements IdAllocationPolicyInterface
{
10 /** The default sequential allocation policy. */
11 SEQUENTIAL(newSequentialPolicy(0)),
12 /** The default scattered allocation policy. */
13 SCATTERED(newScatteredPolicy(0)),
14 /** The sequential allocation policy for an overlay Datastore. */
15 OVERLAY_SEQUENTIAL(newSequentialPolicy(1)),
16 /** The scattered allocation policy for an overlay Datastore. */
17 OVERLAY_SCATTERED(newScatteredPolicy(1));
20 * Maps an ID assigned from a default policy into the corresponding overlay ID space.
22 * @param id an ID from the {@code DEFAULT_SEQUENTIAL} or {@code DEFAULT_SCATTERED} ranges
23 * @return an ID representing the same counter value in the {@code OVERLAY_SEQUENTIAL} or
24 * {@code OVERLAY_SCATTERED} range.
25 * @throws IllegalArgumentException if the ID is not from the {@code DEFAULT_SEQUENTIAL} or
26 * {@code DEFAULT_SCATTERED} ranges
28 public static long overlayIdFromDefaultId(long id
) {
29 if (SEQUENTIAL
.containsId(id
)) {
30 return OVERLAY_SEQUENTIAL
.counterToId(SEQUENTIAL
.idToCounter(id
));
31 } else if (SCATTERED
.containsId(id
)) {
32 return OVERLAY_SCATTERED
.counterToId(SCATTERED
.idToCounter(id
));
34 throw new IllegalArgumentException(
35 "ID does not conform to a known default allocation policy: " + Long
.toHexString(id
));
39 private final IdAllocationPolicyInterface policy
;
41 private IdAllocationPolicy(IdAllocationPolicyInterface policy
) {
46 public boolean containsId(long id
) {
47 return policy
.containsId(id
);
51 public long getMaximumCounterValue() {
52 return policy
.getMaximumCounterValue();
56 public long counterToId(long counter
) {
57 return policy
.counterToId(counter
);
61 public long idToCounter(long id
) {
62 return policy
.idToCounter(id
);
65 private static IdAllocationPolicyInterface
newSequentialPolicy(int depth
) {
66 final long minId
= minSequentialId(depth
);
67 final long maxCounterValue
= (1L << maxSequentialBit(depth
)) - 1;
68 final long maxId
= minId
+ maxCounterValue
;
70 return new IdAllocationPolicyInterface() {
72 public boolean containsId(long id
) {
73 return (id
>= minId
&& id
<= maxId
);
77 public long getMaximumCounterValue() {
78 return maxCounterValue
;
82 public long counterToId(long counter
) {
83 checkCounterBounds(this, counter
);
84 return minId
+ counter
;
88 public long idToCounter(long id
) {
89 checkIdBounds(this, id
);
96 private static IdAllocationPolicyInterface
newScatteredPolicy(int depth
) {
97 final long maxBit
= maxScatteredBit(depth
);
98 final long maxCounterValue
= (1L << maxBit
) - 1;
99 final long minId
= minScatteredId(depth
);
100 final long maxId
= minId
+ maxCounterValue
;
101 final long scatterShift
= 64 - maxBit
;
102 return new IdAllocationPolicyInterface() {
105 public boolean containsId(long id
) {
106 return (id
>= minId
&& id
<= maxId
);
110 public long getMaximumCounterValue() {
111 return maxCounterValue
;
115 public long counterToId(long counter
) {
116 checkCounterBounds(this, counter
);
117 return minId
+ Long
.reverse(counter
<< scatterShift
);
121 public long idToCounter(long id
) {
122 checkIdBounds(this, id
);
123 return Long
.reverse(id
) >>> scatterShift
;
128 private static int maxSequentialBit(int depth
) {
129 return 52 - (3 * depth
);
132 private static long minSequentialId(int depth
) {
134 for (int i
= 0; i
< depth
; i
++) {
135 prefix
= (prefix
<< 3) + 6;
137 return prefix
<< (maxSequentialBit(depth
) + 1);
140 private static int maxScatteredBit(int depth
) {
141 return maxSequentialBit(depth
) - 1;
144 private static long minScatteredId(int depth
) {
145 return minSequentialId(depth
) + (1L << maxSequentialBit(depth
));
148 private static void checkCounterBounds(IdAllocationPolicyInterface policy
, long counter
) {
150 throw new IllegalArgumentException(
151 "Counter " + Long
.toHexString(counter
) + " is non-positive.");
153 if (counter
> policy
.getMaximumCounterValue()) {
154 throw new IllegalArgumentException("Counter " + Long
.toHexString(counter
)
155 + " exceeds maximum counter value " + Long
.toHexString(policy
.getMaximumCounterValue())
160 private static void checkIdBounds(IdAllocationPolicyInterface policy
, long id
) {
161 if (!policy
.containsId(id
)) {
162 throw new IllegalArgumentException("ID does not conform to allocation policy "
163 + policy
.getClass().getName() + ": " + Long
.toHexString(id
));