HDDS-186. Create under replicated queue. Contributed by Ajay Kumar.
This commit is contained in:
parent
56a4cdb980
commit
e9ec3d78f5
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.ozone.container.replication;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
import java.util.Queue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Priority queue to handle under-replicated and over replicated containers
|
||||||
|
* in ozone. ReplicationManager will consume these messages and decide
|
||||||
|
* accordingly.
|
||||||
|
*/
|
||||||
|
public class ReplicationQueue {
|
||||||
|
|
||||||
|
private final Queue<ReplicationRequest> queue;
|
||||||
|
|
||||||
|
ReplicationQueue() {
|
||||||
|
queue = new PriorityQueue<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean add(ReplicationRequest repObj) {
|
||||||
|
if (this.queue.contains(repObj)) {
|
||||||
|
// Remove the earlier message and insert this one
|
||||||
|
this.queue.remove(repObj);
|
||||||
|
}
|
||||||
|
return this.queue.add(repObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean remove(ReplicationRequest repObj) {
|
||||||
|
return queue.remove(repObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves, but does not remove, the head of this queue,
|
||||||
|
* or returns {@code null} if this queue is empty.
|
||||||
|
*
|
||||||
|
* @return the head of this queue, or {@code null} if this queue is empty
|
||||||
|
*/
|
||||||
|
public synchronized ReplicationRequest peek() {
|
||||||
|
return queue.peek();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves and removes the head of this queue,
|
||||||
|
* or returns {@code null} if this queue is empty.
|
||||||
|
*
|
||||||
|
* @return the head of this queue, or {@code null} if this queue is empty
|
||||||
|
*/
|
||||||
|
public synchronized ReplicationRequest poll() {
|
||||||
|
return queue.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean removeAll(List<ReplicationRequest> repObjs) {
|
||||||
|
return queue.removeAll(repObjs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return queue.size();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.ozone.container.replication;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper class for hdds replication queue. Implements its natural
|
||||||
|
* ordering for priority queue.
|
||||||
|
*/
|
||||||
|
public class ReplicationRequest implements Comparable<ReplicationRequest>,
|
||||||
|
Serializable {
|
||||||
|
private final long containerId;
|
||||||
|
private final short replicationCount;
|
||||||
|
private final short expecReplicationCount;
|
||||||
|
private final long timestamp;
|
||||||
|
|
||||||
|
public ReplicationRequest(long containerId, short replicationCount,
|
||||||
|
long timestamp, short expecReplicationCount) {
|
||||||
|
this.containerId = containerId;
|
||||||
|
this.replicationCount = replicationCount;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.expecReplicationCount = expecReplicationCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares this object with the specified object for order. Returns a
|
||||||
|
* negative integer, zero, or a positive integer as this object is less
|
||||||
|
* than, equal to, or greater than the specified object.
|
||||||
|
* @param o the object to be compared.
|
||||||
|
* @return a negative integer, zero, or a positive integer as this object
|
||||||
|
* is less than, equal to, or greater than the specified object.
|
||||||
|
* @throws NullPointerException if the specified object is null
|
||||||
|
* @throws ClassCastException if the specified object's type prevents it
|
||||||
|
* from being compared to this object.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int compareTo(ReplicationRequest o) {
|
||||||
|
if (o == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (this == o) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int retVal = Integer
|
||||||
|
.compare(getReplicationCount() - getExpecReplicationCount(),
|
||||||
|
o.getReplicationCount() - o.getExpecReplicationCount());
|
||||||
|
if (retVal != 0) {
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
return Long.compare(getTimestamp(), o.getTimestamp());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return new HashCodeBuilder(91, 1011)
|
||||||
|
.append(getContainerId())
|
||||||
|
.toHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ReplicationRequest that = (ReplicationRequest) o;
|
||||||
|
return new EqualsBuilder().append(getContainerId(), that.getContainerId())
|
||||||
|
.isEquals();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getContainerId() {
|
||||||
|
return containerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getReplicationCount() {
|
||||||
|
return replicationCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getExpecReplicationCount() {
|
||||||
|
return expecReplicationCount;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.hadoop.ozone.container.replication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ozone Container replicaton related classes.
|
||||||
|
*/
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.ozone.container.replication;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.apache.hadoop.util.Time;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test class for ReplicationQueue.
|
||||||
|
*/
|
||||||
|
public class TestReplicationQueue {
|
||||||
|
|
||||||
|
private ReplicationQueue replicationQueue;
|
||||||
|
private Random random;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
replicationQueue = new ReplicationQueue();
|
||||||
|
random = new Random();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDuplicateAddOp() {
|
||||||
|
long contId = random.nextLong();
|
||||||
|
String nodeId = UUID.randomUUID().toString();
|
||||||
|
ReplicationRequest obj1, obj2, obj3;
|
||||||
|
long time = Time.monotonicNow();
|
||||||
|
obj1 = new ReplicationRequest(contId, (short) 2, time, (short) 3);
|
||||||
|
obj2 = new ReplicationRequest(contId, (short) 2, time + 1, (short) 3);
|
||||||
|
obj3 = new ReplicationRequest(contId, (short) 1, time+2, (short) 3);
|
||||||
|
|
||||||
|
replicationQueue.add(obj1);
|
||||||
|
replicationQueue.add(obj2);
|
||||||
|
replicationQueue.add(obj3);
|
||||||
|
Assert.assertEquals("Should add only 1 msg as second one is duplicate",
|
||||||
|
1, replicationQueue.size());
|
||||||
|
ReplicationRequest temp = replicationQueue.poll();
|
||||||
|
Assert.assertEquals(temp, obj3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPollOp() {
|
||||||
|
long contId = random.nextLong();
|
||||||
|
String nodeId = UUID.randomUUID().toString();
|
||||||
|
ReplicationRequest msg1, msg2, msg3, msg4, msg5;
|
||||||
|
msg1 = new ReplicationRequest(contId, (short) 1, Time.monotonicNow(),
|
||||||
|
(short) 3);
|
||||||
|
long time = Time.monotonicNow();
|
||||||
|
msg2 = new ReplicationRequest(contId + 1, (short) 4, time, (short) 3);
|
||||||
|
msg3 = new ReplicationRequest(contId + 2, (short) 0, time, (short) 3);
|
||||||
|
msg4 = new ReplicationRequest(contId, (short) 2, time, (short) 3);
|
||||||
|
// Replication message for same container but different nodeId
|
||||||
|
msg5 = new ReplicationRequest(contId + 1, (short) 2, time, (short) 3);
|
||||||
|
|
||||||
|
replicationQueue.add(msg1);
|
||||||
|
replicationQueue.add(msg2);
|
||||||
|
replicationQueue.add(msg3);
|
||||||
|
replicationQueue.add(msg4);
|
||||||
|
replicationQueue.add(msg5);
|
||||||
|
Assert.assertEquals("Should have 3 objects",
|
||||||
|
3, replicationQueue.size());
|
||||||
|
|
||||||
|
// Since Priority queue orders messages according to replication count,
|
||||||
|
// message with lowest replication should be first
|
||||||
|
ReplicationRequest temp;
|
||||||
|
temp = replicationQueue.poll();
|
||||||
|
Assert.assertEquals("Should have 2 objects",
|
||||||
|
2, replicationQueue.size());
|
||||||
|
Assert.assertEquals(temp, msg3);
|
||||||
|
|
||||||
|
temp = replicationQueue.poll();
|
||||||
|
Assert.assertEquals("Should have 1 objects",
|
||||||
|
1, replicationQueue.size());
|
||||||
|
Assert.assertEquals(temp, msg5);
|
||||||
|
|
||||||
|
// Message 2 should be ordered before message 5 as both have same replication
|
||||||
|
// number but message 2 has earlier timestamp.
|
||||||
|
temp = replicationQueue.poll();
|
||||||
|
Assert.assertEquals("Should have 0 objects",
|
||||||
|
replicationQueue.size(), 0);
|
||||||
|
Assert.assertEquals(temp, msg4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveOp() {
|
||||||
|
long contId = random.nextLong();
|
||||||
|
String nodeId = UUID.randomUUID().toString();
|
||||||
|
ReplicationRequest obj1, obj2, obj3;
|
||||||
|
obj1 = new ReplicationRequest(contId, (short) 1, Time.monotonicNow(),
|
||||||
|
(short) 3);
|
||||||
|
obj2 = new ReplicationRequest(contId + 1, (short) 2, Time.monotonicNow(),
|
||||||
|
(short) 3);
|
||||||
|
obj3 = new ReplicationRequest(contId + 2, (short) 3, Time.monotonicNow(),
|
||||||
|
(short) 3);
|
||||||
|
|
||||||
|
replicationQueue.add(obj1);
|
||||||
|
replicationQueue.add(obj2);
|
||||||
|
replicationQueue.add(obj3);
|
||||||
|
Assert.assertEquals("Should have 3 objects",
|
||||||
|
3, replicationQueue.size());
|
||||||
|
|
||||||
|
replicationQueue.remove(obj3);
|
||||||
|
Assert.assertEquals("Should have 2 objects",
|
||||||
|
2, replicationQueue.size());
|
||||||
|
|
||||||
|
replicationQueue.remove(obj2);
|
||||||
|
Assert.assertEquals("Should have 1 objects",
|
||||||
|
1, replicationQueue.size());
|
||||||
|
|
||||||
|
replicationQueue.remove(obj1);
|
||||||
|
Assert.assertEquals("Should have 0 objects",
|
||||||
|
0, replicationQueue.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* SCM Testing and Mocking Utils.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.ozone.container.replication;
|
||||||
|
// Test classes for Replication functionality.
|
Loading…
Reference in New Issue
Block a user