1919
2020import util
2121import xs_errors
22- from srmetadata import open_file , file_read_wrapper , file_write_wrapper
22+ from srmetadata import open_file , file_read_wrapper , file_write_wrapper , align_data_to_file
2323
2424LVM_MAX_NAME_LEN = 127
2525
@@ -34,6 +34,16 @@ class Journaler:
3434 SEPARATOR = "_"
3535 JRN_CLONE = "clone"
3636 JRN_LEAF = "leaf"
37+ JRN_REVERT = "revert"
38+
39+ @classmethod
40+ def has_additional_data (cls , type : str ) -> bool :
41+ """Return True if journal type contains additional data inside of it"""
42+ return type in [
43+ cls .JRN_CLONE ,
44+ cls .JRN_LEAF ,
45+ cls .JRN_REVERT ,
46+ ]
3747
3848 def __init__ (self , lvmCache ):
3949 self .vgName = lvmCache .vgName
@@ -42,54 +52,63 @@ def __init__(self, lvmCache):
4252 def create (self , type , id , val ):
4353 """Create an entry of type "type" for "id" with the value "val".
4454 Error if such an entry already exists."""
45- valExisting = self .get (type , id )
46- writeData = False
47- if valExisting or util .fistpoint .is_active ("LVM_journaler_exists" ):
48- raise xs_errors .XenError ('LVMCreate' , opterr = "Journal already exists for '%s:%s': %s" % (type , id , valExisting ))
49- lvName = self ._getNameLV (type , id , val )
55+ to_write = None
56+ journal_exists = self .get (type , id )
57+ if journal_exists or util .fistpoint .is_active ("LVM_journaler_exists" ):
58+ raise xs_errors .XenError ('LVMCreate' , opterr = f"Journal already exists for '{ type } :{ id } ': { journal_exists } " )
59+ lv_name = self ._getNameLV (type , id , val )
60+
61+ mapper_device = self ._getLVMapperName (lv_name )
62+ if len (mapper_device ) > LVM_MAX_NAME_LEN :
63+ lv_name = self ._getNameLV (type , id )
64+ mapper_device = self ._getLVMapperName (lv_name )
65+ assert len (mapper_device ) <= LVM_MAX_NAME_LEN
5066
51- mapperDevice = self ._getLVMapperName (lvName )
52- if len (mapperDevice ) > LVM_MAX_NAME_LEN :
53- lvName = self ._getNameLV (type , id )
54- writeData = True
55- mapperDevice = self ._getLVMapperName (lvName )
56- assert len (mapperDevice ) <= LVM_MAX_NAME_LEN
67+ try :
68+ to_write = ("%d %s" % (len (val ), val )).encode ()
69+ except UnicodeEncodeError as e :
70+ util .logException ("journaler.create" )
71+ raise xs_errors .XenError ("LVMWrite" , opterr = f"Failed to encode data for journal { lv_name } " ) from e
72+ used_size = len (align_data_to_file (to_write ))
73+ if used_size > self .LV_SIZE :
74+ raise xs_errors .XenError ("LVMWrite" , opterr = f"Size of encoded journal { used_size } exceeds limit of { self .LV_SIZE } " )
75+
76+
77+ self .lvmCache .create (lv_name , self .LV_SIZE , self .LV_TAG )
5778
58- self .lvmCache .create (lvName , self .LV_SIZE , self .LV_TAG )
79+ if not to_write :
80+ return
5981
60- if writeData :
61- fullPath = self .lvmCache ._getPath (lvName )
62- journal_file = open_file (fullPath , True )
82+ full_path = self .lvmCache ._getPath (lv_name )
83+ journal_file = open_file (full_path , True )
84+ try :
85+ raised_exception = None
6386 try :
64- e = None
87+ file_write_wrapper (journal_file , 0 , to_write )
88+ if util .fistpoint .is_active ("LVM_journaler_writefail" ):
89+ raise ValueError ("LVM_journaler_writefail FistPoint active" )
90+ except Exception as e :
91+ raised_exception = e
92+ raise
93+ finally :
6594 try :
66- data = ("%d %s" % (len (val ), val )).encode ()
67- file_write_wrapper (journal_file , 0 , data )
68- if util .fistpoint .is_active ("LVM_journaler_writefail" ):
69- raise ValueError ("LVM_journaler_writefail FistPoint active" )
95+ journal_file .close ()
96+ self .lvmCache .deactivateNoRefcount (lv_name )
7097 except Exception as e :
71- raise
72- finally :
73- try :
74- journal_file .close ()
75- self .lvmCache .deactivateNoRefcount (lvName )
76- except Exception as e2 :
77- msg = 'failed to close/deactivate %s: %s' \
78- % (lvName , e2 )
79- if not e :
80- util .SMlog (msg )
81- raise e2
82- else :
83- util .SMlog ('WARNING: %s (error ignored)' % msg )
84-
85- except :
86- util .logException ("journaler.create" )
87- try :
88- self .lvmCache .remove (lvName )
89- except Exception as e :
90- util .SMlog ('WARNING: failed to clean up failed journal ' \
91- ' creation: %s (error ignored)' % e )
92- raise xs_errors .XenError ('LVMWrite' , opterr = "Failed to write to journal %s" % lvName )
98+ msg = f"failed to close/deactivate { lv_name } : { e } "
99+ if not raised_exception :
100+ util .SMlog (msg )
101+ raise e
102+ else :
103+ util .SMlog (f"WARNING: { msg } (error ignored)" )
104+
105+ except :
106+ util .logException ("journaler.create" )
107+ try :
108+ self .lvmCache .remove (lv_name )
109+ except Exception as e :
110+ util .SMlog (f"WARNING: failed to clean up failed journal creation: { e } (error ignored)" )
111+ raise xs_errors .XenError ('LVMWrite' , opterr = f"Failed to write to journal { lv_name } " )
93112
94113 def remove (self , type , id ):
95114 """Remove the entry of type "type" for "id". Error if the entry doesn't
@@ -139,26 +158,23 @@ def _getAllEntries(self, readFile=True):
139158 if len (parts ) != 3 or util .fistpoint .is_active ("LVM_journaler_badname" ):
140159 raise xs_errors .XenError ('LVMNoVolume' , opterr = "Bad LV name: %s" % lvName )
141160 type , id , val = parts
142- if readFile :
143- # For clone and leaf journals, additional
144- # data is written inside file
145- # TODO: Remove dependency on journal type
146- if type == self .JRN_CLONE or type == self .JRN_LEAF :
147- fullPath = self .lvmCache ._getPath (lvName )
148- self .lvmCache .activateNoRefcount (lvName , False )
149- journal_file = open_file (fullPath )
161+ # TODO: Remove dependency on journal type
162+ if readFile and self .has_additional_data (type ):
163+ fullPath = self .lvmCache ._getPath (lvName )
164+ self .lvmCache .activateNoRefcount (lvName , False )
165+ journal_file = open_file (fullPath )
166+ try :
150167 try :
151- try :
152- data = file_read_wrapper (journal_file , 0 )
153- length , val = data .decode ().split (" " , 1 )
154- val = val [:int (length )]
155- if util .fistpoint .is_active ("LVM_journaler_readfail" ):
156- raise ValueError ("LVM_journaler_readfail FistPoint active" )
157- except :
158- raise xs_errors .XenError ('LVMRead' , opterr = "Failed to read from journal %s" % lvName )
159- finally :
160- journal_file .close ()
161- self .lvmCache .deactivateNoRefcount (lvName )
168+ data = file_read_wrapper (journal_file , 0 , - 1 )
169+ length , val = data .decode ().split (" " , 1 )
170+ val = val [:int (length )]
171+ if util .fistpoint .is_active ("LVM_journaler_readfail" ):
172+ raise ValueError ("LVM_journaler_readfail FistPoint active" )
173+ except :
174+ raise xs_errors .XenError ('LVMRead' , opterr = "Failed to read from journal %s" % lvName )
175+ finally :
176+ journal_file .close ()
177+ self .lvmCache .deactivateNoRefcount (lvName )
162178 if not entries .get (type ):
163179 entries [type ] = dict ()
164180 entries [type ][id ] = val
0 commit comments