2 * Copyright 2008-2009 LinkedIn, Inc
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
17 package voldemort
.store
;
19 import java
.io
.Serializable
;
20 import java
.util
.HashMap
;
21 import java
.util
.List
;
23 import voldemort
.client
.RoutingTier
;
24 import voldemort
.serialization
.SerializerDefinition
;
25 import voldemort
.store
.slop
.strategy
.HintedHandoffStrategyType
;
26 import voldemort
.store
.system
.SystemStoreConstants
;
27 import voldemort
.utils
.Utils
;
29 import com
.google
.common
.base
.Objects
;
32 * The configuration information for a store.
36 public class StoreDefinition
implements Serializable
{
38 private static final long serialVersionUID
= 1;
40 private final String name
;
41 private final String type
;
42 private final String description
;
43 private final SerializerDefinition keySerializer
;
44 private final SerializerDefinition valueSerializer
;
45 private final SerializerDefinition transformsSerializer
;
46 private final RoutingTier routingPolicy
;
47 private final int replicationFactor
;
48 private final Integer preferredWrites
;
49 private final int requiredWrites
;
50 private final Integer preferredReads
;
51 private final int requiredReads
;
52 private final Integer retentionPeriodDays
;
53 private final Integer retentionScanThrottleRate
;
54 private final Integer retentionFrequencyDays
;
55 private final String routingStrategyType
;
56 private final String viewOf
;
57 private final HashMap
<Integer
, Integer
> zoneReplicationFactor
;
58 private final Integer zoneCountReads
;
59 private final Integer zoneCountWrites
;
60 private final String valueTransformation
;
61 private final String serializerFactory
;
62 private final HintedHandoffStrategyType hintedHandoffStrategyType
;
63 private final Integer hintPrefListSize
;
64 private final List
<String
> owners
;
65 private final long memoryFootprintMB
;
67 public StoreDefinition(String name
,
70 SerializerDefinition keySerializer
,
71 SerializerDefinition valueSerializer
,
72 SerializerDefinition transformsSerializer
,
73 RoutingTier routingPolicy
,
74 String routingStrategyType
,
75 int replicationFactor
,
76 Integer preferredReads
,
78 Integer preferredWrites
,
82 HashMap
<Integer
, Integer
> zoneReplicationFactor
,
83 Integer zoneCountReads
,
84 Integer zoneCountWrites
,
85 Integer retentionDays
,
86 Integer retentionThrottleRate
,
87 Integer retentionFrequencyDays
,
89 HintedHandoffStrategyType hintedHandoffStrategyType
,
90 Integer hintPrefListSize
,
92 long memoryFootprintMB
) {
93 this.name
= Utils
.notNull(name
);
95 this.description
= description
;
96 this.replicationFactor
= replicationFactor
;
97 this.preferredReads
= preferredReads
;
98 this.requiredReads
= requiredReads
;
99 this.preferredWrites
= preferredWrites
;
100 this.requiredWrites
= requiredWrites
;
101 this.routingPolicy
= routingPolicy
;
102 this.keySerializer
= keySerializer
;
103 this.valueSerializer
= valueSerializer
;
104 this.transformsSerializer
= transformsSerializer
;
105 this.retentionPeriodDays
= retentionDays
;
106 this.retentionScanThrottleRate
= retentionThrottleRate
;
107 this.retentionFrequencyDays
= retentionFrequencyDays
;
108 this.memoryFootprintMB
= memoryFootprintMB
;
109 this.routingStrategyType
= routingStrategyType
;
110 this.viewOf
= viewOfStore
;
111 this.valueTransformation
= valTrans
;
112 this.zoneReplicationFactor
= zoneReplicationFactor
;
113 this.zoneCountReads
= zoneCountReads
;
114 this.zoneCountWrites
= zoneCountWrites
;
115 this.serializerFactory
= factory
;
116 this.hintedHandoffStrategyType
= hintedHandoffStrategyType
;
117 this.hintPrefListSize
= hintPrefListSize
;
118 this.owners
= owners
;
121 private void throwIllegalException(String errorMessage
) {
122 throw new IllegalArgumentException(" Store '" + this.name
+ "'. Error: " + errorMessage
);
125 protected void checkParameterLegality() {
128 Utils
.notNull(this.type
);
129 Utils
.notNull(routingPolicy
);
130 Utils
.notNull(keySerializer
);
131 Utils
.notNull(valueSerializer
);
133 if(requiredReads
< 1)
134 throwIllegalException("Cannot have a requiredReads number less than 1.");
135 else if(requiredReads
> replicationFactor
)
136 throwIllegalException("Cannot have more requiredReads then there are replicas.");
138 if(requiredWrites
< 1)
139 throwIllegalException("Cannot have a requiredWrites number less than 1.");
140 else if(requiredWrites
> replicationFactor
)
141 throwIllegalException("Cannot have more requiredWrites then there are replicas.");
143 if(preferredWrites
!= null) {
144 if(preferredWrites
< requiredWrites
)
145 throwIllegalException("preferredWrites must be greater or equal to requiredWrites.");
146 if(preferredWrites
> replicationFactor
)
147 throwIllegalException("Cannot have more preferredWrites then there are replicas.");
149 if(preferredReads
!= null) {
150 if(preferredReads
< requiredReads
)
151 throwIllegalException("preferredReads must be greater or equal to requiredReads.");
152 if(preferredReads
> replicationFactor
)
153 throwIllegalException("Cannot have more preferredReads then there are replicas.");
156 if(retentionPeriodDays
!= null && retentionPeriodDays
< 0)
157 throwIllegalException("Retention days must be non-negative.");
159 if(!SystemStoreConstants
.isSystemStore(name
) && zoneReplicationFactor
!= null
160 && zoneReplicationFactor
.size() != 0) {
162 if(zoneCountReads
== null || zoneCountReads
< 0)
163 throwIllegalException("Zone Counts reads must be non-negative / non-null");
165 if(zoneCountWrites
== null || zoneCountWrites
< 0)
166 throwIllegalException("Zone Counts writes must be non-negative");
168 int sumZoneReplicationFactor
= 0;
169 int replicatingZones
= 0;
170 for(Integer zoneId
: zoneReplicationFactor
.keySet()) {
171 int currentZoneRepFactor
= zoneReplicationFactor
.get(zoneId
);
173 sumZoneReplicationFactor
+= currentZoneRepFactor
;
174 if(currentZoneRepFactor
> 0)
178 if(replicatingZones
<= 0) {
179 throwIllegalException("Cannot have no zones to replicate to. "
180 + "Should have some positive zoneReplicationFactor");
183 // Check if sum of individual zones is equal to total replication
185 if(sumZoneReplicationFactor
!= replicationFactor
) {
186 throwIllegalException("Sum total of zones (" + sumZoneReplicationFactor
187 + ") does not match the total replication factor ("
188 + replicationFactor
+ ")");
191 // Check if number of zone-count-reads and zone-count-writes are
192 // less than zones replicating to
193 if(zoneCountReads
>= replicatingZones
) {
194 throwIllegalException("Number of zones to block for while reading ("
196 + ") should be less then replicating zones ("
197 + replicatingZones
+ ")");
200 if(zoneCountWrites
>= replicatingZones
) {
201 throwIllegalException("Number of zones to block for while writing ("
203 + ") should be less then replicating zones ("
204 + replicatingZones
+ ")");
209 public String
getDescription() {
210 return this.description
;
213 public String
getSerializerFactory() {
214 return this.serializerFactory
;
217 public boolean hasTransformsSerializer() {
218 return transformsSerializer
!= null;
221 public String
getName() {
225 public int getRequiredWrites() {
226 return requiredWrites
;
229 public SerializerDefinition
getKeySerializer() {
230 return keySerializer
;
233 public SerializerDefinition
getValueSerializer() {
234 return valueSerializer
;
237 public SerializerDefinition
getTransformsSerializer() {
238 return transformsSerializer
;
241 public RoutingTier
getRoutingPolicy() {
242 return this.routingPolicy
;
245 public int getReplicationFactor() {
246 return this.replicationFactor
;
249 public String
getRoutingStrategyType() {
250 return routingStrategyType
;
253 public int getRequiredReads() {
254 return this.requiredReads
;
257 public boolean hasPreferredWrites() {
258 return preferredWrites
!= null;
261 public int getPreferredWrites() {
262 return preferredWrites
== null ?
getRequiredWrites() : preferredWrites
;
265 public int getPreferredReads() {
266 return preferredReads
== null ?
getRequiredReads() : preferredReads
;
269 public boolean hasPreferredReads() {
270 return preferredReads
!= null;
273 public String
getType() {
277 public boolean hasRetentionPeriod() {
278 return this.retentionPeriodDays
!= null && this.retentionPeriodDays
> 0;
281 public Integer
getRetentionDays() {
282 return this.retentionPeriodDays
;
285 public boolean hasRetentionScanThrottleRate() {
286 return this.retentionScanThrottleRate
!= null;
289 public Integer
getRetentionScanThrottleRate() {
290 return this.retentionScanThrottleRate
;
293 public boolean hasRetentionFrequencyDays() {
294 return this.retentionFrequencyDays
!= null;
297 public Integer
getRetentionFrequencyDays() {
298 return this.retentionFrequencyDays
;
301 public boolean isView() {
302 return this.viewOf
!= null;
305 public String
getViewTargetStoreName() {
309 public boolean hasValueTransformation() {
310 return this.valueTransformation
!= null;
313 public String
getValueTransformation() {
314 return valueTransformation
;
317 public HashMap
<Integer
, Integer
> getZoneReplicationFactor() {
318 return zoneReplicationFactor
;
321 public Integer
getZoneCountReads() {
322 return zoneCountReads
;
325 public boolean hasZoneCountReads() {
326 return zoneCountReads
!= null;
329 public Integer
getZoneCountWrites() {
330 return zoneCountWrites
;
333 public boolean hasZoneCountWrites() {
334 return zoneCountWrites
!= null;
337 public HintedHandoffStrategyType
getHintedHandoffStrategyType() {
338 return hintedHandoffStrategyType
;
341 public boolean hasHintedHandoffStrategyType() {
342 return hintedHandoffStrategyType
!= null;
345 public Integer
getHintPrefListSize() {
346 return hintPrefListSize
;
349 public boolean hasHintPreflistSize() {
350 return hintPrefListSize
!= null;
353 public List
<String
> getOwners() {
357 public long getMemoryFootprintMB() {
358 return this.memoryFootprintMB
;
361 public boolean hasMemoryFootprint() {
362 return memoryFootprintMB
!= 0;
366 * When making changes, always make sure {@link #equals(Object)}, {@link #hashCode()} and
367 * {@link #diff(StoreDefinition, String, String)} behave consistently.
369 * @param o other {@link Object} to compare against.
370 * @return true if this instance equals the other instance, false otherwise.
373 public boolean equals(Object o
) {
378 else if(!(o
.getClass() == StoreDefinition
.class))
381 StoreDefinition def
= (StoreDefinition
) o
;
382 return getName().equals(def
.getName())
383 && getType().equals(def
.getType())
384 && getReplicationFactor() == def
.getReplicationFactor()
385 && getRequiredReads() == def
.getRequiredReads()
386 && Objects
.equal(getPreferredReads(), def
.getPreferredReads())
387 && getRequiredWrites() == def
.getRequiredWrites()
388 && Objects
.equal(getPreferredWrites(), def
.getPreferredWrites())
389 && getKeySerializer().equals(def
.getKeySerializer())
390 && getValueSerializer().equals(def
.getValueSerializer())
391 && Objects
.equal(getTransformsSerializer() != null ?
getTransformsSerializer() : null,
392 def
.getTransformsSerializer() != null ? def
.getTransformsSerializer() : null)
393 && getRoutingPolicy() == def
.getRoutingPolicy()
394 && Objects
.equal(getViewTargetStoreName(), def
.getViewTargetStoreName())
395 // FIXME: This comparison is irrelevant, but not changing it in case it breaks something...
396 && Objects
.equal(getValueTransformation() != null ?
getValueTransformation().getClass() : null,
397 def
.getValueTransformation() != null ? def
.getValueTransformation().getClass() : null)
398 // FIXME: This comparison is irrelevant, but not changing it in case it breaks something...
399 && Objects
.equal(getZoneReplicationFactor() != null ?
getZoneReplicationFactor().getClass() : null,
400 def
.getZoneReplicationFactor() != null ? def
.getZoneReplicationFactor().getClass() : null)
401 && Objects
.equal(getZoneCountReads(), def
.getZoneCountReads())
402 && Objects
.equal(getZoneCountWrites(), def
.getZoneCountWrites())
403 && Objects
.equal(getRetentionDays(), def
.getRetentionDays())
404 && Objects
.equal(getRetentionScanThrottleRate(), def
.getRetentionScanThrottleRate())
405 && Objects
.equal(getSerializerFactory() != null ?
getSerializerFactory() : null,
406 def
.getSerializerFactory() != null ? def
.getSerializerFactory() : null)
407 && Objects
.equal(getHintedHandoffStrategyType(), def
.getHintedHandoffStrategyType())
408 && Objects
.equal(getHintPrefListSize(), def
.getHintPrefListSize())
409 && Objects
.equal(getMemoryFootprintMB(), def
.getMemoryFootprintMB());
413 * When making changes, always make sure {@link #equals(Object)}, {@link #hashCode()} and
414 * {@link #diff(StoreDefinition, String, String)} behave consistently.
417 public int hashCode() {
418 return Objects
.hashCode(getName(),
422 getValueSerializer(),
423 getTransformsSerializer(),
425 getRoutingStrategyType(),
426 getReplicationFactor(),
430 getPreferredWrites(),
431 getViewTargetStoreName(),
432 // FIXME: This comparison is irrelevant, but not changing it in case it breaks something...
433 getValueTransformation() == null ?
null : getValueTransformation().getClass(),
434 // FIXME: This comparison is irrelevant, but not changing it in case it breaks something...
435 getZoneReplicationFactor() == null ?
null : getZoneReplicationFactor().getClass(),
437 getZoneCountWrites(),
439 getRetentionScanThrottleRate(),
440 getSerializerFactory(),
441 hasHintedHandoffStrategyType() ?
getHintedHandoffStrategyType() : null,
442 hasHintPreflistSize() ?
getHintPrefListSize() : null,
444 getMemoryFootprintMB());
448 public String
toString() {
449 return "StoreDefinition(name = " + getName() + ", type = " + getType() + ", description = "
450 + getDescription() + ", key-serializer = " + getKeySerializer()
451 + ", value-serializer = " + getValueSerializer() + ", routing = "
452 + getRoutingPolicy() + ", routing-strategy = " + getRoutingStrategyType()
453 + ", replication = " + getReplicationFactor() + ", required-reads = "
454 + getRequiredReads() + ", preferred-reads = " + getPreferredReads()
455 + ", required-writes = " + getRequiredWrites() + ", preferred-writes = "
456 + getPreferredWrites() + ", view-target = " + getViewTargetStoreName()
457 + ", value-transformation = " + getValueTransformation() + ", retention-days = "
458 + getRetentionDays() + ", throttle-rate = " + getRetentionScanThrottleRate()
459 + ", zone-replication-factor = " + getZoneReplicationFactor()
460 + ", zone-count-reads = " + getZoneCountReads() + ", zone-count-writes = "
461 + getZoneCountWrites() + ", serializer factory = " + getSerializerFactory() + ")"
462 + ", hinted-handoff-strategy = " + getHintedHandoffStrategyType()
463 + ", hint-preflist-size = " + getHintPrefListSize() + ", owners = " + getOwners()
464 + ", memory-footprint(MB) = " + getMemoryFootprintMB() + ")";
468 * Calls {@link #diff(StoreDefinition, "this", "other")}
470 * @param other StoreDefinition to compare against.
471 * @return a String containing information about differences between this StoreDefinition and the other one.
473 public String
diff(StoreDefinition other
) {
474 return diff(other
, "this", "other");
478 * When making changes, always make sure {@link #equals(Object)}, {@link #hashCode()} and
479 * {@link #diff(StoreDefinition, String, String)} behave consistently.
481 * @param other StoreDefinition to compare against.
482 * @param thisName The name to be printed to identify this StoreDefinition instance.
483 * @param otherName The name to be printed to identify the other StoreDefinition instance.
484 * @return a String containing information about differences between this StoreDefinition and the other one.
486 public String
diff(StoreDefinition other
, String thisName
, String otherName
) {
487 if (this.equals(other
)) {
488 return "StoreDefinitions are identical.";
490 StringBuilder sb
= new StringBuilder();
491 if (!this.getName().equals(other
.getName())) {
492 addToDiff("Name", this.getName(), other
.getName(), sb
, thisName
, otherName
);
494 if (!this.getType().equals(other
.getType())) {
495 addToDiff("Type", this.getType(), other
.getType(), sb
, thisName
, otherName
);
497 if (this.getReplicationFactor() != other
.getReplicationFactor()) {
498 addToDiff("Replication factor", this.getReplicationFactor(), other
.getReplicationFactor(), sb
, thisName
, otherName
);
500 if (this.getRequiredReads() != other
.getRequiredReads()) {
501 addToDiff("Required reads", this.getRequiredReads(), other
.getRequiredReads(), sb
, thisName
, otherName
);
503 if (!Objects
.equal(this.getPreferredReads(), other
.getPreferredReads())) {
504 addToDiff("Preferred reads", this.getPreferredReads(), other
.getPreferredReads(), sb
, thisName
, otherName
);
506 if (this.getRequiredWrites() != other
.getRequiredWrites()) {
507 addToDiff("Required writes", this.getRequiredWrites(), other
.getRequiredWrites(), sb
, thisName
, otherName
);
509 if (!Objects
.equal(this.getPreferredWrites(), other
.getPreferredWrites())) {
510 addToDiff("Preferred writes", this.getPreferredWrites(), other
.getPreferredWrites(), sb
, thisName
, otherName
);
512 if (!this.getKeySerializer().equals(other
.getKeySerializer())) {
513 addToDiff("Key serializer", this.getKeySerializer().toString(), other
.getKeySerializer().toString(), sb
, thisName
, otherName
);
515 if (!this.getValueSerializer().equals(other
.getValueSerializer())) {
516 addToDiff("Value serializer", this.getValueSerializer().toString(), other
.getValueSerializer().toString(), sb
, thisName
, otherName
);
518 if (!Objects
.equal(this.getTransformsSerializer() != null ?
this.getTransformsSerializer(): null,
519 other
.getTransformsSerializer() != null ? other
.getTransformsSerializer(): null)) {
520 // FIXME: This ternary operator is useless. Leaving it as is for consistency with equals().
521 addToDiff("Transforms Serializer", this.getTransformsSerializer().toString(), other
.getTransformsSerializer().toString(), sb
, thisName
, otherName
);
523 if (this.getRoutingPolicy() != other
.getRoutingPolicy()) {
524 addToDiff("Routing policy", this.getRoutingPolicy().toDisplay(), other
.getRoutingPolicy().toDisplay(), sb
, thisName
, otherName
);
526 if (!Objects
.equal(this.getViewTargetStoreName(), other
.getViewTargetStoreName())) {
527 addToDiff("View target store name", this.getViewTargetStoreName(), other
.getViewTargetStoreName(), sb
, thisName
, otherName
);
529 if (!Objects
.equal(this.getValueTransformation() != null ?
this.getValueTransformation().getClass(): null,
530 other
.getValueTransformation() != null ? other
.getValueTransformation().getClass() : null)) {
531 // FIXME: This class comparison is irrelevant since it's always a String. Leaving it as is for consistency with equals().
532 addToDiff("Value transformation", this.getValueTransformation(), other
.getValueTransformation(), sb
, thisName
, otherName
);
534 if (!Objects
.equal(this.getZoneReplicationFactor() != null ?
this.getZoneReplicationFactor().getClass(): null,
535 other
.getZoneReplicationFactor() != null ? other
.getZoneReplicationFactor().getClass(): null)) {
536 // FIXME: This class comparison is irrelevant since it's always a HashMap. Leaving it as is for consistency with equals().
537 addToDiff("Zone replication factor", this.getZoneReplicationFactor().toString(), other
.getZoneReplicationFactor().toString(), sb
, thisName
, otherName
);
539 if (!Objects
.equal(this.getZoneCountReads(), other
.getZoneCountReads())) {
540 addToDiff("Zone count reads", this.getZoneCountReads(), other
.getZoneCountReads(), sb
, thisName
, otherName
);
542 if (!Objects
.equal(this.getZoneCountWrites(), other
.getZoneCountWrites())) {
543 addToDiff("Zone count writes", this.getZoneCountWrites(), other
.getZoneCountWrites(), sb
, thisName
, otherName
);
545 if (!Objects
.equal(this.getRetentionDays(), other
.getRetentionDays())) {
546 addToDiff("Retention days", this.getRetentionDays(), other
.getRetentionDays(), sb
, thisName
, otherName
);
548 if (!Objects
.equal(this.getRetentionScanThrottleRate(), other
.getRetentionScanThrottleRate())) {
549 addToDiff("Retention scan throttle rate", this.getRetentionScanThrottleRate(), other
.getRetentionScanThrottleRate(), sb
, thisName
, otherName
);
551 if (!Objects
.equal(this.getSerializerFactory() != null ?
getSerializerFactory() : null,
552 other
.getSerializerFactory() != null ? other
.getSerializerFactory(): null)) {
553 addToDiff("Serialization Factory", this.getSerializerFactory(), other
.getSerializerFactory(), sb
, thisName
, otherName
);
555 if (!Objects
.equal(this.getHintedHandoffStrategyType(), other
.getHintedHandoffStrategyType())) {
556 addToDiff("Hinted handoff strategy", this.getHintedHandoffStrategyType().toDisplay(), other
.getHintedHandoffStrategyType().toDisplay(), sb
, thisName
, otherName
);
558 if (!Objects
.equal(this.getHintPrefListSize(), other
.getHintPrefListSize())) {
559 addToDiff("Hinted preference list size", this.getHintPrefListSize(), other
.getHintPrefListSize(), sb
, thisName
, otherName
);
561 if (!Objects
.equal(this.getMemoryFootprintMB(), other
.getMemoryFootprintMB())) {
562 addToDiff("Memory footprint (MB)", this.getMemoryFootprintMB(), other
.getMemoryFootprintMB(), sb
, thisName
, otherName
);
564 sb
.append("All other properties are identical.");
565 return sb
.toString();
569 private void addToDiff(String propertyName
, long thisValue
, long otherValue
, StringBuilder sb
, String thisName
, String otherName
) {
570 addToDiff(propertyName
, Long
.toString(thisValue
), Long
.toString(otherValue
), sb
, thisName
, otherName
);
573 private void addToDiff(String propertyName
, int thisValue
, int otherValue
, StringBuilder sb
, String thisName
, String otherName
) {
574 addToDiff(propertyName
, Integer
.toString(thisValue
), Integer
.toString(otherValue
), sb
, thisName
, otherName
);
577 private void addToDiff(String propertyName
, String thisValue
, String otherValue
, StringBuilder sb
, String thisName
, String otherName
) {
578 sb
.append(propertyName
);
579 sb
.append(" differs:\n\t");
582 sb
.append(thisValue
);
584 sb
.append(otherName
);
586 sb
.append(otherValue
);