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 }