Skip to content
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.hdds.scm.metadata;

/**
* JMX interface for the SCM Metadata Store.
*/
public interface SCMMetadataStoreMXBean {

/**
* Estimated key count for each column family.
*/
String getEstimatedKeyCount();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
import java.io.IOException;
import java.math.BigInteger;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import com.google.protobuf.ByteString;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
Expand Down Expand Up @@ -57,15 +60,19 @@
import static org.apache.hadoop.hdds.scm.metadata.SCMDBDefinition.META;
import static org.apache.hadoop.ozone.OzoneConsts.DB_TRANSIENT_MARKER;

import org.apache.hadoop.metrics2.util.MBeans;
import org.apache.ratis.util.ExitUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.ObjectName;

/**
* A RocksDB based implementation of SCM Metadata Store.
*
*/
public class SCMMetadataStoreImpl implements SCMMetadataStore {
public class SCMMetadataStoreImpl implements SCMMetadataStore,
SCMMetadataStoreMXBean {

private Table<Long, DeletedBlocksTransaction> deletedBlocksTable;

Expand Down Expand Up @@ -100,6 +107,9 @@ public class SCMMetadataStoreImpl implements SCMMetadataStore {
private DBStore store;
private final OzoneConfiguration configuration;

private ObjectName mxBean;
private Map<String, Table<?, ?>> tableMap = new ConcurrentHashMap<>();

/**
* Constructs the metadata store and starts the DB Services.
*
Expand Down Expand Up @@ -190,6 +200,9 @@ public void start(OzoneConfiguration config)

checkTableStatus(statefulServiceConfigTable,
STATEFUL_SERVICE_CONFIG.getName());

mxBean = MBeans.register("SCMMetadataStore", "SCMMetadataStoreImpl",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this needs an "unRegister" in the stop() method?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sodonnel Thank you for your reminder, updated the PR, please have a look.

this);
}
}

Expand All @@ -199,6 +212,10 @@ public void stop() throws Exception {
store.close();
store = null;
}
if (mxBean != null) {
MBeans.unregister(mxBean);
mxBean = null;
}
}

@Override
Expand Down Expand Up @@ -313,6 +330,20 @@ private void checkTableStatus(Table table, String name) throws IOException {
LOG.error(String.format(logMessage, name));
throw new IOException(String.format(errMsg, name));
}
tableMap.put(name, table);
}

@Override
public String getEstimatedKeyCount() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I typed this earlier, but forgot to post it. This means we are going to have a metric where the value is a command seperated list of key value pairs, eg:

metric -> tab1 : 10, tab2 : 15 ... etc.

Have we got any other metrics like this? Would it be better if we had a metric for each table directly, so they can be charted etc if needed? Ie

SCMEstimatedKeyCountTab1 -> 10
SCMEstimatedKeyCounttab2 -> 15
etc

You would need to have dynamic metric names for this, but there is an example of doing that in ReplicationManagerMetrics

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sodonnel Thank you for the advice. Updated the PR, please have a look.

return tableMap.entrySet().stream().map(e -> {
try {
return e.getKey() + " : " + e.getValue().getEstimatedKeyCount();
} catch (IOException ex) {
ex.printStackTrace();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we send this to the logger, rather than stderr?

}
return "N/A";
}).collect(
Collectors.joining(", "));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* 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.hdds.scm.metadata;

import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.ozone.container.common.SCMTestUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.IOException;
import java.nio.file.Path;


/**
* Testing of SCMMetadataStoreImpl.
*/
public class TestSCMMetadataStoreImpl {
private OzoneConfiguration conf;
private SCMMetadataStore scmMetadataStore;

@BeforeEach
public void setUp(@TempDir Path tempDir) throws Exception {
conf = SCMTestUtils.getConf();

scmMetadataStore = new SCMMetadataStoreImpl(conf);
scmMetadataStore.start(conf);
}

@Test
public void testEstimatedKeyCount() {
Assertions.assertTrue(((SCMMetadataStoreImpl) scmMetadataStore)
.getEstimatedKeyCount().contains("sequenceId : 0"));

try {
scmMetadataStore.getSequenceIdTable().put("TestKey", 1L);
} catch (IOException e) {
// Ignore
}

Assertions.assertFalse(((SCMMetadataStoreImpl) scmMetadataStore)
.getEstimatedKeyCount().contains("sequenceId : 0"));
}

}