/** * Remove all {@link Constraint Constraints} that have been added to the table * and turn off the constraint processing. * <p> * All {@link Configuration Configurations} and their associated * {@link Constraint} are removed. * * @param desc * {@link HTableDescriptor} to remove {@link Constraint Constraints} * from. */ public static void remove(HTableDescriptor desc) { // disable constraints disable(desc); // remove all the constraint settings List<Bytes> keys = new ArrayList<>(); // loop through all the key, values looking for constraints for (Map.Entry<Bytes, Bytes> e : desc .getValues().entrySet()) { String key = Bytes.toString((e.getKey().get())); String[] className = CONSTRAINT_HTD_ATTR_KEY_PATTERN.split(key); if (className.length == 2) { keys.add(e.getKey()); } } // now remove all the keys we found for (Bytes key : keys) { desc.remove(key); } }
@SuppressWarnings("unchecked") @Test public void testSimpleReadWrite() throws Throwable { HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName())); Constraints.add(desc, WorksConstraint.class); List<? extends Constraint> constraints = Constraints.getConstraints(desc, this.getClass().getClassLoader()); assertEquals(1, constraints.size()); assertEquals(WorksConstraint.class, constraints.get(0).getClass()); // Check that we can add more than 1 constraint and that ordering is // preserved Constraints.add(desc, AlsoWorks.class, NameConstraint.class); constraints = Constraints.getConstraints(desc, this.getClass() .getClassLoader()); assertEquals(3, constraints.size()); assertEquals(WorksConstraint.class, constraints.get(0).getClass()); assertEquals(AlsoWorks.class, constraints.get(1).getClass()); assertEquals(NameConstraint.class, constraints.get(2).getClass()); }
/** * Add a {@link Constraint} to the table with the given configuration * <p> * Each constraint, when added to the table, will have a specific priority, * dictating the order in which the {@link Constraint} will be run. A * {@link Constraint} added will run on the regionserver before those added to * the {@link HTableDescriptor} later. * * @param desc * table descriptor to the constraint to * @param constraint * to be added * @param conf * configuration associated with the constraint * @throws IOException * if any constraint could not be deserialized. Assumes if 1 * constraint is not loaded properly, something has gone terribly * wrong and that all constraints need to be enforced. */ public static void add(HTableDescriptor desc, Class<? extends Constraint> constraint, Configuration conf) throws IOException { enable(desc); long priority = getNextPriority(desc); addConstraint(desc, constraint, conf, priority++); updateLatestPriority(desc, priority); }
/** * Write the raw constraint and configuration to the descriptor. * <p> * This method takes care of creating a new configuration based on the passed * in configuration and then updating that with enabled and priority of the * constraint. * <p> * When a constraint is added, it is automatically enabled. */ private static void addConstraint(HTableDescriptor desc, Class<? extends Constraint> clazz, Configuration conf, long priority) throws IOException { writeConstraint(desc, serializeConstraintClass(clazz), configure(conf, true, priority)); }
/** * Change the whether the constraint (if it is already present) is enabled or * disabled. */ private static void changeConstraintEnabled(HTableDescriptor desc, Class<? extends Constraint> clazz, boolean enabled) throws IOException { // get the original constraint Pair<String, String> entry = getKeyValueForClass(desc, clazz); if (entry == null) { throw new IllegalArgumentException("Constraint: " + clazz.getName() + " is not associated with this table. You can't enable it!"); } // create a new configuration from that conf Configuration conf = readConfiguration(entry.getSecond()); // set that it is enabled conf.setBoolean(ENABLED_KEY, enabled); // write it back out writeConstraint(desc, entry.getFirst(), conf); }
/** * Test that Constraints are properly enabled, disabled, and removed * * @throws Exception */ @SuppressWarnings("unchecked") @Test public void testEnableDisableRemove() throws Exception { HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName())); // check general enabling/disabling of constraints // first add a constraint Constraints.add(desc, AllPassConstraint.class); // make sure everything is enabled assertTrue(Constraints.enabled(desc, AllPassConstraint.class)); assertTrue(desc.hasCoprocessor(ConstraintProcessor.class.getName())); // check disabling Constraints.disable(desc); assertFalse(desc.hasCoprocessor(ConstraintProcessor.class.getName())); // make sure the added constraints are still present assertTrue(Constraints.enabled(desc, AllPassConstraint.class)); // check just removing the single constraint Constraints.remove(desc, AllPassConstraint.class); assertFalse(Constraints.has(desc, AllPassConstraint.class)); // Add back the single constraint Constraints.add(desc, AllPassConstraint.class); // and now check that when we remove constraints, all are gone Constraints.remove(desc); assertFalse(desc.hasCoprocessor(ConstraintProcessor.class.getName())); assertFalse(Constraints.has(desc, AllPassConstraint.class)); }
/** * Check to see if the given constraint is enabled. * * @param desc * {@link HTableDescriptor} to check. * @param clazz * {@link Constraint} to check for * @return <tt>true</tt> if the {@link Constraint} is present and enabled. * <tt>false</tt> otherwise. * @throws IOException * If the constraint has improperly stored in the table */ public static boolean enabled(HTableDescriptor desc, Class<? extends Constraint> clazz) throws IOException { // get the kv Pair<String, String> entry = getKeyValueForClass(desc, clazz); // its not enabled so just return false. In fact, its not even present! if (entry == null) { return false; } // get the info about the constraint Configuration conf = readConfiguration(entry.getSecond()); return conf.getBoolean(ENABLED_KEY, false); }
@Test public void testConfigurationPreserved() throws Throwable { Configuration conf = new Configuration(); conf.setBoolean("_ENABLED", false); conf.setLong("_PRIORITY", 10); HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName())); Constraints.add(desc, AlsoWorks.class, conf); Constraints.add(desc, WorksConstraint.class); assertFalse(Constraints.enabled(desc, AlsoWorks.class)); List<? extends Constraint> constraints = Constraints.getConstraints(desc, this.getClass().getClassLoader()); for (Constraint c : constraints) { Configuration storedConf = c.getConf(); if (c instanceof AlsoWorks) assertEquals(10, storedConf.getLong("_PRIORITY", -1)); // its just a worksconstraint else assertEquals(2, storedConf.getLong("_PRIORITY", -1)); } }
/** * Test that when we update a constraint the ordering is not modified. * * @throws Exception */ @SuppressWarnings("unchecked") @Test public void testUpdateConstraint() throws Exception { HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName())); Constraints.add(desc, CheckConfigurationConstraint.class, CheckWasRunConstraint.class); Constraints.setConfiguration(desc, CheckConfigurationConstraint.class, CheckConfigurationConstraint.getConfiguration()); List<? extends Constraint> constraints = Constraints.getConstraints(desc, this.getClass().getClassLoader()); assertEquals(2, constraints.size()); // check to make sure the order didn't change assertEquals(CheckConfigurationConstraint.class, constraints.get(0) .getClass()); assertEquals(CheckWasRunConstraint.class, constraints.get(1).getClass()); }
/** * Read in the configuration from the String encoded configuration * * @param bytes * to read from * @return A valid configuration * @throws IOException * if the configuration could not be read */ private static Configuration readConfiguration(String bytes) throws IOException { return readConfiguration(Bytes.toBytes(bytes)); }
/** * Enable the given {@link Constraint}. Retains all the information (e.g. * Configuration) for the {@link Constraint}, but makes sure that it gets * loaded on the table. * * @param desc * {@link HTableDescriptor} to modify * @param clazz * {@link Constraint} to enable * @throws IOException * If the constraint cannot be properly deserialized */ public static void enableConstraint(HTableDescriptor desc, Class<? extends Constraint> clazz) throws IOException { changeConstraintEnabled(desc, clazz, true); }
@Override public void start(CoprocessorEnvironment environment) { // make sure we are on a region server if (!(environment instanceof RegionCoprocessorEnvironment)) { throw new IllegalArgumentException( "Constraints only act on regions - started in an environment that was not a region"); } RegionCoprocessorEnvironment env = (RegionCoprocessorEnvironment) environment; TableDescriptor desc = env.getRegion().getTableDescriptor(); // load all the constraints from the HTD try { this.constraints = Constraints.getConstraints(desc, classloader); } catch (IOException e) { throw new IllegalArgumentException(e); } if (LOG.isInfoEnabled()) { LOG.info("Finished loading " + constraints.size() + " user Constraints on table: " + desc.getTableName()); } }
/** * Write the given key and associated configuration to the * {@link HTableDescriptor} */ private static void writeConstraint(HTableDescriptor desc, String key, Configuration conf) throws IOException { // store the key and conf in the descriptor desc.setValue(key, serializeConfiguration(conf)); }
/** * Check to see if the Constraint is currently set. * * @param desc * {@link HTableDescriptor} to check * @param clazz * {@link Constraint} class to check for. * @return <tt>true</tt> if the {@link Constraint} is present, even if it is * disabled. <tt>false</tt> otherwise. */ public static boolean has(HTableDescriptor desc, Class<? extends Constraint> clazz) { return getKeyValueForClass(desc, clazz) != null; }
throws IOException, IllegalArgumentException { Pair<String, String> e = getKeyValueForClass(desc, clazz); Configuration internal = readConfiguration(e.getSecond()); writeConstraint(desc, e.getFirst(), conf);
/** * Write the raw constraint and configuration to the descriptor. * <p> * This method takes care of creating a new configuration based on the passed * in configuration and then updating that with enabled and priority of the * constraint. * <p> * When a constraint is added, it is automatically enabled. */ private static void addConstraint(HTableDescriptor desc, Class<? extends Constraint> clazz, Configuration conf, long priority) throws IOException { writeConstraint(desc, serializeConstraintClass(clazz), configure(conf, true, priority)); }
/** * Test that Constraints are properly enabled, disabled, and removed * * @throws Exception */ @SuppressWarnings("unchecked") @Test public void testEnableDisableRemove() throws Exception { HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName())); // check general enabling/disabling of constraints // first add a constraint Constraints.add(desc, AllPassConstraint.class); // make sure everything is enabled assertTrue(Constraints.enabled(desc, AllPassConstraint.class)); assertTrue(desc.hasCoprocessor(ConstraintProcessor.class.getName())); // check disabling Constraints.disable(desc); assertFalse(desc.hasCoprocessor(ConstraintProcessor.class.getName())); // make sure the added constraints are still present assertTrue(Constraints.enabled(desc, AllPassConstraint.class)); // check just removing the single constraint Constraints.remove(desc, AllPassConstraint.class); assertFalse(Constraints.has(desc, AllPassConstraint.class)); // Add back the single constraint Constraints.add(desc, AllPassConstraint.class); // and now check that when we remove constraints, all are gone Constraints.remove(desc); assertFalse(desc.hasCoprocessor(ConstraintProcessor.class.getName())); assertFalse(Constraints.has(desc, AllPassConstraint.class)); }
/** * Check to see if the given constraint is enabled. * * @param desc * {@link HTableDescriptor} to check. * @param clazz * {@link Constraint} to check for * @return <tt>true</tt> if the {@link Constraint} is present and enabled. * <tt>false</tt> otherwise. * @throws IOException * If the constraint has improperly stored in the table */ public static boolean enabled(HTableDescriptor desc, Class<? extends Constraint> clazz) throws IOException { // get the kv Pair<String, String> entry = getKeyValueForClass(desc, clazz); // its not enabled so just return false. In fact, its not even present! if (entry == null) { return false; } // get the info about the constraint Configuration conf = readConfiguration(entry.getSecond()); return conf.getBoolean(ENABLED_KEY, false); }
@Test public void testConfigurationPreserved() throws Throwable { Configuration conf = new Configuration(); conf.setBoolean("_ENABLED", false); conf.setLong("_PRIORITY", 10); HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName())); Constraints.add(desc, AlsoWorks.class, conf); Constraints.add(desc, WorksConstraint.class); assertFalse(Constraints.enabled(desc, AlsoWorks.class)); List<? extends Constraint> constraints = Constraints.getConstraints(desc, this.getClass().getClassLoader()); for (Constraint c : constraints) { Configuration storedConf = c.getConf(); if (c instanceof AlsoWorks) assertEquals(10, storedConf.getLong("_PRIORITY", -1)); // its just a worksconstraint else assertEquals(2, storedConf.getLong("_PRIORITY", -1)); } }