Archiver Appliance 事务处理流程

2023-05-16

当 Archiver Appliance 开始运行后发生了什么:

mgmt服务:

config\DefaultConfigService.java

initialize()   {
	this.mgmtRuntime = new MgmtRuntimeState(this);
	
	
	startupExecutor = Executors.newScheduledThreadPool(1, new ThreadFactory() {
		@Override
		public Thread newThread(Runnable r) {
			Thread t = new Thread(r);
			t.setName("Startup executor");
			return t;
		}
	});
	
	
	MgmtPostStartup mgmtPostStartup = new MgmtPostStartup(this);
	ScheduledFuture<?> postStartupFuture = startupExecutor.scheduleAtFixedRate(mgmtPostStartup, 10, 20, TimeUnit.SECONDS);
	mgmtPostStartup.setCancellingFuture(postStartupFuture);
}

创建 mgmt 状态机 —— MgmtRuntimeState;
定期执行 mgmt 后处理 —— MgmtPostStartup。

mgmt\MgmtPostStartup.java

public MgmtPostStartup(ConfigService configService) {
	this.configService = configService;
}

	
@Override
public void run() {
	if(this.configService.isStartupComplete()) {
		this.checkIfAllComponentsHaveStartedUp();
		if(this.configService.getMgmtRuntimeState().haveChildComponentsStartedUp()) { 
			cancellingFuture.cancel(false);
		}
	} else {
		configService.postStartup();
	}
}


checkIfAllComponentsHaveStartedUp() { 
	if(retrievalStartupState == ConfigService.STARTUP_SEQUENCE.STARTUP_COMPLETE) { 
		configService.getMgmtRuntimeState().componentStartedUp(WAR_FILE.RETRIEVAL);
	}
	... // etl 和 engine
}

定期执行的 mgmt 后处理包括:
若 configService 未完成,则执行 configService.postStartup() ;
若 configService 已完成,检查 mgmt、engine、etl、retrieval 四个服务是否都启动成功;
每个服务启动成功时,都会更新 mgmt 状态机中已启动服务列表;
若四个服务都成功启动,则开始存储 PV 值 —— startArchivePVRequests()。

config\DefaultConfigService.java

/*
 * config\DefaultConfigService.java
 */


postStartup() {
	Config config = new XmlConfigBuilder().build();
	...
	hzinstance = Hazelcast.newHazelcastInstance(config);  // 建立集群信息

	pubSub = hzinstance.getTopic("pubSub");

	initializePersistenceLayer();						// 初始化 MySQL 数据库中存储的 PV 信息
	loadTypeInfosFromPersistence();		
	loadAliasesFromPersistence();
	loadArchiveRequestsFromPersistence();			
	loadExternalServersFromPersistence();			
	registerForNewExternalServers(hzinstance.getMap("channelArchiverDataServers"));
			
	eventBus.register(this);  							 // 事务通知
	pubSub.addMessageListener(new MessageListener<PubSubEvent>() {
			@Override
			public void onMessage(Message<PubSubEvent> pubSubEventMsg) {
				PubSubEvent pubSubEvent = pubSubEventMsg.getMessageObject();
				if(pubSubEvent.getDestination().equals("ALL") 
					|| (pubSubEvent.getDestination().startsWith(myIdentity) && pubSubEvent.getDestination().endsWith(DefaultConfigService.this.warFile.toString()))
					) {
						pubSubEvent.markSourceAsCluster();
						eventBus.post(pubSubEvent);	
				}				
	});
	
	this.startupState = STARTUP_SEQUENCE.STARTUP_COMPLETE;
}

将数据库中存储的 PV 信息加载到当前环境;
建立集群信息、事务通知机制:
集群中某个appliance发送消息后,先通过 PubSubEvent 推送到集群,该消息的目的appliance收到并发现是发给自己的某个服务的消息后,再通过 eventBus 推送到本地。

initializePersistenceLayer() throws ConfigException {
	persistanceLayer = new MySQLPersistence();			// 与 MySQL 交互的接口
}

mgmt\MgmtRuntimeState.java

private static int threadNumber = 1;
ScheduledExecutorService archivePVWorkflow = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
	@Override
	public Thread newThread(Runnable r) {
		Thread t = new Thread(r);
		t.setName("MgmtArchivePVWorkflow" + threadNumber++);
		return t;
	}
});


public MgmtRuntimeState(final ConfigService configService) {
	this.configService = configService;
	myIdentity = this.configService.getMyApplianceInfo().getIdentity();
	...
	configService.getEventBus().register(this);
}


componentStartedUp(WAR_FILE component) { 
	componentsThatHaveCompletedStartup.add(component);
	if(this.haveChildComponentsStartedUp()) { 
		this.startArchivePVRequests();					// 若四个服务都成功启动,则开始存储 PV 值
	}
}


private void startArchivePVRequests() { 
	// 对数据库 ArchivePVRequests 表中的 PV 开始存储流程
	for(String pvNameFromPersistence : configService.getArchiveRequestsCurrentlyInWorkflow()) {
			this.startPVWorkflow(pvNameFromPersistence);
	}
		
	startArchivePVWorkflow(initialDelayInSeconds);
}


// 单个 PV 的存储流程开始
startPVWorkflow()   {
	ArchivePVState pvState = new ArchivePVState(pvName, configService);		// 创建单个 PV 的存储状态机
	currentPVRequests.put(pvName, pvState);
}


// 对 currentPVRequests 中最多前 archivePVWorkflowBatchSize 个 PV 定期执行 runWorkFlowForPV.nextStep();
private void startArchivePVWorkflow() {
	theArchiveWorkflow = archivePVWorkflow.scheduleAtFixedRate(new Runnable() {		
		@Override
		public void run() {
			LinkedList<ArchivePVState> archivePVStates = new LinkedList<ArchivePVState>(currentPVRequests.values());
			int totRequests = archivePVStates.size();
			int maxRequestsToProcess = Math.min(archivePVWorkflowBatchSize, totRequests);
			int pvCount = 0;
			while(pvCount < maxRequestsToProcess) { 
				ArchivePVState runWorkFlowForPV = archivePVStates.pop();
				runWorkFlowForPV.nextStep();   // 推动Archive PV步骤进程
				pvCount++;
			}					
	}, initialDelayInSeconds, archivePVWorkflowTickSeconds, TimeUnit.SECONDS);
}

在四个服务都成功启动、开始存储 PV 值后,执行:
对数据库 ArchivePVRequests 表中的 PV 开始存储流程;
定期对 currentPVRequests 中最多前 archivePVWorkflowBatchSize 个 PV 的存储状态机执行状态更新操作。

当在web端点击”Archive PV”后发生了什么:

mgmt\BPLServlet.java:

doPost()   {
	BasicDispatcher.dispatch(req, resp, configService, postActions);
}

common\BasicDispatcher.java:

dispatch()    {
	action = actionClass.getConstructor().newInstance();   // ArchivePVAction.class
	action.execute(req, resp, configService);
}

mgmt\bpl\ArchivePVAction.java

execute()    {
	archivePV(out, pv, samplingPeriodSpecified, samplingMethod, samplingPeriod, controllingPV, policyName, null, skipCapacityPlanning, configService, fieldsAsPartOfStream);
}

archivePV()   {
	configService.addToArchiveRequests(actualPVName, userSpecifiedSamplingParams);
	configService.getMgmtRuntimeState().startPVWorkflow(pvName);
}

config\DefaultConfigService.java

archivePVRequests = hzinstance.getMap("archivePVRequests");

addToArchiveRequests()   {
	archivePVRequests.put(pvName, userSpecifiedSamplingParams);
	persistanceLayer.putArchivePVRequest(pvName, userSpecifiedSamplingParams);
}

mgmt\MgmtRuntimeState.java

startPVWorkflow()   {
	ArchivePVState pvState = new ArchivePVState(pvName, configService);		// 创建单个 PV 的存储状态机
	currentPVRequests.put(pvName, pvState);
}

mgmt\archivepv\ArchivePVState.java

private ArchivePVStateMachine currentState = ArchivePVStateMachine.START;

public ArchivePVState(String pvName, ConfigService configService) {
	this.myIdentity = this.configService.getMyApplianceInfo().getIdentity();
	this.fieldsArchivedAsPartOfStream = configService.getFieldsArchivedAsPartOfStream();
}

public synchronized void nextStep() {
	switch(currentState) {
		case START: {												// [1]
			PubSubEvent pubSubEvent = new PubSubEvent("ComputeMetaInfo", myIdentity + "_" + ConfigService.WAR_FILE.ENGINE, pvName);
			...  // userSpec
			pubSubEvent.setEventData(encoder.encode(userSpec).toJSONString());
			configService.getEventBus().post(pubSubEvent);
			currentState = ArchivePVStateMachine.METAINFO_REQUESTED;
			return;	
		}
		case METAINFO_REQUESTED: {									// [1]
			logger.debug("A request to gather metainfo has been published for the PV " + pvName);
			return;
		}
		case METAINFO_GATHERING: {									// [4]
			logger.debug("Metainfo has been requested and is being gathered for " + pvName);
			return;
		}
		case METAINFO_OBTAINED: {  									// [7]
			PolicyConfig thePolicy = configService.computePolicyForPV(pvName, metaInfo, userSpec);
			...			// 设置该 PV 的存储策略
			PVTypeInfo typeInfo = new PVTypeInfo(pvName, metaInfo.getArchDBRTypes(), !metaInfo.isVector(), metaInfo.getCount());
			...			// 设置该 PV 的基本信息:metaInfo、thePolicy、CreationTime、aliasFieldName、applianceInfoForPV 等
			ApplianceInfo applianceInfoForPV = null;
			...			// 设置该 PV 所属的 appliance
			configService.registerPVToAppliance(pvName, applianceInfoForPV);		// pv2appliancemapping.put(pvName, applianceInfo);
			typeInfo.setApplianceIdentity(applianceIdentityAfterCapacityPlanning);
			configService.updateTypeInfoForPV(pvName, typeInfo);			// typeInfos.put(pvName, typeInfo);
			currentState = ArchivePVStateMachine.POLICY_COMPUTED;
			return;
		}
		case POLICY_COMPUTED: { 									// [8]
			PVTypeInfo typeInfo = configService.getTypeInfoForPV(pvName);
			if(typeInfo.getApplianceIdentity().equals(applianceIdentityAfterCapacityPlanning)) {
				currentState = ArchivePVStateMachine.TYPEINFO_STABLE;
			}
			return;
		}
		case TYPEINFO_STABLE: { 									// [9]
			PVTypeInfo typeInfo = configService.getTypeInfoForPV(pvName);
			// 开始存储 PV
			ArchivePVState.startArchivingPV(pvName, configService, configService.getAppliance(typeInfo.getApplianceIdentity()));
			registerAliasesIfAny(typeInfo);
			currentState = ArchivePVStateMachine.ARCHIVE_REQUEST_SUBMITTED;
			return;
		}
		case ARCHIVE_REQUEST_SUBMITTED: 							// [9]
			// The part in mgmt is basically over; we are waiting for the engine to indicate that it has commenced archiving
			// Until then, we stay in this state.
			return;
		case ARCHIVING: {											// [12]	
			configService.archiveRequestWorkflowCompleted(pvName);
			configService.getMgmtRuntimeState().finishedPVWorkflow(pvName);
			currentState = ArchivePVStateMachine.FINISHED;
			return;
		}
		case ABORTED: {
			configService.archiveRequestWorkflowCompleted(pvName);
			configService.getMgmtRuntimeState().finishedPVWorkflow(pvName);
			currentState = ArchivePVStateMachine.FINISHED;
			return;
		}
		case FINISHED: {											// [13]	
			logger.error("Archive state for PV " + this.pvName + " is finished.");
			return;
		}
	}
}
public void metaInfoRequestAcknowledged() { 							// [4]
	metaInfoRequestedSubmitted = TimeUtils.now();
	this.currentState = ArchivePVStateMachine.METAINFO_GATHERING;
}

public void metaInfoObtained(MetaInfo metaInfo) {  						// [7]
	this.metaInfo = metaInfo;
	this.currentState = ArchivePVStateMachine.METAINFO_OBTAINED;
}

public static void startArchivingPV() throws IOException {				// [9]
	PubSubEvent pubSubEvent = new PubSubEvent("StartArchivingPV", applianceInfoForPV.getIdentity()  + "_" + ConfigService.WAR_FILE.ENGINE, pvName);
	configService.getEventBus().post(pubSubEvent);
}

public void confirmedStartedArchivingPV() {								// [12]	
	this.currentState = ArchivePVStateMachine.ARCHIVING;
}

对单个 PV 的存储流程主要分两大部分:
创建 PV 通道,元数据信息获取;
开始执行数据存储。
TYPEINFO_STABLE 和 ARCHIVE_REQUEST_SUBMITTED 这两个状态,是这两大部分的分界点。

若 ”Archive PV” 不成功,或者成功后出现 PV unconnected 等错误情况,应首先定位问题属于这两大部分的哪一部分,再去具体定位问题。

关于 applianceInfoForPV 的设置过程,详见 Archiver Appliance 建立集群时可能出现的问题 。

engine\pv\EngineContext.java

@Subscribe public void computeMetaInfo(PubSubEvent pubSubEvent) {
	if(pubSubEvent.getType().equals("ComputeMetaInfo")) {				// [2]
		// 通过 MetaGet 创建 PV 通道,添加事件监听,获取 PV 元数据信息
		ArchiveEngine.getArchiveInfo(pvName, configService, extraFields, userSpec.isUsePVAccess(), new ArchivePVMetaCompletedListener(pvName, configService, myIdentity));
		// 对 mgmt 提出的 ComputeMetaInfo 操作进行应答	
		PubSubEvent confirmationEvent = new PubSubEvent("MetaInfoRequested", pubSubEvent.getSource() + "_" + ConfigService.WAR_FILE.MGMT, pvName);
		configService.getEventBus().post(confirmationEvent);
	} else if(pubSubEvent.getType().equals("StartArchivingPV")) {		// [10]
		String pvName = pubSubEvent.getPvName();
		this.startArchivingPV(pvName);				// 开始存储 PV
											
		PubSubEvent confirmationEvent = new PubSubEvent("StartedArchivingPV", pubSubEvent.getSource() + "_" + ConfigService.WAR_FILE.MGMT, pvName);
		configService.getEventBus().post(confirmationEvent);
		
	} else if(pubSubEvent.getType().equals("AbortComputeMetaInfo")) {
		String pvName = pubSubEvent.getPvName();
		this.abortComputeMetaInfo(pvName);
	}
}
private void startArchivingPV(String pvName) {							// [10]
	PVTypeInfo typeInfo = configService.getTypeInfoForPV(pvName);
	...		// 获取 dbrType、firstDest、samplingMethod、samplingPeriod、secondsToBuffer、lastKnownTimeStamp、controllingPV、archiveFields 等信息
	ArchiveEngine.archivePV(pvName, samplingPeriod, samplingMethod, secondsToBuffer, firstDest, configService, dbrType, lastKnownTimeStamp, controllingPV, archiveFields, typeInfo.getHostName(), typeInfo.isUsePVAccess(), typeInfo.isUseDBEProperties()); 
	}

engine\ArchiveEngine.java

public static void getArchiveInfo(final String pvName,
			final ConfigService configservice, final String metadatafields[], boolean usePVAccess,
			final MetaCompletedListener metaListener) throws Exception {
	MetaGet metaget = new MetaGet(pvName, configservice, metadatafields, usePVAccess, metaListener);
	metaget.initpv();
}
public static void archivePV() {										// [10]
	ArchiveEngine.createChannels4PVWithMetaField(pvName, samplingPeriod, mode, secondstoBuffer, writer,
		configservice, archdbrtype, lastKnownEventTimeStamp, start, null, metaFieldNames, iocHostName, usePVAccess, useDBEProperties);
}

private static void createChannels4PVWithMetaField() {
	ArchiveChannel channel = ArchiveEngine.addChannel(pvName, writer, Enablement.Enabling, scan_mode2, 
		lastKnownEventTimeStamp,configservice, archdbrtype, controlPVname, iocHostName, usePVAccess);
	channel.initializeMetaFieldPVS(metaFields, configservice, usePVAccess, useDBEProperties);
}

private static ArchiveChannel addChannel() {
	...		// Determine buffer capacity
	int JCACommandThreadID = engineContext.assignJCACommandThread(name, iocHostName);
	// Create new channel
	if (sample_mode.isMonitor()) {
		if (sample_mode.getDelta() > 0) {
			channel = new DeltaArchiveChannel(name, writer, enablement, buffer_capacity, last_sampleTimestamp, pvSamplingPeriod, sample_mode.getDelta(),configservice, archdbrtype, controlPVname, JCACommandThreadID, usePVAccess);
		} else { 
			channel = new MonitoredArchiveChannel(name, writer, enablement, buffer_capacity, last_sampleTimestamp, pvSamplingPeriod, configservice, archdbrtype, controlPVname, JCACommandThreadID, usePVAccess);
		}
	} else {
		channel = new ScannedArchiveChannel(name, writer, enablement, buffer_capacity, last_sampleTimestamp, pvSamplingPeriod, configservice, archdbrtype, controlPVname, JCACommandThreadID, usePVAccess);
	}
	configservice.getEngineContext().getChannelList().put(channel.getName(), channel);
	engineContext.getWriteThead().addChannel(channel);
	return channel;
}

engine\metadata\MetaGet.java

initpv() throws Exception {
	int jcaCommandThreadId = configservice.getEngineContext().assignJCACommandThread(pvName, null);
	PV pv = PVFactory.createPV(pvName, configservice, jcaCommandThreadId, usePVAccess);
	pv.addListener(new PVListener() {
		@Override
		public void pvValueUpdate(PV pv, DBRTimeEvent ev) {}
		@Override
		public void pvDisconnected(PV pv) {}
		@Override
		public void pvConnected(PV pv) {
			...
		}
		@Override
		public void pvConnectionRequestMade(PV pv) {}
		@Override
		public void sampleDroppedTypeChange(PV pv, ArchDBRTypes newDBRtype) {}
	});
	pvList.put("main", pv);
	pv.start();					// 连接 PV
			
	class FieldListener implements PVListener {
		...
	}
}

@Override
public void run() {
	...		// 获取 PV 元数据信息
	metaListener.completed(mainMeta);		// 告诉 ArchivePVMetaCompletedListener 已经完成 PV 元数据信息获取
																			// [5]
}

创建 PV 通道,添加事件监听,获取 PV 元数据信息。

engine\pv\EngineContext.java

static class ArchivePVMetaCompletedListener implements MetaCompletedListener {
	@Override
	public void completed(MetaInfo metaInfo) {								// [5]
		PubSubEvent confirmationEvent = new PubSubEvent("MetaInfoFinished", myIdentity + "_" + ConfigService.WAR_FILE.MGMT, pvName);
		confirmationEvent.setEventData(JSONValue.toJSONString(metaInfoObj));
		configService.getEventBus().post(confirmationEvent);
	}
}

mgmt\MgmtRuntimeState.java

@Subscribe public void computeMetaInfo(PubSubEvent pubSubEvent) {
	if(pubSubEvent.getType().equals("MetaInfoRequested")) {					// [3]
		String pvName = pubSubEvent.getPvName();
		ArchivePVState pvState = currentPVRequests.get(pvName);
		pvState.metaInfoRequestAcknowledged();
	} else if (pubSubEvent.getType().equals("MetaInfoFinished")) {			// [6]
		String pvName = pubSubEvent.getPvName();
		ArchivePVState pvState = currentPVRequests.get(pvName);
		MetaInfo metaInfo = new MetaInfo();
		decoder.decode(metaInfoObj, metaInfo);
		pvState.metaInfoObtained(metaInfo);
	} else if (pubSubEvent.getType().equals("StartedArchivingPV")) {		// [11]
		String pvName = pubSubEvent.getPvName();
		pvState.confirmedStartedArchivingPV();
	}
}			
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Archiver Appliance 事务处理流程 的相关文章

  • 【docker ros】docker 开启自启运行容器中的程序

    前言 xff1a 使用docker大规模部署应用 xff0c 而又需要开机自启 xff0c 自动启动容器中的程序 xff0c 这里以docker ros为例子 xff0c 使用systemctl服务 xff0c 结合shell脚本 xff0
  • 网络协议与网络编程(双电脑串口通讯)

    C C 43 43 网络编程 双电脑串口通讯 在阅读本文前 请确保先查看这篇文章 xff0c 学习有关TCP网编与单电脑信息传输实践 文章目录 C C 43 43 网络编程 双电脑串口通讯 1 让两台电脑连接同一个局域网2 查询IP地址3
  • Linux shell的数组详解

    Linux shell的数组详解 前提变量数组数组声明声明索引数组声明关联数组 数组赋值数组引用数组中常用的变量数组中的其它操作 示例 前提 程序是指 指令 43 数据 的组合 指令 xff1a bash脚本中的代码 xff08 函数 调用
  • cannot find trajectory file at ./examples/trajectory.txt

    slam十四讲 3 7显示运动轨迹的程序 trajectory txt文件路径修改 string trajectory file 61 34 examples trajectory txt 34 改为 string trajectory f
  • slam14讲,李代数库Sophus遇到的问题及解决办法

    首先遇到sophus安装问题是在第4章时 xff0c 高博虽然书上说 我们使用带模板的Sophus库 xff0c 但实际的代码使用的是非模板库 高博在git上给的sophus库文件我在make的时候报错 xff0c 找不到解决办法 xff0
  • PX4添加新的msg和topic

    本人也是初次接触PX4固件没几天 xff0c 学习了msg的一些知识后写下这个以供自己以后参考 一 首先在 PX4 Autopilot msg文件夹下新建一个 msg文件 xff1a 这里我添加的是Data link msg msg 在 m
  • 物理机安装LINUX后的网卡配置问题

    基础材料 xff1a CentOS7 物理服务器 背景说明 xff1a 安装完LINUX操作系统的网卡配置让主机连通网络 xff0c 对于系统管理员来说是再常见不过的事情 xff0c 而且基本上也没什么难度 xff0c 但凡做过系统管理员的
  • PX4添加新的库(lib)

    就在前一两天 xff0c PX4源代码更新了 xff0c 固件库的名称从Firmware变成了PX4 Autopilot 一 首先在lib下新建一个文件夹并添加 cpp hpp和CMakeLists txt 其中 cpp和 hpp是自己写的
  • PX4添加新的应用

    研究了四天怎么添加新的应用程序 xff0c 前几天都尝试着添加 cpp文件的应用程序 xff0c 跟着网上的方法都失败了 xff0c 结果今天试着添加一个 c文件的应用程序居然成功了 先把 c的添加方法写一写 xff0c 以后学会了怎么添加
  • PX4应用程序开机自启动

    修改启动脚本 新版本的PX4固件这些rc文件位置为 xff1a PX4 Autopilot ROMFS px4fmu common init d文件夹中 1 以rc为开头的都是飞控的启动脚本的文件 xff0c 通过这些文件决定那些应用程序应
  • 自由链表(free list)——SGI STL的空间配置器(allocator)第二级配置器维护方法

    参考 xff1a STL源码剖析 以及 STL空间配置器之第二级配置器的free list详解 span class token comment free list的节点 span span class token keyword unio
  • 【C语言 Linux系统开发 视频课程学习笔记】

    学习的课程在b站 xff1a 史上最强最细腻的linux嵌入式C语言学习教程 李慧芹老师 感谢李老师 xff01 感谢up主 xff01 本篇博客只是收集一下学习过程中遇到的函数和其他知识点 xff0c 并不会详细展开 某个函数的具体情况还
  • pthread线程私有数据TSD 几点测试结果

    更加详细的内容查看man手册或百度 xff0c 这里只是几个实际测试的结果 仅代表实验现象 xff0c 并不考虑实现原理 pthread key t key可以定义为全局变量 xff0c 全局变量属于所有线程共有的 在不同的线程中可以用pt
  • 【muduo库】server端流程图

    1 首先是根据陈硕老师的muduo库手册p11的类图 xff0c 结合自己的学习所得画的一个更详细的流程 xff0c 使用IO线程池与计算线程池 xff08 1 xff09 计算线程中 xff0c task 调用TcpConnection
  • std::bind实现在类外访问类私有成员函数

    span class token macro property span class token directive hash span span class token directive keyword include span spa
  • 树莓派(linux)安装scipy

    这里写目录标题 成功案例失败案例1 xff08 使用pip直接安装 xff09 失败案例2 xff08 使用pip安装依赖 xff09 命令安装yum使用alien 失败案例3 xff08 whl 43 setup py安装 xff09 查
  • 计算机的基本组成

    一个完整的计算机系统包括硬件系统和软件系统两大部分 xff1a 硬件系统 xff1a 是我们肉眼所见的实体 如 xff1a 电源 显示器 主机箱等 软件系统 xff1a 是我们使用的程序 xff0c 如 xff1a 微信 QQ音乐 浏览器等
  • pycharm关闭拼写检查

    pycharm默认会对函数名 xff0c 类名进行拼写检查 xff0c 不符合规则的会有一些提示和警告 xff0c 虽然不会影响程序运行 xff0c 但是看着还是比较不爽 xff0c 所以写一下关闭拼写检查的方法 打开pycharm xff

随机推荐

  • ROS基础——tf相关

    service和srv 我们有一个节点A会计算出右臂逆向关节运动学坐标 xff0c 我们有一个节点B xff0c 不会经常用到 xff0c 但是偶尔会用到节点A的这个坐标 假设我们用主题来通信 xff0c 那么我们的节点A要不停的来发布消息
  • EPICS的学习过程

    在此之前 xff0c 最好先学习下Linux系统的基本操作 一 了解什么是EPICS 了解EPICS base Channel Access IOC OPI 的概念 高能所内网可参考这些材料 xff1b 打开USPAS xff0c 熟悉其大
  • CentOS 7下ArchiveViewer的安装与使用

    1 下载 安装jdk 下载安装包https www oracle com java technologies downloads java8 xff1b 解压 xff1b 将 JAVA HOME bin路径添加到 PATH中 注意 xff1
  • CentOS7 安装 Archiver Appliance 的 Grafana服务

    1 安装 Grafana 7 采用rpm的安装方式 xff1a span class token function wget span https dl grafana com enterprise release grafana ente
  • AA中策略文件的使用

    一 AA策略文件 AA中关于存储策略设置的文件主要有两个 xff1a policies py archappl properties 每个appliance只有一个archappl properties和policies py文件 xff0
  • AA的管理

    1 AA的整体代码结构 AA代码的设计遵循了MVC模式 xff0c 将模型层 xff08 数据端 xff09 视图层 xff08 web客户端 xff09 控制层分离 数据端 xff08 M xff09 利用StoragePlugin接口建
  • CentOS 7下 VNC 服务的配置和开启、常见问题

    文章目录 1 X server Xvnc 和 VNC serverX Window SystemX ServerX ClientX Window ManagerDisplay ManagerX Window启动方式方式一 xff1a sta
  • AA部署中,修改Context属性造成的问题

    此处利用了https github com jeonghanlee epicsarchiverap env将AA安装在 opt epicsarchiverap 下 xff0c 并以系统服务的方式启停 问题产生原因 地球人都知道 xff0c
  • CentOS 7 下安装 Olog-es(Phoebus-olog)

    介绍报告 Olog es 服务端安装包 GitHub Olog phoebus olog Online logbook for experimental and industrial logging web服务端安装包 GitHub Olo
  • 视频监控系统安装和使用过程中的常见问题

    1 视频卡顿 花屏 当已确定POE供电距离在何时范围内时 xff0c 有可能是网线接线不规范或是网线损坏导致 对于POE供电距离较远 网络带宽较大的 xff0c 尽量连接在POE交换机的红口 xff08 红口保障 xff09 2 NVR的初
  • 关于CIDR地址的计算方法

    CIDR无类域间路由 xff0c 打破了原本的ABC类地址的规划限定 xff0c 使用地址段分配更加灵活 xff0c 日常工作中也经常使用 xff0c 也正是因为其灵活的特点使我们无法一眼辨认出网络号 广播地址 网络中的第一台主机等信息 x
  • EPICS CA请求能否成功的影响因素

    1 子网和广播域 子网掩码和广播域互为互补的网段 例如 xff1a 10 0 2 235的掩码为255 255 0 0 xff0c 则它所在的子网为10 0 0 0 xff0c 广播域为10 0 255 255 xff1b 192 168
  • 服务器采购和选型

    1 CPU 双路CPU xff0c 0号位和1号位 xff0c 只要0号位CPU正常 xff0c 服务器就能工作 xff0c 若1号位CPU故障 xff0c 服务器会报警 若0号位CPU故障 xff0c 1号位CPU正常 xff0c 服务器
  • CentOS 7自定义系统服务(以Phoebus-Olog为例)

    需要开启的服务 xff1a MongoDBElasticSearchPhoebus Olog后端服务Phoebus Olog web client前端服务 配置系统服务的方式 xff1a systemd 把spring boot项目配置为L
  • 在未联网的计算机中部署 yum 源和 EPICS 环境

    1 基本背景 EPICS 软件仓库 xff1a 192 168 206 234 8888 安装方式 xff1a yum 2 配置跳板机 跳板机功能 xff1a 借助ssh 隧道服务进行端口转发 xff0c 使未联网的计算机能够访问软件仓库
  • 在未联网计算机中部署Archiver Appliance(以Rocky Linux 8系统为例)

    由于计算机未联网 xff0c 而利用 epicsarchiverap env 工具进行安装的过程中需要一些联网下载安装包的操作步骤 xff0c 因此以下会给出相应的解决方法 总体思路就是 xff1a 对于一般性网址如 GitHub 等 xf
  • CentOS 7 / Rocky Linux 8 / Windows 10 系统启动 Chrony/NTP 服务

    本文内容 背景介绍1 Chrony NTP 的联系与区别2 关于 Chrony NTP 服务端 客户端的概念3 Chrony 核心组件 CentOS 7 Rocky Linux 8 系统启动 Chrony 服务1 服务状态查询2 服务配置3
  • 前端基础知识——CSS

    CSS CSS 基于 HTML 中的父子元素思想 CSS 有很多类似 Word 的排版功能 xff08 颜色 字体 文字环绕等 xff09 的属性 相关语法说明 xff1a 基本语法 xff1a 选择器 span class token p
  • GitLab的使用

    简介 xff1a Git xff0c GitHub与GitLab有什么区别 xff1f 官方网站 xff1a https docs gitlab com ee topics git 常用命令和使用方式 xff1a 看完这篇还不会用Git x
  • Archiver Appliance 事务处理流程

    当 Archiver Appliance 开始运行后发生了什么 xff1a mgmt服务 xff1a config DefaultConfigService java span class token function initialize