shareddata 2.1.4__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {shareddata-2.1.4 → shareddata-2.2.0}/PKG-INFO +1 -1
  2. {shareddata-2.1.4 → shareddata-2.2.0}/setup.cfg +1 -1
  3. shareddata-2.1.4/src/SharedData/SharedDataFrame.py → shareddata-2.2.0/src/SharedData/DataFrame.py +2 -2
  4. {shareddata-2.1.4 → shareddata-2.2.0}/src/SharedData/Defaults.py +1 -1
  5. shareddata-2.1.4/src/SharedData/SharedDataFeeder.py → shareddata-2.2.0/src/SharedData/Feeder.py +5 -15
  6. {shareddata-2.1.4 → shareddata-2.2.0}/src/SharedData/Logger.py +18 -27
  7. {shareddata-2.1.4 → shareddata-2.2.0}/src/SharedData/LoggerConsumerProcess.py +1 -1
  8. {shareddata-2.1.4 → shareddata-2.2.0}/src/SharedData/Metadata.py +1 -1
  9. shareddata-2.1.4/src/SharedData/SharedDataPeriod.py → shareddata-2.2.0/src/SharedData/Period.py +44 -45
  10. shareddata-2.1.4/src/SharedData/SharedDataRealTime.py → shareddata-2.2.0/src/SharedData/RealTime.py +1 -1
  11. shareddata-2.1.4/src/SharedData/SharedDataRealTimeProcess.py → shareddata-2.2.0/src/SharedData/RealTimeProcess.py +1 -1
  12. shareddata-2.2.0/src/SharedData/SharedData.py +197 -0
  13. shareddata-2.1.4/src/SharedData/SharedDataTable.py → shareddata-2.2.0/src/SharedData/Table.py +62 -59
  14. shareddata-2.1.4/src/SharedData/SharedDataTableIndex.py → shareddata-2.2.0/src/SharedData/TableIndex.py +23 -23
  15. shareddata-2.1.4/src/SharedData/SharedDataTimeSeries.py → shareddata-2.2.0/src/SharedData/TimeSeries.py +45 -232
  16. shareddata-2.2.0/src/SharedData/TimeseriesContainer.py +390 -0
  17. {shareddata-2.1.4 → shareddata-2.2.0}/src/shareddata.egg-info/PKG-INFO +1 -1
  18. shareddata-2.2.0/src/shareddata.egg-info/SOURCES.txt +30 -0
  19. shareddata-2.1.4/src/SharedData/SeriesLib.py +0 -122
  20. shareddata-2.1.4/src/SharedData/SharedData.py +0 -172
  21. shareddata-2.1.4/src/shareddata.egg-info/SOURCES.txt +0 -30
  22. {shareddata-2.1.4 → shareddata-2.2.0}/LICENSE +0 -0
  23. {shareddata-2.1.4 → shareddata-2.2.0}/README.md +0 -0
  24. {shareddata-2.1.4 → shareddata-2.2.0}/pyproject.toml +0 -0
  25. /shareddata-2.1.4/src/SharedData/SharedDataAWSKinesis.py → /shareddata-2.2.0/src/SharedData/AWSKinesis.py +0 -0
  26. /shareddata-2.1.4/src/SharedData/SharedDataAWSS3.py → /shareddata-2.2.0/src/SharedData/AWSS3.py +0 -0
  27. {shareddata-2.1.4 → shareddata-2.2.0}/src/SharedData/MultiProc.py +0 -0
  28. {shareddata-2.1.4 → shareddata-2.2.0}/src/SharedData/SharedNumpy.py +0 -0
  29. /shareddata-2.1.4/src/SharedData/SharedDataTableIndexJit.py → /shareddata-2.2.0/src/SharedData/TableIndexJit.py +0 -0
  30. {shareddata-2.1.4 → shareddata-2.2.0}/src/SharedData/Utils.py +0 -0
  31. {shareddata-2.1.4 → shareddata-2.2.0}/src/SharedData/__init__.py +0 -0
  32. {shareddata-2.1.4 → shareddata-2.2.0}/src/shareddata.egg-info/dependency_links.txt +0 -0
  33. {shareddata-2.1.4 → shareddata-2.2.0}/src/shareddata.egg-info/requires.txt +0 -0
  34. {shareddata-2.1.4 → shareddata-2.2.0}/src/shareddata.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: shareddata
3
- Version: 2.1.4
3
+ Version: 2.2.0
4
4
  Summary: Shared Memory Database with S3 repository
5
5
  Home-page: https://github.com/jcarlitooliveira/SharedData
6
6
  Author: Jose Carlito de Oliveira Filho
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = shareddata
3
- version = 2.1.4
3
+ version = 2.2.0
4
4
  author = Jose Carlito de Oliveira Filho
5
5
  author_email = jcarlitooliveira@gmail.com
6
6
  description = Shared Memory Database with S3 repository
@@ -14,8 +14,8 @@ from datetime import datetime, timedelta
14
14
 
15
15
 
16
16
  from SharedData.Logger import Logger
17
- from SharedData.SharedDataAWSS3 import S3Download,S3Upload,UpdateModTime
18
- from SharedData.SharedDataRealTime import SharedDataRealTime
17
+ from SharedData.AWSS3 import S3Download,S3Upload,UpdateModTime
18
+ from SharedData.RealTime import SharedDataRealTime
19
19
 
20
20
 
21
21
  class SharedDataFrame:
@@ -15,7 +15,7 @@ else:
15
15
  raise Exception('PYTHONHASHSEED must be set to 0 in the environment!')
16
16
 
17
17
  if not 'DATABASE_FOLDER' in os.environ:
18
- os.environ['DATABASE_FOLDER'] = os.path.expanduser("~")+'\DB'
18
+ os.environ['DATABASE_FOLDER'] = os.path.expanduser("~")+'/db'
19
19
 
20
20
  if not 'S3_BUCKET' in os.environ:
21
21
  os.environ['S3_BUCKET'] = 's3://deepportfolio'
@@ -1,5 +1,5 @@
1
- from SharedData.SharedDataPeriod import SharedDataPeriod
2
- from SharedData.SharedDataTable import SharedDataTable
1
+ from SharedData.Period import SharedDataPeriod
2
+ from SharedData.Table import SharedDataTable
3
3
 
4
4
  class SharedDataFeeder():
5
5
 
@@ -12,7 +12,7 @@ class SharedDataFeeder():
12
12
 
13
13
  # DATA DICTIONARY
14
14
  # data[period][tag]
15
- self.data = {}
15
+ self.data = {}
16
16
 
17
17
  def __setitem__(self, dataset, value):
18
18
  if not dataset in self.data.keys():
@@ -24,7 +24,7 @@ class SharedDataFeeder():
24
24
  return self.data[dataset]
25
25
 
26
26
  def __getitem__(self, dataset):
27
- if not dataset in self.data.keys():
27
+ if not dataset in self.data.keys():
28
28
  if (dataset in SharedDataFeeder.dense_datasets.keys()):
29
29
  period = dataset
30
30
  self.data[period] = SharedDataPeriod(self, period)
@@ -34,14 +34,4 @@ class SharedDataFeeder():
34
34
  if (dataset in SharedDataFeeder.dense_datasets.keys()):
35
35
  return self.data[dataset]
36
36
  else:
37
- return self.data[dataset].records
38
-
39
- def create_table(self,dataset,names,formats,size,overwrite=False):
40
- self.data[dataset] = SharedDataTable(\
41
- self,dataset,names=names,formats=formats,size=size,\
42
- overwrite=overwrite)
43
- return self.data[dataset].records
44
-
45
- def load_table(self,dataset,size=None):
46
- self.data[dataset] = SharedDataTable(self,dataset,size=size)
47
- return self.data[dataset].records
37
+ return self.data[dataset].records
@@ -8,19 +8,18 @@ import pandas as pd
8
8
  from pythonjsonlogger.jsonlogger import JsonFormatter
9
9
  import boto3
10
10
 
11
- from importlib.metadata import version
12
-
13
- import SharedData.Defaults as Defaults
14
- from SharedData.SharedDataAWSKinesis import KinesisLogStreamHandler
15
11
 
12
+ from SharedData.AWSKinesis import KinesisLogStreamHandler
16
13
 
17
14
  class Logger:
18
15
 
19
16
  log = None
20
- user = None
17
+ user = 'guest'
18
+ source = 'unknown'
21
19
 
22
- def __init__(self, source, user=None):
23
- if Logger.log is None:
20
+ @staticmethod
21
+ def connect(source,user=None):
22
+ if Logger.log is None:
24
23
  if 'SOURCE_FOLDER' in os.environ:
25
24
  try:
26
25
  commompath = os.path.commonpath([source,os.environ['SOURCE_FOLDER']])
@@ -42,13 +41,10 @@ class Logger:
42
41
  source = source.lstrip('src').lstrip('\\src')
43
42
  source = source.lstrip('\\').lstrip('/')
44
43
  source = source.replace('.py','')
45
- self.source = source
44
+ Logger.source = source
46
45
 
47
46
  if not user is None:
48
47
  Logger.user = user
49
- else:
50
- user = 'guest'
51
- Logger.user = 'guest'
52
48
 
53
49
  path = Path(os.environ['DATABASE_FOLDER'])
54
50
  path = path / 'Logs'
@@ -68,8 +64,8 @@ class Logger:
68
64
  loglevel = logging.INFO
69
65
 
70
66
  # Create Logger
71
- self.log = logging.getLogger(source)
72
- self.log.setLevel(logging.DEBUG)
67
+ Logger.log = logging.getLogger(source)
68
+ Logger.log.setLevel(logging.DEBUG)
73
69
  formatter = logging.Formatter(os.environ['USERNAME']+'@'+os.environ['COMPUTERNAME'] +
74
70
  ';%(asctime)s;%(name)s;%(levelname)s;%(message)s',\
75
71
  datefmt='%Y-%m-%dT%H:%M:%S%z')
@@ -77,12 +73,12 @@ class Logger:
77
73
  handler = logging.StreamHandler()
78
74
  handler.setLevel(loglevel)
79
75
  handler.setFormatter(formatter)
80
- self.log.addHandler(handler)
81
- #log file
82
- fhandler = logging.FileHandler(os.environ['LOG_PATH'], mode='a')
83
- fhandler.setLevel(loglevel)
84
- fhandler.setFormatter(formatter)
85
- self.log.addHandler(fhandler)
76
+ Logger.log.addHandler(handler)
77
+ # #log file
78
+ # fhandler = logging.FileHandler(os.environ['LOG_PATH'], mode='a')
79
+ # fhandler.setLevel(loglevel)
80
+ # fhandler.setFormatter(formatter)
81
+ # Logger.log.addHandler(fhandler)
86
82
  #log to aws kinesis
87
83
  kinesishandler = KinesisLogStreamHandler(user=Logger.user)
88
84
  kinesishandler.setLevel(logging.DEBUG)
@@ -90,15 +86,10 @@ class Logger:
90
86
  ';%(asctime)s;%(name)s;%(levelname)s;%(message)s',\
91
87
  datefmt='%Y-%m-%dT%H:%M:%S%z')
92
88
  kinesishandler.setFormatter(jsonformatter)
93
- self.log.addHandler(kinesishandler)
94
- #assign static variable log to be used by modules
95
- Logger.log = self.log
96
- try:
97
- Logger.log.debug('Logger initialized shareddata user %s version %s!' % \
98
- (Logger.user,version('SharedData')))
99
- except:
100
- Logger.log.debug('Logger initialized shareddata!')
89
+ Logger.log.addHandler(kinesishandler)
90
+
101
91
 
92
+ @staticmethod
102
93
  def readLogs(self):
103
94
  logsdir = Path(os.environ['LOG_PATH']).parents[0]
104
95
  lenlogsdir = len(str(logsdir))
@@ -3,7 +3,7 @@ import numpy as np
3
3
 
4
4
  from SharedData.Logger import Logger
5
5
  logger = Logger(__file__,user='worker')
6
- from SharedData.SharedDataAWSKinesis import KinesisLogStreamConsumer
6
+ from SharedData.AWSKinesis import KinesisLogStreamConsumer
7
7
 
8
8
  SLEEP_TIME = 2
9
9
 
@@ -9,7 +9,7 @@ from datetime import datetime, timedelta
9
9
  import gzip,io,shutil,hashlib
10
10
 
11
11
  from SharedData.Logger import Logger
12
- from SharedData.SharedDataAWSS3 import S3Upload, S3ListFolder, S3Download, UpdateModTime
12
+ from SharedData.AWSS3 import S3Upload, S3ListFolder, S3Download, UpdateModTime
13
13
 
14
14
  class Metadata():
15
15
 
@@ -1,4 +1,4 @@
1
- import os,io,hashlib,gzip,shutil
1
+ import os,io,hashlib,gzip,shutil,time
2
2
  import pandas as pd
3
3
  import numpy as np
4
4
  from datetime import datetime, timedelta
@@ -6,11 +6,10 @@ from pathlib import Path
6
6
  from pandas.tseries.offsets import BDay
7
7
  from threading import Thread
8
8
 
9
-
10
9
  from SharedData.Logger import Logger
11
- from SharedData.SharedDataFrame import SharedDataFrame
12
- from SharedData.SharedDataTimeSeries import SharedDataTimeSeries
13
- from SharedData.SharedDataAWSS3 import S3Upload,S3Download,UpdateModTime
10
+ from SharedData.DataFrame import SharedDataFrame
11
+ from SharedData.TimeSeries import SharedDataTimeSeries
12
+ from SharedData.AWSS3 import S3Upload,S3Download,UpdateModTime
14
13
 
15
14
  class SharedDataPeriod:
16
15
 
@@ -41,16 +40,6 @@ class SharedDataPeriod:
41
40
  self.getContinousTimeIndex(self.default_startDate)
42
41
  self.loaded = False
43
42
 
44
-
45
- def load(self):
46
- # read if not loaded
47
- shdatalist = self.sharedData.list()
48
- path, shm_name = self.get_path()
49
- idx = [shm_name in str(s) for s in shdatalist.index]
50
- if not np.any(idx):
51
- self.read()
52
-
53
-
54
43
  def __setitem__(self, tag, df):
55
44
  if not tag in self.tags.keys():
56
45
  if isinstance(tag, pd.Timestamp):
@@ -63,9 +52,9 @@ class SharedDataPeriod:
63
52
  icol = df.columns.intersection(data.columns)
64
53
  data.loc[iidx, icol] = df.loc[iidx, icol].copy()
65
54
 
66
- def __getitem__(self, tag):
55
+ def __getitem__(self, tag):
67
56
  if not self.loaded:
68
- self.load()
57
+ self.load()
69
58
  self.loaded=True
70
59
  if not tag in self.tags.keys():
71
60
  if isinstance(tag, pd.Timestamp):
@@ -125,30 +114,6 @@ class SharedDataPeriod:
125
114
  self.ctimeidx[startDate][periods.values] = np.arange(len(periods))
126
115
  return self.ctimeidx[startDate]
127
116
 
128
- def get(self, tag):
129
- if isinstance(tag, pd.Timestamp):
130
- df = SharedDataFrame(self, tag, malloc=False)
131
- return df.data
132
- else:
133
- return pd.DataFrame([])
134
-
135
- def exists(self, tag):
136
- if isinstance(tag, pd.Timestamp):
137
- path = Path(os.environ['DATABASE_FOLDER'])
138
- path = path / self.sharedData.user
139
- path = path / self.sharedData.database
140
- path = path / self.sharedDataFeeder.feeder
141
- path = path / self.period
142
- fpath = path / (tag.strftime('%Y%m%d%H%M')+'.npy')
143
- return fpath.is_file()
144
- else:
145
- return False
146
-
147
- def create_timeseries(self,tag,startDate,columns,overwrite=False):
148
- self.tags[tag] = SharedDataTimeSeries(\
149
- self,tag,startDate=startDate,columns=columns,overwrite=overwrite)
150
- return self.tags[tag].data
151
-
152
117
  def get_path(self):
153
118
  shm_name = self.sharedData.user + '/' + self.sharedData.database + '/' \
154
119
  + self.sharedDataFeeder.feeder + '/' + self.period
@@ -166,7 +131,31 @@ class SharedDataPeriod:
166
131
  os.makedirs(path.parent)
167
132
  return path , shm_name
168
133
 
134
+ #CREATE
135
+ def create_timeseries(self,tag,startDate,columns,overwrite=False):
136
+ self.tags[tag] = SharedDataTimeSeries(\
137
+ self,tag,startDate=startDate,columns=columns,overwrite=overwrite)
138
+ return self.tags[tag].data
139
+
140
+ # READ
141
+ def load(self):
142
+ # read if not loaded
143
+ shdatalist = self.sharedData.list()
144
+ path, shm_name = self.get_path()
145
+ idx = [shm_name in str(s) for s in shdatalist.index]
146
+ if not np.any(idx):
147
+ self.read()
148
+ else:
149
+ #map
150
+ self.map(shm_name,shdatalist.index[idx])
151
+
152
+ def map(self,shm_name,shm_name_list):
153
+ for shm in shm_name_list:
154
+ tag = shm.replace(shm_name,'')[1:]
155
+ self.tags[tag] = SharedDataTimeSeries(self, tag = tag)
156
+
169
157
  def read(self):
158
+ tini = time.time()
170
159
  datasize = 1
171
160
  path, shm_name= self.get_path()
172
161
  headpath = str(path)+'_head.bin'
@@ -209,20 +198,27 @@ class SharedDataPeriod:
209
198
  tail_io = open(str(tailpath),'rb')
210
199
 
211
200
  if not head_io is None:
212
- self.read_io(head_io,headpath)
201
+ datasize += self.read_io(head_io,headpath)
213
202
 
214
203
  if not tail_io is None:
215
- self.read_io(tail_io,tailpath)
204
+ datasize += self.read_io(tail_io,tailpath)
205
+
206
+ te = time.time()-tini+0.000001
207
+ datasize = datasize/(1024*1024)
208
+ Logger.log.debug('read %s/%s %.2fMB in %.2fs %.2fMBps ' % \
209
+ (self.sharedDataFeeder,self.period,datasize,te,datasize/te))
216
210
 
217
211
  def read_io(self,io_obj,path):
212
+ datasize = 0
218
213
  #read
219
214
  io_obj.seek(0)
220
215
  io_data = io_obj.read()
216
+ datasize = len(io_data)
221
217
  _m = hashlib.md5(io_data[:-24]).digest()
222
218
  m = io_data[-16:]
223
219
  if (m!=_m):
224
- Logger.log.error('Timeseries read_head() file %s corrupted!' % (path))
225
- raise Exception('Timeseries read_head() %s corrupted!' % (path))
220
+ Logger.log.error('Timeseries file %s corrupted!' % (path))
221
+ raise Exception('Timeseries file %s corrupted!' % (path))
226
222
  io_obj.seek(0)
227
223
  separator = np.frombuffer(io_obj.read(8),dtype=np.int64)[0]
228
224
  while (separator==1):
@@ -249,6 +245,9 @@ class SharedDataPeriod:
249
245
  separator = np.frombuffer(io_obj.read(8),dtype=np.int64)[0]
250
246
  io_obj.close()
251
247
 
248
+ return datasize
249
+
250
+ # WRITE
252
251
  def write(self,startDate=None):
253
252
  path , shm_name= self.get_path()
254
253
  mtime = datetime.now().timestamp()
@@ -4,7 +4,7 @@ import pandas as pd
4
4
  import numpy as np
5
5
 
6
6
  from SharedData.Logger import Logger
7
- from SharedData.SharedDataAWSKinesis import KinesisStreamProducer
7
+ from SharedData.AWSKinesis import KinesisStreamProducer
8
8
 
9
9
  class SharedDataRealTime:
10
10
 
@@ -6,7 +6,7 @@ from pathlib import Path
6
6
  from SharedData.Logger import Logger
7
7
  logger = Logger(__file__)
8
8
  from SharedData.SharedData import SharedData
9
- from SharedData.SharedDataAWSKinesis import KinesisStreamConsumer
9
+ from SharedData.AWSKinesis import KinesisStreamConsumer
10
10
 
11
11
 
12
12
  try:
@@ -0,0 +1,197 @@
1
+ import os, psutil
2
+ import pandas as pd
3
+ from multiprocessing import shared_memory
4
+ from pathlib import Path
5
+ from importlib.metadata import version
6
+
7
+ import SharedData.Defaults as Defaults
8
+ from SharedData.Logger import Logger
9
+ from SharedData.Table import Table
10
+ from SharedData.TimeseriesContainer import TimeseriesContainer
11
+ from SharedData.TimeSeries import TimeSeries
12
+ from SharedData.DataFrame import SharedDataFrame
13
+ from SharedData.RealTime import SharedDataRealTime
14
+ from SharedData.Utils import remove_shm_from_resource_tracker
15
+
16
+ class SharedData:
17
+
18
+ def __init__(self,source,user='guest'):
19
+ self.source = source
20
+ self.user = user
21
+
22
+ # DATA DICTIONARY
23
+ self.data = {}
24
+
25
+ # LOGIN VARIABLES
26
+ self.islogged = False
27
+ self.source=source
28
+ self.user=user
29
+ self.mode='rw'
30
+
31
+ # S3 VARIABLES
32
+ self.s3read = True
33
+ self.s3write = True
34
+
35
+ # save files locally
36
+ self.save_local = (os.environ['SAVE_LOCAL'] == 'True')
37
+
38
+ self.databases = {
39
+ 'MarketData' : ['date','symbol'],
40
+ 'Relationships' : ['date','symbol1','symbol2'],
41
+ 'Portfolios' : ['date','portfolio'],
42
+ 'Signals' : ['date','portfolio','symbol'],
43
+ 'Risk' : ['date','portfolio','symbol'],
44
+ 'Positions' : ['date','portfolio','symbol'],
45
+ 'Orders' : ['date','portfolio','symbol','clordid'],
46
+ 'Trades' : ['date','portfolio','symbol','tradeid']
47
+ }
48
+
49
+ Logger.connect(self.source,self.user)
50
+
51
+ if (os.name == 'posix'):
52
+ remove_shm_from_resource_tracker()
53
+
54
+ if not self.islogged:
55
+ self.islogged = True
56
+ try:
57
+ Logger.log.debug('%s@%s CONNECTED!\nSharedData version %s, user %s' %
58
+ (os.environ['USERNAME'], os.environ['COMPUTERNAME'],version('SharedData'), self.user))
59
+ except:
60
+ Logger.log.debug('%s:%s CONNECTED!\nSharedData user %s!' %
61
+ (os.environ['USERNAME'], os.environ['COMPUTERNAME'],self.user))
62
+
63
+ ###############################################
64
+ ############# DATA CONTAINERS #################
65
+ ###############################################
66
+
67
+ ############# TABLE #################
68
+ def table(self,database,period,source,tablename,\
69
+ names=None,formats=None,size=None,value=None,user='master'):
70
+
71
+ path = user+'/'+database+'/'+period+'/'+source+'/table/'+tablename
72
+ if not path in self.data.keys():
73
+ self.data[path] = Table(self,database,period,source,\
74
+ tablename,records=value,names=names,formats=formats,size=size,user=user)
75
+ return self.data[path].records
76
+
77
+ ############# TIMESERIES #################
78
+ def timeseries(self,database,period,source,tag=None,\
79
+ startDate=None,columns=None,value=None,user='master'):
80
+
81
+ path = user+'/'+database+'/'+period+'/'+source+'/timeseries'
82
+ if not path in self.data.keys():
83
+ self.data[path] = TimeseriesContainer(self, database, period, source,user=user)
84
+ if tag is None:
85
+ return self.data[path]
86
+
87
+ if not tag in self.data[path].tags.keys():
88
+ if (startDate is None) & (columns is None) & (value is None):
89
+ self.data[path].load()
90
+ if not tag in self.data[path].tags.keys():
91
+ Logger.log.error('Tag %s/%s doesnt exist' % (path,tag))
92
+ return None
93
+ else:
94
+ self.data[path].tags[tag] = TimeSeries(self, self.data[path],\
95
+ database, period, source, tag,\
96
+ value=value,startDate=startDate,columns=columns,user=user)
97
+
98
+ return self.data[path].tags[tag].data
99
+
100
+ ############# DATAFRAME #################
101
+ def dataframe(self,database,period,source,\
102
+ date=None,value=None,user='master'):
103
+ pass
104
+
105
+ ###############################################
106
+ ######### SHARED MEMORY MANAGEMENT ############
107
+ ###############################################
108
+ @staticmethod
109
+ def malloc(shm_name,create=False,size=None,overwrite=False):
110
+ ismalloc = False
111
+ shm = None
112
+ try:
113
+ shm = shared_memory.SharedMemory(\
114
+ name = shm_name,create=False)
115
+ ismalloc = True
116
+ except:
117
+ pass
118
+
119
+ if (not ismalloc) & (create) & (not size is None):
120
+ shm = shared_memory.SharedMemory(\
121
+ name=shm_name,create=True,size=size)
122
+ ismalloc = True
123
+
124
+ elif (create) & (size is None):
125
+ raise Exception('SharedData malloc must have a size when create=True')
126
+
127
+ elif (os.name=='posix')\
128
+ & (ismalloc) & (create) & (overwrite) & (not size is None):
129
+ SharedData.free(shm_name)
130
+ shm = shared_memory.SharedMemory(\
131
+ name=shm_name,create=True,size=size)
132
+ ismalloc = True
133
+
134
+ # register process id access to memory
135
+ if ismalloc:
136
+ fpath = Path(os.environ['DATABASE_FOLDER'])
137
+ fpath = fpath/('shm/'+shm_name.replace('\\','/')+'.csv')
138
+ os.makedirs(fpath.parent,exist_ok=True)
139
+ pid = os.getpid()
140
+ f = open(fpath, "a+")
141
+ f.write(str(pid)+',')
142
+ f.flush()
143
+ f.close()
144
+
145
+ return [shm, ismalloc]
146
+
147
+ @staticmethod
148
+ def free(shm_name):
149
+ if os.name=='posix':
150
+ try:
151
+ shm = shared_memory.SharedMemory(\
152
+ name = shm_name,create=False)
153
+ shm.close()
154
+ shm.unlink()
155
+ fpath = Path(os.environ['DATABASE_FOLDER'])
156
+ fpath = fpath/('shm/'+shm_name.replace('\\','/')+'.csv')
157
+ if fpath.is_file():
158
+ os.remove(fpath)
159
+ except:
160
+ pass
161
+
162
+ @staticmethod
163
+ def list():
164
+ folder = Path(os.environ['DATABASE_FOLDER'])/'shm'
165
+ shm_names = pd.DataFrame()
166
+ for root, _, filenames in os.walk(folder):
167
+ for filename in filenames:
168
+ if filename.endswith('.csv'):
169
+ fpath = os.path.join(root, filename)
170
+ shm_name = fpath.removeprefix(str(folder))[1:]
171
+ shm_name = shm_name.removesuffix('.csv')
172
+ shm_name = shm_name.replace('/','\\')
173
+ try:
174
+ shm = shared_memory.SharedMemory(\
175
+ name = shm_name,create=False)
176
+ shm_names.loc[shm_name,'size'] = shm.size
177
+ shm.close()
178
+ except:
179
+ try:
180
+ if fpath.is_file():
181
+ os.remove(fpath)
182
+ except:
183
+ pass
184
+ shm_names = shm_names.sort_index()
185
+ return shm_names
186
+
187
+ @staticmethod
188
+ def freeall():
189
+ shm_names = SharedData.list()
190
+ for shm_name in shm_names.index:
191
+ SharedData.free(shm_name)
192
+
193
+ ###############################################
194
+ ############# REAL TIME MANAGEMENT ############
195
+ ###############################################
196
+ def subscribe(database,source,period):
197
+ SharedDataRealTime.subscribe(database,source,period)