001 /** 002 * Copyright (c) 2010 Yahoo! Inc. All rights reserved. 003 * Licensed under the Apache License, Version 2.0 (the "License"); 004 * you may not use this file except in compliance with the License. 005 * You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software 010 * distributed under the License is distributed on an "AS IS" BASIS, 011 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 * See the License for the specific language governing permissions and 013 * limitations under the License. See accompanying LICENSE file. 014 */ 015 package org.apache.oozie.service; 016 017 import java.sql.Connection; 018 import java.util.HashMap; 019 import java.util.Map; 020 021 import org.apache.hadoop.conf.Configuration; 022 import org.apache.oozie.ErrorCode; 023 import org.apache.oozie.client.WorkflowJob; 024 import org.apache.oozie.service.SchemaService.SchemaName; 025 import org.apache.oozie.store.Store; 026 import org.apache.oozie.store.StoreException; 027 import org.apache.oozie.store.WorkflowStore; 028 import org.apache.oozie.util.Instrumentable; 029 import org.apache.oozie.util.Instrumentation; 030 import org.apache.oozie.util.XLog; 031 import org.apache.oozie.workflow.WorkflowLib; 032 import org.apache.oozie.workflow.lite.DBLiteWorkflowLib; 033 034 public class DBLiteWorkflowStoreService extends LiteWorkflowStoreService implements Instrumentable { 035 private boolean selectForUpdate; 036 private XLog log; 037 private int statusWindow; 038 039 public static final String CONF_PREFIX = Service.CONF_PREFIX + "DBLiteWorkflowStoreService."; 040 public static final String CONF_METRICS_INTERVAL_MINS = CONF_PREFIX + "status.metrics.collection.interval"; 041 public static final String CONF_METRICS_INTERVAL_WINDOW = CONF_PREFIX + "status.metrics.window"; 042 043 private static final String INSTRUMENTATION_GROUP = "jobstatus"; 044 private static final String INSTRUMENTATION_GROUP_WINDOW = "windowjobstatus"; 045 046 private Map<String, Integer> statusCounts = new HashMap<String, Integer>(); 047 private Map<String, Integer> statusWindowCounts = new HashMap<String, Integer>(); 048 049 /** 050 * Gets the number of workflows for each status and populates the hash. 051 */ 052 class JobStatusCountCallable implements Runnable { 053 @Override 054 public void run() { 055 WorkflowStore store = null; 056 try { 057 store = Services.get().get(WorkflowStoreService.class).create(); 058 store.beginTrx(); 059 WorkflowJob.Status[] wfStatusArr = WorkflowJob.Status.values(); 060 for (WorkflowJob.Status aWfStatusArr : wfStatusArr) { 061 statusCounts.put(aWfStatusArr.name(), store.getWorkflowCountWithStatus(aWfStatusArr.name())); 062 statusWindowCounts.put(aWfStatusArr.name(), store.getWorkflowCountWithStatusInLastNSeconds( 063 aWfStatusArr.name(), statusWindow)); 064 } 065 store.commitTrx(); 066 } 067 catch (StoreException e) { 068 if (store != null) { 069 store.rollbackTrx(); 070 } 071 log.warn("Exception while accessing the store", e); 072 } 073 catch (Exception ex) { 074 log.error("Exception, {0}", ex.getMessage(), ex); 075 if (store != null && store.isActive()) { 076 try { 077 store.rollbackTrx(); 078 } 079 catch (RuntimeException rex) { 080 log.warn("openjpa error, {0}", rex.getMessage(), rex); 081 } 082 } 083 } 084 finally { 085 if (store != null) { 086 if (!store.isActive()) { 087 try { 088 store.closeTrx(); 089 } 090 catch (RuntimeException rex) { 091 log.warn("Exception while attempting to close store", rex); 092 } 093 } 094 else { 095 log.warn("transaction is not committed or rolled back before closing entitymanager."); 096 } 097 } 098 } 099 } 100 } 101 102 public void init(Services services) throws ServiceException { 103 Configuration conf = services.getConf(); 104 statusWindow = conf.getInt(CONF_METRICS_INTERVAL_WINDOW, 3600); 105 int statusMetricsCollectionInterval = conf.getInt(CONF_METRICS_INTERVAL_MINS, 5); 106 log = XLog.getLog(getClass()); 107 selectForUpdate = false; 108 109 WorkflowJob.Status[] wfStatusArr = WorkflowJob.Status.values(); 110 for (WorkflowJob.Status aWfStatusArr : wfStatusArr) { 111 statusCounts.put(aWfStatusArr.name(), 0); 112 statusWindowCounts.put(aWfStatusArr.name(), 0); 113 } 114 Runnable jobStatusCountCallable = new JobStatusCountCallable(); 115 services.get(SchedulerService.class).schedule(jobStatusCountCallable, 1, statusMetricsCollectionInterval, 116 SchedulerService.Unit.MIN); 117 } 118 119 public void destroy() { 120 } 121 122 /** 123 * Return the workflow lib without DB connection. Will be used for parsing purpose. 124 * 125 * @return Workflow Library 126 */ 127 @Override 128 public WorkflowLib getWorkflowLibWithNoDB() { 129 return getWorkflowLib(null); 130 } 131 132 private WorkflowLib getWorkflowLib(Connection conn) { 133 javax.xml.validation.Schema schema = Services.get().get(SchemaService.class).getSchema(SchemaName.WORKFLOW); 134 return new DBLiteWorkflowLib(schema, LiteDecisionHandler.class, LiteActionHandler.class, conn); 135 } 136 137 @Override 138 public WorkflowStore create() throws StoreException { 139 try { 140 return new WorkflowStore(selectForUpdate); 141 } 142 catch (Exception ex) { 143 throw new StoreException(ErrorCode.E0600, ex.getMessage(), ex); 144 } 145 } 146 147 @Override 148 public <S extends Store> WorkflowStore create(S store) throws StoreException { 149 try { 150 return new WorkflowStore(store, selectForUpdate); 151 } 152 catch (Exception ex) { 153 throw new StoreException(ErrorCode.E0600, ex.getMessage(), ex); 154 } 155 } 156 157 158 @Override 159 public void instrument(Instrumentation instr) { 160 final WorkflowJob.Status[] wfStatusArr = WorkflowJob.Status.values(); 161 for (WorkflowJob.Status aWfStatusArr : wfStatusArr) { 162 final String statusName = aWfStatusArr.name(); 163 instr.addVariable(INSTRUMENTATION_GROUP, statusName, new Instrumentation.Variable<Long>() { 164 public Long getValue() { 165 return statusCounts.get(statusName).longValue(); 166 } 167 }); 168 instr.addVariable(INSTRUMENTATION_GROUP_WINDOW, statusName, new Instrumentation.Variable<Long>() { 169 public Long getValue() { 170 return statusWindowCounts.get(statusName).longValue(); 171 } 172 }); 173 } 174 } 175 }