Package com.prodeagle.java.counters

Source Code of com.prodeagle.java.counters.CounterNamesManager

/*
* Copyright 2011 PA Consulting Ltd
*
* Licensed 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 com.prodeagle.java.counters;


import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import com.google.appengine.api.NamespaceManager;
import com.google.appengine.api.datastore.AsyncDatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.prodeagle.java.DatastoreManager;
import com.prodeagle.java.ProdEagleConstants;
import com.prodeagle.java.DatastoreManager.ResultType;

/**
* Helper functions and utilities that help with the management
* of counters by storing and receiving values into MemCache
* @author Edward Hartwell Goose
*
*/
public class CounterNamesManager implements ProdEagleConstants {
 
  private static final Logger _logger = Logger.getLogger(CounterNamesManager.class.getName());
 
  /**
   * The maximum difference between two slots
   */
  private static final int MAX_CLOCK_SKEW = 1000 * 60; //60 seconds
 
  private Long lastUpdate;
  /**
   * The set of counter names known to the instance
   */
  private Set<String> knownCounterNames;
  /**
   * The id (key) of the last shard of counter names
   */
  private Long lastShard;
 
  public CounterNamesManager() {
    lastUpdate = null;
    knownCounterNames = new HashSet<String>();
    lastShard = null;
  }

  /**
   * Get all the counter names from the datastore
   * @return - a set of all the counter names
   */
  public Set<String> allCounterNames() {
    String originalNamespace = NamespaceManager.get();
   
    try {
      NamespaceManager.set(NAMESPACE);
     
      AsyncDatastoreService asyncDatastoreService = DatastoreServiceFactory.getAsyncDatastoreService();
     
      Query query = new Query("CounterNamesShard");
     
      if (null != this.lastUpdate) {
        Long now = new Date().getTime();
        query.addFilter("timestamp", FilterOperator.GREATER_THAN_OR_EQUAL, (now - (MAX_CLOCK_SKEW)));
      }
     
      PreparedQuery pq = asyncDatastoreService.prepare(query);
      Iterator<Entity> it = pq.asIterator();
     
      while (it.hasNext()) {
        Entity entity = it.next();
       
        @SuppressWarnings("unchecked")
        List<String> names = (List<String>) entity.getProperty("names");
        this.knownCounterNames.addAll(names);
       
        if (null == this.lastShard) {
          this.lastShard = entity.getKey().getId();
        } else {
          this.lastShard = Math.max(this.lastShard, entity.getKey().getId());
        }
       
        this.lastUpdate = new Date().getTime();
      }
     
      return this.knownCounterNames;
    } finally {
      NamespaceManager.set(originalNamespace);
    }
  }
 
  /**
   * Adds counters to the list of known counters (if they don't already exist)
   * @param names
   * @return - an object[] { Boolean, Long }, where the Boolean indicates if a read of the datastore was done
   * and the Long indicates how many counters were written to the database
   */
  public Object[] addIfNew(Collection<String> names) {
    String originalNamespace = NamespaceManager.get();

    try {
      NamespaceManager.set(NAMESPACE);
      Set<String> newNames = new HashSet<String>();
      Set<String> fresh = null;
     
      for (String name : names) {
        if (!this.knownCounterNames.contains(name)) {
          if (null == fresh) {
            fresh = this.allCounterNames(); //retrieve all the counter names from the datastore
           
            if (!fresh.contains(name)) {
              newNames.add(name);
            }
          } else {
            newNames.add(name);
          }
        }
      }
     
      if (!newNames.isEmpty()) {
        _logger.info("There are " + newNames.size() + " new counters to add");
        if (null == this.lastShard) {
          Entity entity = DatastoreManager.getOrInsertCounterNamesShard(1);
          this.lastShard = entity.getKey().getId();
        }
       
        DatastoreManager.ResultType result = DatastoreManager.addNames(this.lastShard, newNames);
       
        _logger.info("Adding names returned: " + result.toString());
       
        if (result.equals(ResultType.ADD_FULL)) {
          DatastoreManager.getOrInsertCounterNamesShard(this.lastShard + 1);
          addIfNew(names);
        }
       
        if (result.equals(ResultType.ADD_SUCCESS)) {
          _logger.info(newNames.size() + " counters have been added");
        } else {
          _logger.warning("Couldn't register counter names. Will retry next time. Numbers of counters: " + newNames.size());
        }
      }
     
      Boolean b = (null != fresh);
     
      return new Object[] { b, Long.valueOf(newNames.size()) };
    } finally {
      NamespaceManager.set(originalNamespace);
    }
  }
}
TOP

Related Classes of com.prodeagle.java.counters.CounterNamesManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.