001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.conf; 019 020import static org.junit.jupiter.api.Assertions.assertFalse; 021import static org.junit.jupiter.api.Assertions.assertTrue; 022 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.testclassification.ClientTests; 025import org.apache.hadoop.hbase.testclassification.SmallTests; 026import org.junit.jupiter.api.Tag; 027import org.junit.jupiter.api.Test; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030 031@Tag(SmallTests.TAG) 032@Tag(ClientTests.TAG) 033public class TestConfigurationManager { 034 035 private static final Logger LOG = LoggerFactory.getLogger(TestConfigurationManager.class); 036 037 static class DummyConfigurationObserver implements ConfigurationObserver { 038 private boolean notifiedOnChange = false; 039 private final ConfigurationManager cm; 040 041 public DummyConfigurationObserver(ConfigurationManager cm) { 042 this.cm = cm; 043 register(); 044 } 045 046 @Override 047 public void onConfigurationChange(Configuration conf) { 048 notifiedOnChange = true; 049 } 050 051 // Was the observer notified on Configuration change? 052 public boolean wasNotifiedOnChange() { 053 return notifiedOnChange; 054 } 055 056 public void resetNotifiedOnChange() { 057 notifiedOnChange = false; 058 } 059 060 public void register() { 061 cm.registerObserver(this); 062 } 063 064 public void deregister() { 065 cm.deregisterObserver(this); 066 } 067 } 068 069 /** 070 * Test if observers get notified by the <code>ConfigurationManager</code> when the Configuration 071 * is reloaded. 072 */ 073 @Test 074 public void testCheckIfObserversNotified() { 075 Configuration conf = new Configuration(); 076 ConfigurationManager cm = new ConfigurationManager(); 077 DummyConfigurationObserver d1 = new DummyConfigurationObserver(cm); 078 079 // Check if we get notified. 080 cm.notifyAllObservers(conf); 081 assertTrue(d1.wasNotifiedOnChange()); 082 d1.resetNotifiedOnChange(); 083 084 // Now check if we get notified on change with more than one observers. 085 DummyConfigurationObserver d2 = new DummyConfigurationObserver(cm); 086 cm.notifyAllObservers(conf); 087 assertTrue(d1.wasNotifiedOnChange()); 088 d1.resetNotifiedOnChange(); 089 assertTrue(d2.wasNotifiedOnChange()); 090 d2.resetNotifiedOnChange(); 091 092 // Now try deregistering an observer and verify that it was not notified 093 d2.deregister(); 094 cm.notifyAllObservers(conf); 095 assertTrue(d1.wasNotifiedOnChange()); 096 d1.resetNotifiedOnChange(); 097 assertFalse(d2.wasNotifiedOnChange()); 098 } 099 100 // Register an observer that will go out of scope immediately, allowing 101 // us to test that out of scope observers are deregistered. 102 private void registerLocalObserver(ConfigurationManager cm) { 103 new DummyConfigurationObserver(cm); 104 } 105 106 /** 107 * Test if out-of-scope observers are deregistered on GC. 108 */ 109 @Test 110 public void testDeregisterOnOutOfScope() { 111 Configuration conf = new Configuration(); 112 ConfigurationManager cm = new ConfigurationManager(); 113 114 boolean outOfScopeObserversDeregistered = false; 115 116 // On my machine, I was able to cause a GC after around 5 iterations. 117 // If we do not cause a GC in 100k iterations, which is very unlikely, 118 // there might be something wrong with the GC. 119 for (int i = 0; i < 100000; i++) { 120 registerLocalObserver(cm); 121 cm.notifyAllObservers(conf); 122 123 // 'Suggest' the system to do a GC. We should be able to cause GC 124 // atleast once in the 2000 iterations. 125 System.gc(); 126 127 // If GC indeed happened, all the observers (which are all out of scope), 128 // should have been deregistered. 129 if (cm.getNumObservers() <= i) { 130 outOfScopeObserversDeregistered = true; 131 break; 132 } 133 } 134 if (!outOfScopeObserversDeregistered) { 135 LOG.warn("Observers were not GC-ed! Something seems to be wrong."); 136 } 137 assertTrue(outOfScopeObserversDeregistered); 138 } 139}