docs: public static Deferred<Boolean> processAllTrees(final TSDB tsdb, 
        final TSMeta meta) {
  
      /**
       * Simple final callback that waits on all of the processing calls before
       * returning
       */
      final class FinalCB implements Callback<Boolean, 
        ArrayList<ArrayList<Boolean>>> {
        @Override
        public Boolean call(final ArrayList<ArrayList<Boolean>> groups) 
          throws Exception {
          return true;
        }
      }
  
      /**
       * Callback that loops through the local list of trees, processing the
       * TSMeta through each
       */
      final class ProcessTreesCB implements Callback<Deferred<Boolean>, 
        List<Tree>> {
        
        // stores the tree deferred calls for later joining. Lazily initialized
        ArrayList<Deferred<ArrayList<Boolean>>> processed_trees;
        
        @Override
        public Deferred<Boolean> call(List<Tree> trees) throws Exception {
          if (trees == null || trees.isEmpty()) {
            LOG.debug("No trees found to process meta through");
            return Deferred.fromResult(false);
          } else {
            LOG.debug("Loaded [" + trees.size() + "] trees");
          }
          
          processed_trees = 
            new ArrayList<Deferred<ArrayList<Boolean>>>(trees.size());
          for (Tree tree : trees) {
            if (!tree.getEnabled()) {
              continue;
            }
            final TreeBuilder builder = new TreeBuilder(tsdb, new Tree(tree));
            processed_trees.add(builder.processTimeseriesMeta(meta, false));
          }
          
          return Deferred.group(processed_trees).addCallback(new FinalCB());
        }
        
      }
      
      /**
       * Callback used when loading or re-loading the cached list of trees
       */
      final class FetchedTreesCB implements Callback<List<Tree>, List<Tree>> {
  
        @Override
        public List<Tree> call(final List<Tree> loaded_trees) 
          throws Exception {
          
          final List<Tree> local_trees;
          synchronized(trees) {
            trees.clear();
            for (final Tree tree : loaded_trees) {
              if (tree.getEnabled()) {
                trees.add(tree);
              }
            }
            
            local_trees = new ArrayList<Tree>(trees.size());
            local_trees.addAll(trees);
          }
          trees_lock.unlock();
          return local_trees;
        }
        
      }
  
      /**
       * Since we can't use a try/catch/finally to release the lock we need to 
       * setup an ErrBack to catch any exception thrown by the loader and
       * release the lock before returning
       */
      final class ErrorCB implements Callback<Object, Exception> {
  
        @Override
        public Object call(final Exception e) throws Exception {
          trees_lock.unlock();
          throw e;
        }
        
      }
      
      // lock to load or 
      trees_lock.lock();
      
      // if we haven't loaded our trees in a while or we've just started, load
      if (((System.currentTimeMillis() / 1000) - last_tree_load) > 300) {
        final Deferred<List<Tree>> load_deferred = Tree.fetchAllTrees(tsdb)
          .addCallback(new FetchedTreesCB()).addErrback(new ErrorCB());
        last_tree_load = (System.currentTimeMillis() / 1000);
        return load_deferred.addCallbackDeferring(new ProcessTreesCB());
      }
      
      // copy the tree list so we don't hold up the other threads while we're
      // processing
      final List<Tree> local_trees;
      if (trees.isEmpty()) {
        LOG.debug("No trees were found to process the meta through");
        trees_lock.unlock();
        return Deferred.fromResult(true);
      }
      
      local_trees = new ArrayList<Tree>(trees.size());
      local_trees.addAll(trees);
      
      // unlock so the next thread can get a copy of the trees and start
      // processing
      trees_lock.unlock();
      
      try {
        return new ProcessTreesCB().call(local_trees);
      } catch (Exception e) {
        throw new RuntimeException("Failed to process trees", e);
      }
    }